威尼斯www608cc:selenium模拟登陆今日头条天涯论坛

by admin on 2019年9月5日

登录第一步,添加自己的用户名(username),请求prelogin_url链接地址:

上一篇文章《Scrapy用Cookie实现模拟登录》完成了用Cookie实现模拟登录,绕开了用户名、密码和验证码登录的步骤。今天来比较一下以常规验证(用户名密码+验证码)的方式实现新浪微博的模拟登录,看看实现的过程中有哪些要注意的点。

PC登录新浪微博时,在客户端用js预先对用户名、密码都进行了加密,而且在POST之前会GET一组参数,这也将作为POST_DATA的一部分。这样,就不能用通常的那种简单方法来模拟POST登录(比如人人网)。

因为项目原因,我被领导委任爬取微博用户的一些信息,而作为一个爬虫经验几乎为0的python非老司机,开始了漫长的研究之路。。。。

刚学python不久,爬虫更是一个弱鸡,基本上一个小白,几周前侥幸在一个小公司得到一个数据分析的实习工作(真想感谢面试官大佬祖宗十八辈,真的是感谢!!)目前入职刚两周。入职当天部门boss让我写一个基于用户时间微博内容和评论的爬虫,之前只用过requests,beautifulsoup这几个库爬过豆瓣网,从来没爬过动态网页,但是本着不能给母校丢人的原则,我一拍胸脯,大喊一声没问题,然后boss微微一笑,气若游丝的飘来一句,用scrapy。我…..好了进入正题,跳过我没日没夜排查过的坑,开始写干货。

prelogin_url =
‘)’
% username

一、分析登录URL和表单字段

为了更好分析登录验证过程,找到登录提交的URL和表单字段,选取了新浪微博手机版的页面进行追踪分析,采用的工具是chrome开发者工具Network功能。

威尼斯www608cc 1

手机版登录页面

1、查看源代码,了解基本表单字段
通过查看登录页源代码,了解登录的url,用户名字段mobile,
密码字段password_9771(是password加上一个随机数),还有一些隐藏字段vk,
capId,以及验证码。

2、Network追踪登录过程
1)登录的完整表单字段:

威尼斯www608cc 2

Form Data记录

  • 这些字段名和值需要先从登录页面抓取:
    • 密码字段名不是一个固定的值,password+随机数
    • vk, capId是隐藏字段,登录时必须
    • code 是验证码

2)登录的全过程:
新浪微博的登录过程,第一步是提交用户名密码及其他参数,POST方法,后面经过4次重定向,完成登录。

威尼斯www608cc 3

查看新浪微博登录重定向过程

重定向都是通过location发送,get方法。理论上登录流程,重定向的过程不需要我们关心,但是Scrapy在发送登录请求时,会遇到种种问题,需要调试时,了解整个过程就很关键。

通过爬虫获取新浪微博数据,模拟登录是必不可少的。

在了解了爬虫的基本工具和著名框架scrapy后

我一开始只知道PC版的微博(大多数人貌似也只知道这一个版本的微博吧?),所以,先掀这口锅盖…先说为什么要模拟登录,进入PC版微博后,先不登录,随意点开一个用户进入微博主页,下拉,下拉,点击下一页,然后gg,必须登录才能进入下一页,所以要爬PC版微博必须先要模拟登录。有很多大佬分享过各种模拟登录的方法,每种方法有各自的优势,下面贴上我自己(啥??明明是粘贴复制别人的,竟然有脸说是自己的??)用selenium模拟登录新浪微博的代码:

使用get方法得到以下类似内容:

二、抓取登录表单及参数

1、先发送一个登录url请求:start_requests()方法

def start_requests(self):

        return [Request("http://login.weibo.cn/login/", meta={'cookiejar': 1}, callback=self.pre_login)]

