模拟登陆就是获取新浪服务器返回的登陆参数(cookies等),然后添加到爬虫的post请求中来伪装用户提交给新浪访客系统
首先感谢 Bgods(https://blog.csdn.net/songzhilian22/article/details/48396545)
敲代码的耗子(http://www.cnblogs.com/mouse-coder/archive/2013/03/03/2941265.html?utm_source=tuicool)等前辈的启发
所需工具:chrome
python库:requests, re,rsa,binascii, base64, urllib
一.分析新浪微博登陆机制
首先打开新浪通行证http://login.sina.com.cn/
然后打开chrome开发者工具Network页面 勾选 Preserve log 监控登陆过程
输入账户密码登陆(要记得提前清理浏览器Cookies)
可以观察到登陆过程中浏览器发出的请求
主要分析这三个请求
分别观察三个请求的Response_headers 和Cookies可以发现是在第二个请求中set的cookies
所以只要模拟了第二个请求就能拿到cookies
二.模拟登陆
PC登录新浪微博时,在客户端用js预先对用户名、密码都进行了加密,而且在POST之前会GET一组参数,这也将作为POST_DATA的一部分.
2.1GET获取四个参数(servertime,nonce,pubkey和rsakv)
username = '11111111'.encode() #str 转bytes
url = 'https://login.sina.com.cn/sso/prelogin.php?entry=account&callback=sinaSSOController.preloginCallBack&su={}&rsakt=mod&client=ssologin.js(v1.4.15)&_={}'.format(quote(username),quote(username))
构造出url后GET获取四个参数servertime,nonce,pubkey和rsakv的值
sever_data = eval(result.content.decode("utf-8").replace("sinaSSOController.preloginCallBack", ''))
观察第二个请求的post表单(su,sp分别为加密后的username和password)
刚才的四个参数已经拿到,还需要对密码进行加密
ssologin.js文件中定义了加密过程,右键点击在source中打开可以看到加密算法
密码加密为RSA算法 10001为加密公钥参数另一个公钥参数为第一次GET请求的返回的pubkey
2.2加密password username
us = base64.b64encode(username) # 加密用户名
rsaPublickey = int(pubkey, 16)
key = rsa.PublicKey(rsaPublickey, 65537) #创建公钥
message = str(servertime) + '\t' + str(nonce) + '\n' + str(password) #拼接明文js加密文件中得到
message = message.encode('utf-8')
passwd = rsa.encrypt(message, key) #加密
passwd = binascii.b2a_hex(passwd) #将加密信息转换为16进制。
print('加密后的passwd',passwd)
2.3提交post请求
login_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)&_={}'.format(quote(username))
data = {'entry': 'weibo',
'gateway': '1',
'from': 'null',
'savestate': '30',
'userticket': '0',
'pagerefer': '',
#'ssosimplelogin': '1',
'vsnf': '1',
#'vsnval': '',
'su': username,
'service': 'account',
'servertime': servertime,
'nonce': nonce,
'pwencode': 'rsa2',
'sp': passwd,
'encoding': 'UTF-8',
'prelt': '49',
'rsakv' : rsakv,
'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
'returntype': 'META',
#'cdult': '3',
#'sr': '1536*864',
#'pcid': pcid,
}
(其中的pcid是验证码id,如登陆过程中遇到验证码, 可以利用picd下载验证码后对接打码平台破解)
拿到result 可以观察replace的url中的retcode参数 retcode=0,则说明登陆成功,如果是retcode=101则说明是失败
这就是上面三个请求中的第二个请求 根据响应头正则提取出cookies(sub, subp, login 这三个参数为主要参数,其它的没试)
拿到这个页面后会发现它重新replace到了一个新的页面(登陆页面), 同样正则提取出url后访问这个页面(带上刚才提取的cookies)
2.4登陆页面
result2 = requests.get(urlnew1, cookies=cookies1, headers=headers) #正在登陆界面
如果得到如下页面则登陆成功说明刚才的cookies可用,接下来就可以保存并利用此cookies登陆新浪微博了(新浪的cookies失效时间大概是15个小时左右记不清了)
同时会发现又replace到了一个新地址,我尝试抓取了这个页面分析了一下响应头发现它可能会重新set-cookies(login参数),我试的很多次中只出现了一次这种情况所以没有弄清机制,同时原cookies也可用,以防万一我还是写了一个函数更新cookies
new_set_cookies = result2.cookies
new_set_cookies = requests.utils.dict_from_cookiejar(new_set_cookies) #cookies转字典
print('new_set_cookies:', new_set_cookies)
if new_set_cookies == {}: #是否重新设置login cookie
result2 = requests.get(urlnew2, cookies=cookies1, headers=headers) #未知界面
response2 = result2.headers
print('response2未知界面:')
html = result2.content # 获取二进制内容
html = html.decode('GBK', 'replace')
print(html)
return cookies1
else:
cookies1['login'] = new_set_cookies['login']
return cookies1
详细代码上传到github后会更新链接