• scrapy模拟登录微博


    http://blog.csdn.net/pipisorry/article/details/47008981

    这篇文章是介绍使用scrapy模拟登录微博,并爬取微博相关内容。

    关于登录流程为嘛如此设置,请參考[微博登录过程分析]。

    截包分析

    下载软件Fiddler for .NET2查看相关登录流程信息。执行python程序訪问和直接在浏览器中刷新页面都能够在fiddler中找到网络包的相关信息。


    Note: fiddler是抓包用的,是独立的工具。类似这样的前端登录动作。也能够用casperjs。还能够用浏览器嵌入工具HttpWatch截包工具如Firefox的插件httpfox。

    获取登录入口

    微博的登录入口有好几个,事实上仅仅要登录的逻辑不变, 其他的入口也是能够的。在微博登录界面分析html源代码。获得其登录界面为http://weibo.com/login.php


    查看须要的postdata

    登录微博前,我们要先post相关数据。打开fiddler2,再登录微博,并查看fiddler2的内容变化


    图中webForms全部数据就是我们在模拟登录时须要填入的数据.这些数据中除了su、sp、rsakv、servertime、nonce是经过js处理动态生成的,其他都是个固定值(事实上须要的也就仅仅有pubkey、url、pwencode和nonce、pubkey、retcode、exectime、pcid,其他的不用加入postdata,甚至和后面的有些能够不用加入(lz未验证)),能够在代码中写死。所以你的postdata仅仅要提交su、sp、servertime、nonce、url、pwencode和pubkey、retcode、exectime、pcid

    Note: su是js处理后的username;sp是js处理后的password。servertime、nonce 、pubkey都是登录时候须要使用的,用于post信息(sp)的加密;pwnencode=rsa2是weibo登录对password的加密方式。

    获得postdata

    当然上面的信息能够用抓包工具抓到,可是我们要在程序中获得这些post信息。

    1. 在浏览器登录后。fiddler2会抓到还有一个login.sina.com.cn下的js文件http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18),这个js文件就是当用户输入username时,网页发送username到js文件里。js文件处理username并返回su、servertime、nonce、url、pwencode和rsakv、retcode、exectime、pcid这些post数据,用于后面的password加密并提交到兴许站点,在以下的textview中能够看到

    Note:1. 上面的js地址是在未登录的情况下抓包得到。而且后面的&_=1441377653804%20HTTP/1.1已经被lz省略了。后面的数字实际上是str(time.time()).replace('.', '')这个东西。对于获取postdata没用。

    2. 上面url的su=部分, 这里的su是经过js处理后的username,在后面增加js处理后的username,js处理后的username当然是登录后得到的


    2. 事实上手动在浏览器中输入上面的js地址,也会得到对应的post数据输出


    能够看到

    假设su-为空,得到:
    sinaSSOController.preloginCallBack({"retcode":0,"servertime":1441379724,"pcid":"gz-ca74a2cf2705a177abe404a62a1140d71d09","nonce":"89VNFB","pubkey":"EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443","rsakv":"1330428213","uid":"2835992634","exectime":4})
    填入js处理后的username得到:
    sinaSSOController.preloginCallBack({"retcode":0,"servertime":1441380255,"pcid":"gz-3ab638aed06967c056296dca13e50a4a6333","nonce":"TCEW1Y","pubkey":"EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443","rsakv":"1330428213","exectime":3})

    Note: 登录后的结果,不过少了一个uid,同一时候全部人的pubkey是一样的。由于是公钥嘛。

    皮皮Blog


    模拟js处理username及password

    浏览器中输入http://login.sina.com.cn/js/sso/ssologin.js得到这个js文件。复制内容到js编辑器中(lz是在pycharm中创建js文件格式化后查阅的)查看。

    Note: 在未登录状态。浏览器中刷新登录界面http://login.sina.com.cn/signup/signin.php?

    entry=sso这个页面,fiddler2就能够抓到那个ssologin.js文件

    查看ssologin.js的makeRequest函数:

        var makeRequest = function (username, password, savestate) {
            var request = {
                entry: me.getEntry(),
                gateway: 1,
                from: me.from,
                savestate: savestate,
                useticket: me.useTicket ?

    1 : 0
            };
            if (me.failRedirect) {
                me.loginExtraQuery.frd = 1
            }
            request = objMerge(request, {pagerefer: document.referrer || ""});
            request = objMerge(request, me.loginExtraFlag);
            request = objMerge(request, me.loginExtraQuery);
            request.su = sinaSSOEncoder.base64.encode(urlencode(username));
            if (me.service) {
                request.service = me.service
            }
            if ((me.loginType & rsa) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.RSAKey) {
                request.servertime = me.servertime;
                request.nonce = me.nonce;
                request.pwencode = "rsa2";
                request.rsakv = me.rsakv;
                var RSAKey = new sinaSSOEncoder.RSAKey();
                RSAKey.setPublic(me.rsaPubkey, "10001");
                password = RSAKey.encrypt([me.servertime, me.nonce].join(" ") + " " + password)
            } else {
                if ((me.loginType & wsse) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.hex_sha1) {
                    request.servertime = me.servertime;
                    request.nonce = me.nonce;
                    request.pwencode = "wsse";
                    password = sinaSSOEncoder.hex_sha1("" + sinaSSOEncoder.hex_sha1(sinaSSOEncoder.hex_sha1(password)) + me.servertime + me.nonce)
                }
            }
            request.sp = password;
            try {
                request.sr = window.screen.width + "*" + window.screen.height
            } catch (e) {
            }
            return request
        };

    username加密

    从代码中我们能够知道su就是经过html字符转义再转成base64编码

    python中我们能够这样转化:

    def get_su(self, user_name):
        '''
        对用户名加密
        '''
        username_ = urllib.quote(user_name)  # html字符转义
        return base64.encodestring(username_)[:-1]
    password加密

    weibo登录对password有两种加密方式:rsa2与wsse,我们从上面的password加密方式pwnencode=rsa2可知, js处理走的是这一部分逻辑。(wsse逻辑是通过一个if else推断得到。但我们登录通常是rsa2,wsse是干嘛的没深究)

    而且servertime, nonce, pubkey都被用上了,我们仅仅要把这部分js在python中转义即可了。

    def get_sp_rsa(self, password, pubkey, servertime, nonce):
        '''
        对密码加密,http://login.sina.com.cn/js/sso/ssologin.js中makeRequest的python实现
        '''
        # 公钥pubkey在prelogin得到,固定值
        key = rsa.PublicKey(int(pubkey, 16), 65537)  # 10001相应的10进制,创建公钥
        message = ('	').join([str(servertime), str(nonce)]) + '
    ' + password
        encropy_pwd = rsa.encrypt(message, key)
        return binascii.b2a_hex(encropy_pwd)  # 将加密信息转换为16进制
    Note:

    1. 0x10001要转化成10进制的65537, 还有要经过servertime + +' ' + nonce + ' ' + passwd拼接字符串再进行Rsa加密, 最后转成16进制即得到sp.

    2. 使用rsa加密要安装rsa拓展包 pip install rsa

    皮皮Blog



    模拟登录微博

    以上我们分析了怎样获取post值,知道哪些数据是须要提交的。也知道怎么处理username和password来获取su、sp。以下解说怎样利用这些信息模拟登录新浪微博。

    1. 请求http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18)。这个相当于登录前请求相关postdata的地址,在返回的response中获取servertime,nonce,pubkey等值

    def get_prelogin_data(self):
        '''
        登录前,获得之后要提交的数据
        :return:
        '''
        prelogin_url = globleOptions.prelogin_url
        post_ori_text = requests.get(prelogin_url).text
        json_data = re.search(r'((.*?))', post_ori_text).group(1)
        json_data = json.loads(json_data)
        prelogin_data = dict(json_data)
        for key, value in prelogin_data.items():
            prelogin_data[key] = str(value)
        # print(prelogin_data)
        return prelogin_data
    2. 模拟js计算加密后的usernamesu、模拟js计算加密后的passwordsp(加上上一步获取的pubkey、servertime、nonce)

    3. 把1中得到的全部postdata与其他固定值su、sp一起提交到http://login.sina.com.cn/sso/login.php?

    client=ssologin.js(v1.4.18),这个是请求登录的地址

    Note: postdata要手动加入这两个数据,它们是1中返回时解析不到的。仅仅有在抓包中看到。


    post_data.update({'pwencode': 'rsa2', 'url': r'http://weibo.com/ajaxlogin.php?

    framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack'})

    这个地址会跳转到passport.weibo.com/wbsso/login/,response会返回我们须要的地址,用正則表達式取出这个地址并请求, 得到例如以下正則表達式结果则登录成功

    http://passport.weibo.com/wbsso/login?ssosavestate=1472919508&url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack%26sudaref%3Dweibo.com&ticket=*****&retcode=0

    retcode=101则表示登录失败

    def start_requests(self):
        '''
        获取postdata并提交到登录地址
        '''
        login_url = globleOptions.login_url
        username = globleOptions.username
        password = globleOptions.password
    
        post_data = self.get_postdata(username, password)
        # headers能够不用加入
        headers = globleOptions.headers
    
        # 将数据提交到登录地址
        return [scrapy.http.FormRequest(url=login_url, formdata=post_data, callback=self.access_new_loginurl)]
    4. 还要请求上面得到的这个长地址(实际中的新登录地址),也就是得到重定位信息后,解析得到终于跳转到的新登录URL打开该URL后,server才会自己主动将用户登陆信息写入cookie,登陆成功。仅仅有写入了cookie,后面的登录才会顺利。

    def access_new_loginurl(self, response):
        '''
        获取新的登录地址并提交request訪问, 自己主动写入cookie, 下次就能够直接訪问其他站点了
        '''
        # print(response.body.decode('gb2312'))
        new_login_url = re.search(r"location.replace('(.*?

    )')", response.body).group(1) # print('new_login_url : %s ' % new_login_url) request = scrapy.http.Request(new_login_url) # 假设没有callback,就默觉得parse方法 return request

    5. 这时cookie已经写入,我们再訪问微博相关的网页,就能够直接得到登录后的页面数据了

    def parse(self, response):
        '''
        登录后的爬虫,parse方法会自己主动request遍历start_urls中的url
        '''
        for url in self.start_urls:
            request = scrapy.http.Request(url=url, callback=self.parse_item)
            # request = response.request.replace(url=globleOptions.redir_url, callback=self.parse_item)
            yield request
    def parse_item(self, response):
        '''
        处理items
        '''
        filename = re.split('//|?

    ', response.url)[1] # print(filename) filename = re.sub('/|?', '.', filename) + '.html' with open(os.path.join('./TmpFiles', filename), 'wb') as html_file: html_page = response.body html_file.write(html_page)

    Note:至于代码实现,能够用scrapy,也能够用python自带的urllib(当然这个明显爬取速度更快)

    保存请求的cookie
    仅仅要把保存的cookie持久化到文件, scrapy每次请求时带上这个cookie就能够了。

    from:http://blog.csdn.net/pipisorry/article/details/47008981


  • 相关阅读:
    [再寄小读者之数学篇](2014-07-17 一阶中值)
    对流体力学做出巨大贡献的杰出历史人物
    理科生毁灭世界
    [再寄小读者之数学篇](2014-07-17 行列式的计算)
    [再寄小读者之数学篇](2014-07-16 高阶导数的一个表达式)
    [再寄小读者之数学篇](2014-07-16 与对数有关的不等式)
    [再寄小读者之数学篇](2014-07-16 凹函数与次线性性)
    [再寄小读者之数学篇](2014-07-16 二阶中值)
    [再寄小读者之数学篇](2014-07-16 任意阶导数在零处为零的一个充分条件)
    对PostgreSQL xmin的深入学习
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/6749207.html
Copyright © 2020-2023  润新知