2、抓取登录的表单字段:pre_login()方法

   def pre_login(self,response):


        selector = Selector(response)
        pwdname =selector.xpath('//input[@type="password"]/@name').extract()[0]
        vk = selector.xpath('//input[@name="vk"]/@value').extract()[0]
        imgsrc = selector.xpath('/html/body/div[2]/form/div/img[1]/@src').extract()[0]
        index = imgsrc.find('cpt=')
        capId = imgsrc[index+4:]

        action = selector.xpath('/html/body/div[2]/form/@action').extract()[0]
        action = 'http://login.weibo.cn/login/'+action

        # ... ... next, 完成验证码验证,构造表单参数...

1、在提交POST请求之前,需要GET获取四个参数(servertime,nonce,pubkey和rsakv),不是之前提到的只是获取简单的servertime,nonce,这里主要是由于js对用户名、密码加密方式改变了。

博主还是决定自己参考网上的各路大神的脚本,写一个登录脚本。。。。

# -*- coding: utf-8 -*-
import re
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
#from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC

def login():
    url='http://weibo.com/login.php'
    account='账户'
    passwd='密码'
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get(url)
    print('开始登陆')
    name_field = driver.find_element_by_id('loginname')
    name_field.clear()
    name_field.send_keys(account)
    password_field = driver.find_element_by_class_name('password').find_element_by_name('password')
    password_field.clear()
    password_field.send_keys(passwd)

    submit = driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[6]/a/span')
    time.sleep(2)
    submit.click()
#    ActionChains(driver).double_click(submit).perform()
    time.sleep(5)
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, 'WB_miniblog')))
    source = driver.page_source
    if is_login(source):
        print('登录成功')
#    print(sina_cookies)        
    sina_cookie=driver.get_cookies()
    driver.quit()
    return sina_cookie

def is_login(source):
    rs = re.search("CONFIG\['islogin'\]='(\d)'", source)
    if rs:
        return int(rs.group(1)) == 1
    else:
        return False

if __name__ == '__main__':
#    url ='http://weibo.com/login.php'
#    url='https://weibo.com/81715239?is_all=1'
#    name_input = input('请输入你的账号\n')
#    passwd_input = input('请输入你的密码\n')
#    cookies=login(name_input, passwd_input, url)
    cookies=login()

sinaSSOController.preloginCallBack({“retcode”:0,”servertime”:1362041092,”pcid”:”gz-6664c3dea2bfdaa3c94e8734c9ec2c9e6a1f”,”nonce”:”IRYP4N”,”pubkey”:”EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443″,”rsakv”:”1330428213″,”exectime”:1})

三、完成验证码的验证

在这里,我没有采用复杂的图片验证算法库,而是直接在控制台上把验证码的URL输出来,访问一下,手工填入的方式,codeimg = raw_input('please input image:'),
简单粗暴、快速准确。

威尼斯www608cc 4

查看验证码

1.1
由于加密方式的改变,我们这里将使用到RSA模块,有关RSA公钥加密算法的介绍可以参考网络中的有关内容。下载并安装rsa模块:

 

进而从中提取到我们想要的servertime,nonce,pubkey和rsakv。当然,pubkey和rsakv的值我们可以写死在代码中,它们是固定值。

四、构造表单参数,提交登录请求

         data = {'mobile':'name@126.com',    #你的微博帐号
                pwdname: '123456789',     #你的密码
                'code': codeimg,    #获取的验证码
                'remember':'',
                'backURL':'http://weibo.cn/u/2508944032',   #登录后要访问url
                'backTitle':u'手机新浪网',
                'tryCount':'',
                'vk':vk,            #隐藏字段
                'capId':capId,  #隐藏字段
                'submit':u'登录'}

yield FormRequest(url=action,meta={'cookiejar': response.meta['cookiejar']},headers=self.headers,formdata=data,callback=self.parse_item)

注意这里使用了FormRequest直接提交登录url和表单参数,而不是用FormRequest.from_response(),因为请求的登录url不一样。Scrapy官网《FormRequest.from_response()方法模拟用户登录》

