【python】抄写爬淘宝已买到的宝贝的代码

教程地址: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()
    
原文地址:https://www.cnblogs.com/dplearning/p/4859466.html