教程地址: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'u8ba2u5355u53f7'是订单号的编码 pattern = re.compile(u'createTime":"(.*?)","id":"(.*?)".*?"shopName":"(.*?)".*?snapUrl.*?"title":"(.*?)".*?priceInfo":{"original":"(.*?)".*?"realTotal":"(.*?)".*?"quantity":"(.*?)"', re.S) #pattern = re.compile(u'dealtime.*?>(.*?)</span>.*?u8ba2u5355u53f7.*?<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':"0", 'newlogin':"0", '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':"000001", 'CtrlVersion':"1,0,0,7", 'loginType':"3", 'minititle':"", 'minipara':"", 'umto':"NaN", 'pstrong':"", 'sign':"", 'need_sign':"", 'isIgnore':"", 'full_redirect':"", 'popid':"", 'callback':"", 'guf':"", 'not_duplite_str':"", 'need_user_id':"", 'poy':"", 'gvfdcname':"10", 'gvfdcre':"xxxxxxxxxxxxxxxxxxx", 'from_encoding':"", 'sub':"", 'TPL_password_2':self.password2, 'loginASR':"1", 'loginASRSuc':"1", '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"获取请求成功") #u8bf7u8f93u5165u9a8cu8bc1u7801这六个字是请输入验证码的utf-8编码 pattern = re.compile(u'u8bf7u8f93u5165u9a8cu8bc1u7801', 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解码呢 如何判断解码格式? #检测验证码错误的正则表达式,u9a8cu8bc1u7801u9519u8bef 是验证码错误五个字的编码 pattern = re.compile(u'u9a8cu8bc1u7801u9519u8bef',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()