OK,使用Scrapy完成新浪微博验证登录。在实现的过程也遇到不少问题,查看错误提示,不断调试。
可能是因为新浪微博登录参数和流程的更改,大家可以对比一下网络上的代码以及Scrapy官网上的说明。

下一步就是数据提取、保存。之前文章都有讲过。

威尼斯www608cc 5

控制台信息

下载:

环境

2、之前username经过BASE64计算:

Github地址 https://github.com/ppy2790/weibo.git

rsa模块文档地址:

tools

[python]  

根据自己的Python版本选择适合自己的rsa安装包(.egg),在win下安装需要通过命令行使用easy_install.exe(win上安装setuptool从这里下载:setuptools-0.6c11.win32-py2.6.exe
安装文件 )进行安装,例如:easy_install
rsa-3.1.1-py2.6.egg,最终命令行下测试import rsa,未报错则安装成功。

1、Chrome及其developer tools

username_ = urllib.quote(username)  

1.2 获得以及查看新浪微博登录js文件

2、Charles【这个是fiddler的Mac替代版,付费软件,但是网上有破解版的,可以搜一下,用着比Mac版的fiddler舒服多了】

username = base64.encodestring(username)[:-1]  <span
style=”font-family: Arial, Helvetica, sans-serif;”>  </span>  

查看新浪通行证url

3、python3.6

password经过三次SHA1加密,且其中加入了 servertime 和 nonce
的值来干扰。即:两次SHA1加密后,结果加上servertime和nonce的值,再SHA1算一次。

1.3 登录

4、pycharm

在最新的rsa加密方法中,username还是以前一样的处理;

登录第一步,添加自己的用户名(username),请求prelogin_url链接地址:

查询资料的过程中,因为微博登录有好几个跳转,很多大神建议preserve log模式打开

password加密方式和原来有所不同:

prelogin_url =
‘)’
% username

 

2.1
先创建一个rsa公钥,公钥的两个参数新浪微博都给了固定值,不过给的都是16进制的字符串,第一个是登录第一步中的pubkey,第二个是js加密文件中的‘10001’。

使用get方法得到以下类似内容:

python3.6中使用的库

这两个值需要先从16进制转换成10进制,不过也可以写死在代码里。这里就把10001直接写死为65537。代码如下:

sinaSSOController.preloginCallBack({“retcode”:0,”servertime”:1362041092,”pcid”:”gz-6664c3dea2bfdaa3c94e8734c9ec2c9e6a1f”,”nonce”:”IRYP4N”,”pubkey”:”EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443″,”rsakv”:”1330428213″,”exectime”:1})

1、urllib.request、urllib.error、urllib.parse

[python] 

进而从中提取到我们想要的servertime,nonce,pubkey和rsakv。当然,pubkey和rsakv的值我们可以写死在代码中,它们是固定值。

2、re——正则表达式

rsaPublickey = int(pubkey, 16)  

 

3、rsa、base64

key = rsa.PublicKey(rsaPublickey, 65537) #创建公钥  

2、之前username 经过BASE64计算:

4、json

message = str(servertime) + ‘\t’ + str(nonce) + ‘\n’ +
str(password)#拼接明文 js加密文件中得到  

复制代码 代码如下:

5、binascii——对加密数据进行编码

passwd = rsa.encrypt(message, key)#加密  

username_ = urllib.quote(username)
username = base64.encodestring(username)[:-1]

ps:博主这里用的是anaconda自带的库,发现rsa和base64需要用pip另外下载

passwd = binascii.b2a_hex(passwd) #将加密信息转换为16进制。  

password经过三次SHA1加密,且其中加入了 servertime 和 nonce
的值来干扰。即:两次SHA1加密后,结果加上servertime和nonce的值,再SHA1算一次。

 

2.2 请求通行证url:login_url
=‘

在最新的rsa加密方法中,username还是以前一样的处理;

系统

需要发送的报头信息

password加密方式和原来有所不同:

Mac OS 10.13.2

[python]  

