获取微博登录Cookies的几种方案

为什么需要获取登录后Cookies

  1. 微博爬虫
  2. 微博图床

目前这两个项目所使用的cookies值,都是手工复制的,虽然工作的很好,但是时间久了也挺烦的。

直接模拟(方案A)

微博的登录网上已有开源方案:https://github.com/xchaoinfo/fuck-login

需要说明的一点是看现在的登录代码不是特别复杂,但是如果自己分析的话,难度还是比较大的。需要说明的是这边是直接模拟:weibo.com 上的登录框,所以每次登录的时候都需要验证码。

间接方案(方案B)

目前这个方案,还不需要验证码

登录点:https://login.sina.com.cn/signup/signin.php?entry=sso

登录获取跨域登录链接(ajax)

{
retcode: "0",
uid: "2437997797",
nick: "用户2437997797",
crossDomainUrlList: [
"https://passport.weibo.com/wbsso/login?ticket=ST-MjQzNzk5Nzc5Nw%3D%3D-1476862474-xd-C1439DCDBC3B12C3A8C02748E9EC9173&ssosavestate=1508398474",
"https://passport.weibo.cn/sso/crossdomain?action=login&savestate=1"
]
}

访问跨域登录链接(get)

返回值如下所示

{
result: true,
userinfo: {
uniqueid: "2437997797",
displayname: "用户2437997797"
}
}

直接访问微博(get)

浏览器内直接访问:weibo.com,就可以自动登录上了。

利用phantomJS获取cookies【方案B实现】

使用phantomJS主要原因就是,自己去分析实现微博的登录流程比较复杂耗时,干脆用一个webkit内核浏览器去访问就好了,然后再间接获取到cookies值。

方案二的登录流程用phantomJS来实现的示例代码如下:

var pageA = require('webpage').create();
pageA.open('https://passport.weibo.com/wbsso/login?ticket=ST-MjQzNzk5Nzc5Nw%3D%3D-1476862474-xd-C1439DCDBC3B12C3A8C02748E9EC9173&ssosavestate=1508398474', function(status) {
console.log('Status: ' + status);
if (status === 'success') {
var cookie = pageA.evaluate(function() {
return document.cookie
});
console.log(cookie)
setTimeout(openPageB, 200);
} else {
phantom.exit(1);
}
});
var pageB = require('webpage').create();
pageB.onResourceReceived = function(response) {
console.log('pageB Data...');
console.log('Request ' + JSON.stringify(response, undefined, 4));
console.log('the pageB Cookie is...');
var cookie = pageB.evaluate(function() {
return document.cookie
});
console.log(cookie)
}
function openPageB() {
pageB.open('http://weibo.com', function(status) {
if (status == 'success') {
console.log('weibo page success');
var cookie = pageB.evaluate(function() {
return document.cookie
});
console.log(cookie)
pageB.render('222.png');
} else {
console.log('weibo page failed');
phantom.exit(1);
}
});
}

需要说明的代码内pageA.open()内的链接,就是方案B中说明的跨域登录链接。
获取到的cookies如下所示,我做了整理。

ALF=1508402613;
Apache=8011726459953.934.1476866663139;
SCF=【实际需要,但phantomJS没获取到】
SINAGLOBAL=8011726459953.934.1476866663139;
SSOLoginState=1476866657;
SUB=【实际需要,但phantomJS没获取到】
SUHB=079ir7sjI-ybjm;
SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WWRA0_nRLiEO4qNVpFZ7AQh5JpX5K2hUgL.FozXe0M41KMN1KM2dJLoI7fzqgL0dgLj9HvNqg4r;
ULV=1476866663145:1:1:1:8011726459953.934.1476866663139:
UOR=【可有可无,但phantomJS也没获取到】
YF-Page-G0=【可有可无,但phantomJS没获取到】
YF-Ugrow-G0=b02489d329584fca03ad6347fc915997;
YF-V5-G0=a0e87040bfaca9b1b05c465a9e888d2d;
_s_tentry=-;
wvr=6;

但是这个cookies却无法用在其他地方,因为缺少了最重要的两个cookie值SCF和SUB,那为什么没获取到这两个cookies值呢?看下面的截图。
新浪微博cookies截图

可以发现,这两个cookies值被设置成了HTTP-ONLY,也就是说使用Javascript是无法通过document.cookie获取到的。
这个是浏览器特性,具体可以参考这里:HttpOnly,简单来说就是为了防止XSS盗取cookies,然后伪造用户。

虽然两个最重要的cookies通过phantomJS无法获取,那么再变通一下,因为phantomJS内的无界面webkit浏览器已经是登录上微博了,所有的请求都会带上包含SCF和SUB的cookies串。

我们可以写个后台常驻的后台脚本来监控phantomJS产生的网络请求,这样就能够抓取到微博的cookies值了。具体怎么玩,我还没有研究。

总的来说,利用phantomJS来获取一些没有设置HTTP-only型cookies但登录又有点复杂的网站的cookies时是非常方便高效的。

Python模拟实现【方案B实现】

# coding: utf-8
import requests
import json
import base64
def login(username, password):
username = base64.b64encode(username.encode('utf-8')).decode('utf-8')
postData = {
'entry': 'sso',
'gateway': '1',
'from': 'null',
'savestate': '30',
'userticket': '0',
'pagerefer': '',
'vsnf': '1',
'su': username,
'service': 'sso',
'sp': password,
'sr': '1440*900',
'encoding': 'UTF-8',
'cdult': '3',
'domain': 'sina.com.cn',
'prelt': '0',
'returntype': 'TEXT',
}
loginURL = r'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)'
session = requests.Session()
res = session.post(loginURL, data = postData)
jsonStr = res.content.decode('gbk')
info = json.loads(jsonStr)
print info
if info["retcode"] == "0":
print("登录成功")
# 把cookies添加到headers中,必须写这一步,否则后面调用API失败
weibo_com_session = requests.Session()
ret = weibo_com_session.get(info['crossDomainUrlList'][0])
print ret.content
cookies = ret.cookies.get_dict('.weibo.com', '/')
cookies = [key + "=" + value for key, value in cookies.items()]
cookies = "; ".join(cookies)
print cookies
else:
print("登录失败,原因: %s" % info["reason"])
return session
if __name__ == '__main__':
session = login('username', 'password')

前半部分登录脚本是抄自:Python-模拟登录新浪微博

踩过的一个小坑

在把图片上传至微博图床的时候,一定要是事先保证图片是有效的,否则会上传失败,原先一直以为是cookies的问题,导致浪费了好几天的时间研究微博的登录过程。