教程地址:http://cuiqingcai.com/1076.html
这一篇掌握的不好。虽然代码可以跑,但是里面的很多东西都一知半解。需要有空的时候系统整理。
原代码中的正则表达式已经失效了,我自己又重新写的。
知识点:
1.cookie的使用
2.验证码的处理,填写后的提交方式
3.浏览器打开页面
4.提交的表单信息可以通过火狐浏览器中 F12-网络-POST方法-参数-表单数据 来获得。
疑问:
1.无法获取翻页信息,只能重复的输出第一页信息。且第一页信息不全。
2.一次性下了多个订单时,只显示第一个。
3.为何用gbk解码?
4.为何正则表达式中用 \u****的编码形式,而不是直接写汉字?
5.为何谷歌浏览器和火狐浏览器用F12看到的内容不一样?谷歌浏览器的要长很多,结构非常复杂,且没有明晰的关键字,都是0.2.3.1这样的东西;火狐浏览器的关键字就比较明了,但结构不好,内容都写在同一行里。
6.用到的很多中转的url不知道是怎么来的?我用这些url可以得到正确的内容,但是我自己的浏览器上的url跟代码中的不同。这是为什么??
7.ua, st, token是什么?为什么要这些?如何知道登陆时需要哪些信息?
8.stURL怎么来的?教程中说直接用
https://login.taobao.com/member/vst.htm?st=1uynJELa4hKfsfWU3OjPJCw&TPL_username=cqcre
的形式可以直接打开登陆后的页面,可是我获取了st,并输入我自己的用户名,结果在浏览器中登陆失败。可是代码中确实可以成功。为什么?
9. 为什么通过 pattern = re.compile('top.location = "(.*?)"', re.S) 就可以判断是否登陆成功?我在浏览器中,分别尝试登陆和未登录情况,都不能获得top.location这个关键字。
10.已买到的宝贝的url,代码中的和实际浏览器中显示的不同。且代码中无法获取翻页后的信息。
代码中的是:'http://buyer.trade.taobao.com/trade/itemlist/listBoughtItems.htm?action=itemlist/QueryAction&event_submit_do_query=1' + '&pageNum=' + str(pageIndex)
浏览器中的是:https://buyertrade.taobao.com/trade/itemlist/list_bought_items.htm?spm=xxxx.xxxxxxxxx.xxxxxxx.x.xxxxxxx
spm的用途:导购效果跟踪http://open.taobao.com/doc2/detail.htm?articleId=959&docType=1&treeId=null
整体代码如下:(一些个人信息我删掉了)
import urllib.request
import urllib.parse
import re
import http.cookiejar
import webbrowser #处理获得的宝贝页面
class Tool:
#初始化
def __init__(self):
pass #获得页码数
def getPageNum(self,page):
pattern = re.compile('"totalPage":(.*?)}',re.S)
result = re.search(pattern,page)
if result:
print("找到了共多少页")
pageNum = result.group(1).strip()
print('共',pageNum,'页')
return pageNum
def getGoodsInfo(self,page):
#u'\u8ba2\u5355\u53f7'是订单号的编码
pattern = re.compile(u'createTime":"(.*?)","id":"(.*?)".*?"shopName":"(.*?)".*?snapUrl.*?"title":"(.*?)".*?priceInfo":{"original":"(.*?)".*?"realTotal":"(.*?)".*?"quantity":"(.*?)"', re.S)
#pattern = re.compile(u'dealtime.*?>(.*?)</span>.*?\u8ba2\u5355\u53f7.*?<em>(.*?)</em>.*?shopname.*?title="(.*?)".*?baobei-name">.*?<a.*?>(.*?)</a>.*?'
# u'price.*?title="(.*?)".*?quantity.*?title="(.*?)".*?amount.*?em.*?>(.*?)</em>.*?trade-status.*?<a.*?>(.*?)</a>',re.S)
result = re.findall(pattern,page)
for item in result:
print('------------------------------------------------------------')
print("购买日期:",item[0].strip(), '订单号:',item[1].strip(),'卖家店铺:',item[2].strip())
print('宝贝名称:',item[3].strip())
print('原价:',item[4].strip(),'购买数量:',item[6].strip(),'实际支付:',item[5].strip()) #模拟登陆淘宝类
class Taobao:
#初始化方法
def __init__(self):
#登陆的URL
self.loginURL = "https://login.taobao.com/member/login.jhtml"
#代理IP地址,防止自己的IP被封禁
self.proxyURL = 'http://120.193.146.97:843'
#登陆POST数据时发送的头部信息
self.loginHeaders = {
'Host':'login.taobao.com',
'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0',
'Referer':'https://login.taobao.com/member/login.jhtml',
'Content-Type':'application/x-www-form-urlencoded',
'Connection':'keep-alive'
}
#用户名
self.username = '自己的用户名'
#ua字符串,经过淘宝ua算法计算得出,包含了时间戳,浏览器,屏幕分辨率,随机数,鼠标移动,鼠标点击,其实还有键盘输入记录,鼠标移动的记录、点击的记录等等的信息
self.ua = '自己获取'
#密码
self.password2 = '自己获取'
#post的数据就是F12后网络-POST方法-参数-表单数据 里的全部内容
self.post = post = {
'ua':self.ua,
'TPL_username':self.username,
'TPL_password':"",
'TPL_checkcode':"",
'loginsite':"",
'newlogin':"",
'TPL_redirect_url':"https://www.taobao.com/?spm=axxxxxxxxxxxxxx",
'from':"tbTop",
'fc':"default",
'style':"default",
'css_style':"",
'keyLogin':"false",
'qrLogin':"true",
'newMini':"false",
'tid':"",
'support':"",
'CtrlVersion':"1,0,0,7",
'loginType':"",
'minititle':"",
'minipara':"",
'umto':"NaN",
'pstrong':"",
'sign':"",
'need_sign':"",
'isIgnore':"",
'full_redirect':"",
'popid':"",
'callback':"",
'guf':"",
'not_duplite_str':"",
'need_user_id':"",
'poy':"",
'gvfdcname':"",
'gvfdcre':"xxxxxxxxxxxxxxxxxxx",
'from_encoding':"",
'sub':"",
'TPL_password_2':self.password2,
'loginASR':"",
'loginASRSuc':"",
'allp':"",
'oslanguage':"zh-CN",
'sr':"1366*768",
'osVer':"windows|6.3",
'naviVer':"firefox|41"
}
#将POST的数据进行编码转换
self.postData = urllib.parse.urlencode(self.post).encode(encoding='UTF8')
#设置代理
self.proxy = urllib.request.ProxyHandler({'http':self.proxyURL})
#设置cookie
self.cookie = http.cookiejar.CookieJar()
#设置cookie处理器
self.cookieHandler = urllib.request.HTTPCookieProcessor(self.cookie)
#设置登陆用到的opener
self.opener = urllib.request.build_opener(self.cookieHandler,self.proxy,urllib.request.HTTPHandler)
#赋值J_HToken
self.J_HToken = ''
#登陆成功时,需要的Cookie
self.newCookie = http.cookiejar.CookieJar()
#登陆成功时,需要一个新的opener
self.newOpener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(self.newCookie))
#引入工具类
self.tool = Tool() #得到是否需要输入验证码,有时需要,有时不需要
def needIdenCode(self):
#第一次登陆获取验证码尝试,构建request
request = urllib.request.Request(self.loginURL,self.postData,self.loginHeaders)
#得到第一次登陆尝试的响应
response = self.opener.open(request)
#获取其中的内容
content = response.read().decode('gbk')
#获取状态码
status = response.getcode()
#状态码为200,获取成功
if status == 200:
print(u"获取请求成功")
#\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801这六个字是请输入验证码的utf-8编码
pattern = re.compile(u'\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801', re.S)
result = re.search(pattern, content)
if result:
print(u"您需要输入验证码")
return content
else:
print(u"不需要输入验证码")
#返回结果直接带有J_HToken,表明直接验证通过
tokenPattern = re.compile('id="J_HToken" value="(.*?)"')
tokenMatch = re.search(tokenPattern,content)
if tokenMatch:
self.J_HToken = tokenMatch.group(1)
print(u"此次安全验证通过,您这次不需要输入验证码")
return False
else:
print(u"获取请求失败")
return None #得到验证码图片
def getIdenCode(self, page):
#得到验证码的图片
pattern = re.compile('img id="J_StandardCode_m.*?data-src="(.*?)"',re.S)
#匹配的结果
matchResult = re.search(pattern, page)
#已经匹配得到内容,并且验证码图片链接不为空
if matchResult and matchResult.group(1):
print(matchResult.group(1))
return matchResult.group(1)
else:
print(u"没找到验证码内容")
return False #输入验证码,重新请求,如果验证成功,则返回J_HToken
def loginWithCheckCode(self):
#提示用户输入验证码
checkcode = input('请输入验证码:')
self.post['TPL_checkcode'] = checkcode
#对post数据重新进行编码
self.postData = urllib.parse.urlencode(self.post).encode(encoding='UTF8')
try:
#再次构建请求,加入验证码之后的第二次登陆尝试
request = urllib.request.Request(self.loginURL,self.postData,self.loginHeaders)
#得到第一次登陆尝试的响应
response = self.opener.open(request)
#获取其中的内容
content = response.read().decode('gbk') #为什么这里是用gbk解码呢 如何判断解码格式?
#检测验证码错误的正则表达式,\u9a8c\u8bc1\u7801\u9519\u8bef 是验证码错误五个字的编码
pattern = re.compile(u'\u9a8c\u8bc1\u7801\u9519\u8bef',re.S)
result = re.search(pattern,content)
#如果返回页面包括了,验证码错误五个字
if result:
print(u"验证码输入错误")
return False
else:
#返回结果直接带有J_HToken字样,说明验证码输入成功,成功跳转到了获取HToken的界面
tokenPattern = re.compile('id="J_HToken" value="(.*?)"')
tokenMatch = re.search(tokenPattern,content)
#如果匹配成功,找到了J_HToken
if tokenMatch:
print(u"验证码输入正确")
print(tokenMatch.group(1))
self.J_HToken = tokenMatch.group(1)
return tokenMatch.group(1)
else:
print(u"J_HToken获取失败")
return False
except urllib.error.HTTPError as e:
print(u"连接服务器出错,错误原因",e.reason)
return False #通过token获得st
def getSTbyToken(self, token):
#下面的URL怎么来的??
tokenURL = 'https://passport.alipay.com/mini_apply_st.js?site=0&token=%s&callback=stCallback6' % token
request = urllib.request.Request(tokenURL)
response = urllib.request.urlopen(request)
#处理st,获得用户淘宝主页的登陆地址
pattern = re.compile('{"st":"(.*?)"}',re.S)
result = re.search(pattern,response.read().decode('gbk')) #这里原本没有decode,但我觉得要加
if result:
print(u"获取st码成功")
st = result.group(1)
print(st)
return st
else:
print(u"未找到st")
return False #利用st码进行登陆,获取重定向网址
def loginByST(self, st, username):
stURL = 'https://login.taobao.com/member/vst.htm?st=%s&TPL_username=%s' % (st,username)
headers = {
'Host':'login.taobao.com',
'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0',
'Connection':'keep-alive'
}
request = urllib.request.Request(stURL, headers = headers)
response = self.newOpener.open(request)
content = response.read().decode('gbk')
#检测结果,看是否登陆成功
pattern = re.compile('top.location = "(.*?)"', re.S) #这里不懂??
match = re.search(pattern, content)
if match:
print(u"登陆网址成功")
location = match.group(1)
return True
else:
print(u"登陆失败")
return False #获得已买到的宝贝页面
def getGoodsPage(self,pageIndex):
goodsURL = 'http://buyer.trade.taobao.com/trade/itemlist/listBoughtItems.htm?action=itemlist/QueryAction&event_submit_do_query=1' + '&pageNum=' + str(pageIndex)
response = self.newOpener.open(goodsURL)
page = response.read().decode('gbk')
return page #获取所有已买到的宝贝信息
def getAllGoods(self,pageNum):
print(u"获取到的商品列表如下")
for x in range(1,int(pageNum)+1):
page = self.getGoodsPage(x)
self.tool.getGoodsInfo(page) #程序运行主干
def main(self):
#是否需要验证码,是则得到页面内容,不是则返回False
needResult = self.needIdenCode()
if not needResult == None:
if not needResult == False:
print(u"您需要手动输入验证码")
idenCode = self.getIdenCode(needResult)
if not idenCode == False:
print(u"获取验证码成功")
print(u"请在浏览器中输入您看到的验证码")
webbrowser.open_new_tab(idenCode)
self.loginWithCheckCode()
else:
print(u"验证码获取失败,请重试")
else:
print("不需要输入验证码")
else:
print(u"请求登陆页面失败,无法确认是否需要验证码") #判断token是否正常获取到
if not self.J_HToken:
print(u"获取Token失败,请重试")
return
#获取st码
st = self.getSTbyToken(self.J_HToken)
#利用st进行登陆
result = self.loginByST(st, self.username)
if result:
#获得所有宝贝的页面
page = self.getGoodsPage(1)
pageNum = self.tool.getPageNum(page)
self.getAllGoods(pageNum)
else:
print(u"登陆失败") taobao = Taobao()
taobao.main()