2.1
先创建一个rsa公钥,公钥的两个参数新浪微博都给了固定值,不过给的都是16进制的字符串,第一个是登录第一步中的pubkey,第二个是js加密文件中的‘10001’。

 

postPara = {  

这两个值需要先从16进制转换成10进制,不过也可以写死在代码里。这里就把10001直接写死为65537。代码如下:

weibo.com登录

        ‘entry’: ‘weibo’,  

复制代码 代码如下:

当我登录微博后,每隔一段时间就会出现push_count.json文件,当我们点击输入用户名时,会出现prelogin.php文件,引起了我们的注意

        ‘gateway’: ‘1’,  

rsaPublickey = int(pubkey, 16)
key = rsa.PublicKey(rsaPublickey, 65537) #创建公钥
message = str(servertime) + ‘\t’ + str(nonce) + ‘\n’ + str(password)
#拼接明文js加密文件中得到
passwd = rsa.encrypt(message, key) #加密
passwd = binascii.b2a_hex(passwd) #将加密信息转换为16进制。

威尼斯www608cc 6

        ‘from’: ”,  

2.2 请求通行证url:login_url
=‘)’

点开查看,会发现一些十分可疑的东西,比如su。

        ‘savestate’: ‘7’,  

需要发送的报头信息

这里我们用base64对其解码试试

        ‘userticket’: ‘1’,  

复制代码 代码如下:

1 import base64
2 print(base64.b64decode('MzU4NTEwMjQ5JTQwcXEuY29t'))

        ‘ssosimplelogin’: ‘1’,  

postPara = {
        ‘entry’: ‘weibo’,
        ‘gateway’: ‘1’,
        ‘from’: ”,
        ‘savestate’: ‘7’,
        ‘userticket’: ‘1’,
        ‘ssosimplelogin’: ‘1’,
        ‘vsnf’: ‘1’,
        ‘vsnval’: ”,
        ‘su’: encodedUserName,
        ‘service’: ‘miniblog’,
        ‘servertime’: serverTime,
        ‘nonce’: nonce,
        ‘pwencode’: ‘rsa2’,
        ‘sp’: encodedPassWord,
        ‘encoding’: ‘UTF-8’,
        ‘prelt’: ‘115’,
        ‘rsakv’ : rsakv,
        ‘url’:
”,
        ‘returntype’: ‘META’
    }

输出结果为:b’358510249%40qq.com’

        ‘vsnf’: ‘1’,  

请求的内容中添加了rsakv,将pwencode的值修改为rsa2,其他跟以前一致。

果然,是用户名!!!

        ‘vsnval’: ”,  

将参数组织好,POST请求。检验是否登录成功,可以参考POST后得到的内容中的一句
location.replace(“”);

需要注意的是,用户名中可能包含@这样的符号,而我们刚才看到的加密过的su,解码之后@变成了%40,这其实是url的编码

        ‘su’: encodedUserName,  

如果retcode=101则表示登录失败。登录成功后结果与之类似,不过retcode的值是0。

 

        ‘service’: ‘miniblog’,  

3、登录成功后,在body中的replace信息中的url就是我们下一步要使用的url。然后对上面的url使用GET方法来向服务器发请求,保存这次请求的Cookie信息,就是我们需要的登录Cookie了。

然后为了方便查看,我们切换到charles工具查看一下prelogin.php的body部分

        ‘servertime’: serverTime,  

sinaSSOController.preloginCallBack({
    "retcode": 0,
    "servertime": 1515836591,
    "pcid": "gz-cd9bccf44f515b8765496d8694e51ba7c996",
    "nonce": "JLT53P",
    "pubkey": "EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443",
    "rsakv": "1330428213",
    "is_openlock": 0,
    "showpin": 0,
    "exectime": 5
})

        ‘nonce’: nonce,  

一眼望过去,哇,长得好像json,嗨森!

        ‘pwencode’: ‘rsa2’,  

有用的似乎有servertime、nonce、rsakv以及这长长的pubkey。。。。是什么鬼!!

        ‘sp’: encodedPassWord,  

一查:好嘛,非对称加密,呵呵好开心。。。。。才怪!!!QAQ

        ‘encoding’: ‘UTF-8’,  

 

        ‘prelt’: ‘115’,  

登录微博

        ‘rsakv’ : rsakv,  www.2cto.com

在这里,我们需要用到Charles来抓取跳转的连接。结果如下:

        ‘url’:
”,
 

威尼斯www608cc 7

        ‘returntype’: ‘META’  

我们抓取的目标就是prelogin后面出现的POST表单login.php?client=ssologin.js(v1.4.19)

    }  

观察一下里面的内容:

请求的内容中添加了rsakv,将pwencode的值修改为rsa2,其他跟以前一致。

entry:weibo
gateway:1
from:
savestate:7
qrcode_flag:false
useticket:1
pagerefer:https://login.sina.com.cn/crossdomain2.php?action=logout&r=https%3A%2F%2Fweibo.com%2Flogout.php%3Fbackurl%3D%252F%252Fs.weibo.com
vsnf:1
su:MzU4NTEwMjQ5JTQwcXEuY29t
service:miniblog
servertime:1515895583
nonce:JLT53P
pwencode:rsa2
rsakv:1330428213
sp:02ca1b627293c21e098882de3e276def93654ffba9817d0d95174b11c403e46e8016bf66ed421198fffaaa691fb0c9d03d45da676de0282a30aef899855262e09164dfef35eb6820ba017ecf8f437643fe94eaf0632095ffcc647ada27b23c9ed1b1c8f7d1d87ce2c69ed4f9997fb9283c42622c677dbecfe60a802f4b621ee3
sr:1680*1050
encoding:UTF-8
prelt:31
url:https://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack
returntype:META

将参数组织好,POST请求。检验是否登录成功,可以参考POST后得到的内容中的一句
location.replace(“”);

不难看出,su即username,sp即password,sp显然已经用rsa加密过。

如果retcode=101则表示登录失败。登录成功后结果与之类似,不过retcode的值是0。

 

3、登录成功后,在body中的replace信息中的url就是我们下一步要使用的url。然后对上面的url使用GET方法来向服务器发请求,保存这次请求的Cookie信息,就是我们需要的登录Cookie了。

为了解密加密过后的sp,我们首先需对js进行分析。

prelogin_url =

首先,登录的时候会出现一个post表单login.php?client=ssologin.js(v1.4.19),随后出现一个ssologin.js文件,点开以后,我们发现了一堆密密麻麻的东西。

结合之前的信息,我们已经知道RSA加密和一个叫pubkey的参数,搜一下,立刻能得到我们想要的信息:

威尼斯www608cc 8

这里,10001就是rsa加密用到的exponent,需要注意的是,它是16进制的,所以我们还需要将其转化为10进制。

另一个信息就死我们的password啦

password=RSAKey.encrypt([me.servertime,me.nonce].join("\t")+"\n"+password)}

对应的Python加密代码如下:

 1 import rsa
 2 import binascii
 3 def get_encrypted_pw(self, data):
 4     rsa_e = int('10001',16)  # 0x10001
 5     pw_string = str(servertime) + '\t' + str(nonce) + '\n' + str(password)
 6     key = rsa.PublicKey(int(pubkey, 16), rsa_e)
 7     pw_encypted = rsa.encrypt(pw_string.encode('utf-8'), key)
 8     password = ''  # 安全起见清空明文密码
 9     passwd = binascii.b2a_hex(pw_encypted)  #将二进制编码转化为ascii/hex
10     print(passwd)
11     return passwd

 

最终代码

威尼斯www608cc 9威尼斯www608cc 10

  1 # 导入所需模块
  2 import urllib.error
  3 import urllib.request
  4 import urllib.parse
  5 import re
  6 import rsa
  7 import http.cookiejar  #从前的cookielib
  8 import base64
  9 import json
 10 import urllib
 11 import binascii
 12 
 13 # 简历Launcher类
 14 class Launcher():
 15     # 初始化username和password这两个参数
 16     def __init__(self,username,password):
 17         self.username = username
 18         self.password = password
 19 
 20     #建立get_encrypted_name方法,获取base64加密后的用户名
 21     def get_encrypted_name(self):
 22         # 将字符串转化为url编码
 23         username_urllike = urllib.request.quote(self.username)
 24         username_encrypted = base64.b64encode(bytes(username_urllike, encoding='utf-8'))
 25         return username_encrypted.decode('utf-8')  # 将bytes对象转为str
 26 
 27     def get_prelogin_args(self):
 28         '''
 29         该函数用于模拟预登录过程,并获取服务器返回的 nonce , servertime , pubkey 等信息,用一个字典返回数据
 30         '''
 31         json_pattern = re.compile('\((.*)\)')
 32         url = 'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&' + self.get_encrypted_name() + '&rsakt=mod&client=ssologin.js(v1.4.19)'
 33         try:
 34             request = urllib.request.Request(url)
 35             response = urllib.request.urlopen(request)
 36             raw_data = response.read().decode('utf-8')
 37             # 利用正则取出json
 38             json_data = json_pattern.search(raw_data).group(1)
 39             # 讲json包装成字典
 40             data = json.loads(json_data)
 41             # print(data)
 42             return data
 43         except urllib.error as e:
 44             print("%d" % e.code)
 45             return None
 46 
 47     # 建立get_encrypeted_pw获取登录信息生成的rsa加密版密码
 48     def get_encrypted_pw(self, data):
 49         rsa_e = int('10001',16)  # 0x10001
 50         pw_string = str(data['servertime']) + '\t' + str(data['nonce']) + '\n' + str(self.password)
 51         key = rsa.PublicKey(int(data['pubkey'], 16), rsa_e)
 52         pw_encypted = rsa.encrypt(pw_string.encode('utf-8'), key)
 53         self.password = ''  # 安全起见清空明文密码
 54         passwd = binascii.b2a_hex(pw_encypted)
 55         print(passwd)
 56         return passwd
 57 
 58     def enableCookies(self):
 59         # 建立一个cookies 容器
 60         cookie_container = http.cookiejar.CookieJar()
 61         # 将一个cookies容器和一个HTTP的cookie的处理器绑定
 62         cookie_support = urllib.request.HTTPCookieProcessor(cookie_container)
 63         # 创建一个opener,设置一个handler用于处理http的url打开
 64         opener = urllib.request.build_opener(cookie_support, urllib.request.HTTPHandler)
 65         # 安装opener,此后调用urlopen()时会使用安装过的opener对象
 66         urllib.request.install_opener(opener)
 67 
 68     # 构造build_post_data方法,用于包装一个POST方法所需的数据
 69     def build_post_data(self, raw):
 70         post_data = {
 71             "entry": "weibo",
 72             "gateway": "1",
 73             "from": "",
 74             "savestate": "7",
 75             "qrcode_flag":'false',
 76             "useticket": "1",
 77             "pagerefer": "https://login.sina.com.cn/crossdomain2.php?action=logout&r=https%3A%2F%2Fweibo.com%2Flogout.php%3Fbackurl%3D%252F",
 78             "vsnf": "1",
 79             "su": self.get_encrypted_name(),
 80             "service": "miniblog",
 81             "servertime": raw['servertime'],
 82             "nonce": raw['nonce'],
 83             "pwencode": "rsa2",
 84             "rsakv": raw['rsakv'],
 85             "sp": self.get_encrypted_pw(raw),
 86             "sr": "1680*1050",
 87             "encoding": "UTF-8",
 88             "prelt": "194",
 89             "url": "https://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack",
 90             "returntype": "META"
 91         }
 92         data = urllib.parse.urlencode(post_data).encode('utf-8')
 93         return data
 94 
 95     # 登录,注意这里需要进行三次跳转
 96     def login(self):
 97         url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)'
 98         self.enableCookies()
 99         data = self.get_prelogin_args()
100         post_data = self.build_post_data(data)
101         headers = {
102             "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
103         }
104         try:
105             request = urllib.request.Request(url=url, data=post_data, headers=headers)
106             response = urllib.request.urlopen(request)
107             html = response.read().decode('GBK')
108             '''
109             一开始用的是utf-8解码,然而得到的数据很丑陋,却隐约看见一个GBK字样。所以这里直接采用GBK解码
110             '''
111             # print(html)
112         except urllib.error as e:
113             print(e.code)
114 
115         p = re.compile('location\.replace\("(.*?)"\)')
116         p2 = re.compile("location\.replace\('(.*?)'\)")
117         p3 = re.compile(r'"userdomain":"(.*?)"')
118         try:
119             login_url = p.search(html).group(1)
120             request = urllib.request.Request(login_url)
121             response = urllib.request.urlopen(request)
122             page = response.read().decode('GBK')
123             # print(page)
124             login_url2 = p2.search(page).group(1)
125             request = urllib.request.Request(login_url2)
126             response = urllib.request.urlopen(request)
127             page2 = response.read().decode('utf-8')
128             # print(page2)
129             login_url = 'http://weibo.com/' + p3.search(page2).group(1)
130             request = urllib.request.Request(login_url)
131             response = urllib.request.urlopen(request)
132             final = response.read().decode('utf-8')
133             print(final)
134 
135             print("Login success!")
136         except:
137             print('Login error!')
138             return 0

View Code

 

值得注意的是,在最后的login中,我们现尝试直接登录,看看返回的是什么。

 1 def login(self):
 2     url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)'
 3     self.enableCookies()
 4     data = self.get_prelogin_args()
 5     post_data = self.build_post_data(data)
 6     headers = {
 7         "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
 8     }
 9     try:
10         request = urllib.request.Request(url=url, data=post_data, headers=headers)
11         response = urllib.request.urlopen(request)
12         html = response.read().decode('GBK')
13         '''
14         一开始用的是utf-8解码,然而得到的数据很丑陋,却隐约看见一个GBK字样。所以这里直接采用GBK解码
15         '''
16         print(html)
17         print('-------------------------')
18     except urllib.error as e:
19         print(e.code)

很好,我们看到的果然是一堆奇怪的东西呢!!

<html>
<head>
<title>新浪通行证</title>
<meta http-equiv="refresh" content="0; url=&#39;https://login.sina.com.cn/crossdomain2.php?action=login&entry=weibo&r=https%3A%2F%2Fpassport.weibo.com%2Fwbsso%2Flogin%3Fssosavestate%3D1547533996%26url%3Dhttps%253A%252F%252Fweibo.com%252Fajaxlogin.php%253Fframelogin%253D1%2526callback%253Dparent.sinaSSOController.feedBackUrlCallBack%26display%3D0%26ticket%3DST-MjQ2Nzk2MDk3Mg%3D%3D-1515997996-gz-5F219439701347BC4686F4A3E10C79C9-1%26retcode%3D0&sr=1680%2A1050&#39;"/>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
</head>
<body bgcolor="#ffffff" text="#000000" link="#0000cc" vlink="#551a8b" alink="#ff0000">
<script type="text/javascript" language="javascript">
location.replace("https://login.sina.com.cn/crossdomain2.php?action=login&entry=weibo&r=https%3A%2F%2Fpassport.weibo.com%2Fwbsso%2Flogin%3Fssosavestate%3D1547533996%26url%3Dhttps%253A%252F%252Fweibo.com%252Fajaxlogin.php%253Fframelogin%253D1%2526callback%253Dparent.sinaSSOController.feedBackUrlCallBack%26display%3D0%26ticket%3DST-MjQ2Nzk2MDk3Mg%3D%3D-1515997996-gz-5F219439701347BC4686F4A3E10C79C9-1%26retcode%3D0&sr=1680%2A1050");
</script>
</body>
</html>

 

看大神的解释说,这是一段重新定向的的代码,重新定向的url写在location.replace后面,所以我们需要编写一段正则表达式将这段url爬取下来。

 1 p = re.compile('location\.replace\("(.*?)"\)')
 2 try:
 3     login_url = p.search(html).group(1)
 4     request = urllib.request.Request(login_url)
 5     response = urllib.request.urlopen(request)
 6     page = response.read().decode('GBK')
 7     print(page)
 8 except:
 9     print('Login error!')
10     return 0

来看看结果:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>新浪通行证</title>


<script charset="utf-8" src="https://i.sso.sina.com.cn/js/ssologin.js"></script>
</head>
<body>
正在登录 ...
<script>
try{sinaSSOController.setCrossDomainUrlList({"retcode":0,"arrURL":["https:\/\/passport.weibo.com\/wbsso\/login?ticket=ST-MjQ2Nzk2MDk3Mg%3D%3D-1515997996-gz-0D1D8222688249D4F950E05810AD22DD-1&ssosavestate=1547533996","https:\/\/passport.97973.com\/sso\/crossdomain?action=login&savestate=1547533996","https:\/\/passport.krcom.cn\/sso\/crossdomain?service=krvideo&savestate=1&ticket=ST-MjQ2Nzk2MDk3Mg%3D%3D-1515997996-gz-94884ABE2B9E4113CE7B809F4B5C92DC-1&ssosavestate=1547533996","https:\/\/passport.weibo.cn\/sso\/crossdomain?action=login&savestate=1"]});}
        catch(e){
            var msg = e.message;
            var img = new Image();
            var type = 1;
            img.src = 'https://login.sina.com.cn/sso/debuglog?msg=' + msg +'&type=' + type;
        }try{sinaSSOController.crossDomainAction('login',function(){location.replace('https://passport.weibo.com/wbsso/login?ssosavestate=1547533996&url=https%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack&display=0&ticket=ST-MjQ2Nzk2MDk3Mg==-1515997996-gz-5F219439701347BC4686F4A3E10C79C9-1&retcode=0');});}
        catch(e){
            var msg = e.message;
            var img = new Image();
            var type = 2;
            img.src = 'https://login.sina.com.cn/sso/debuglog?msg=' + msg +'&type=' + type;
        }
</script>
</body>
</html>

很好又是一堆奇怪的东西!(ノಠ益ಠ)ノ彡┻━┻不过仔细一看,是不是还挺眼熟??

OMG!!location.replace
again!!!只是这次后面的链接似乎是passport.weibo.com,哇哦~是不是敲像正式登陆的~

 

话不多说,立刻先用这则表达把这段url提取出来再说!

 1 p2 = re.compile("location\.replace\('(.*?)'\)")
 2 try:
 3     login_url2 = p2.search(page).group(1)
 4     request = urllib.request.Request(login_url2)
 5     response = urllib.request.urlopen(request)
 6     page2 = response.read().decode('utf-8')
 7     print(page2)
 8 except:
 9     print('Login error!')
10     return 0

本以为这次妥妥的了的我看到的结果却是。。。。

<html><head><script language='javascript'>parent.sinaSSOController.feedBackUrlCallBack({"result":true,"userinfo":{"uniqueid":"2467960972","userid":null,"displayname":null,"userdomain":"?wvr=5&lf=reg"}});</script></head><body></body></html>

呵呵,又是一个重定向= =

然而这次很轻易地注意到里面有个"?wvr=5&lf=reg"字段肥肠眼熟,看看刚才手工登陆抓到的包,果然,这是最终链接的一部分。

所以再搞一个正则表达式,把该字段也搞出来,然后拼接一个最终url出来,就可以轻松而愉悦地模拟登陆了!

威尼斯www608cc 11

以上~

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图