这次想试一试模拟登陆,以为应该会很顺利,但是遇到了各种问题,所以记录总结一下。
参考文章:请点击这里
模拟登陆segmentfault
参考文章使用的node.js
,感觉没有python
用起来方便。
工具
python2.7
Chrome浏览器
requests
PyV8
lxml
思路
首先进入segmentfault的登陆页面。
可以随便输入错误密码点击登陆,使用Chrome
查看请求发到了哪个url
。
另外看post的参数,这里有三个:remember
, username
和 password
。
然后可以顺便按照Requests Headers
把请求头设置好(照抄到代码里)。
requests
库的session
对象能够帮我们跨请求保持某些参数,也会在同一个session
实例发出的所有请求之间保持cookies
。
使用:
# 创建一个session对象
session = requests.session()
# 用session对象发出get请求
response = session.get('https://segmentfault.com/user/login')
# 获取cookie
cookies = response.cookies
设置了请求头,cookie也拿到了,看看post的url
发现这段url后面是带了查询字符串的,每次发请求都会变化。
只有明白它是如何生成的才能取得我们要post的url,这里我卡了好久,去寻找答案,才找到了参考文章,这里面提供了思路获取js中生成的token。
- 在
login.min.js
中查询字符串 "_=" (Chrome f12下使用快捷键Crtl+F可以打开查询窗口),因为注意到url是https://segmentfault.com/api/user/login?_=[querystring]
发现要post的url是根url加上"?_=
"再加上a._
.
可以想到a
是一个对象,_
是a
这个对象的一个属性。
可以找到:
于是发现了a._
是window.SF.token
取得token
分析:回到login
文件发现token
是html
中的script
标签中一个函数生成的,而html可以使用requests.get
取得,然后可以通过python
的re
模块用正则表达式提取出所需要的函数,这时还需要python
中的PyV8
模块来执行js函数。
执行:分析html的DOM节点,发现函数的位置,使用xpath取得那个script标签
response = requests.get('https://segmentfault.com/user/login')
sel = html.fromstring(response.text)
s = sel.xpath('/html/body/script[8]/text()')[0]
st = str(s.encode('utf-8'))
写一个get_token
函数取得token
(这里要用到PyV8
模块实现python
和JavaScript
的交互)
这个DOM目前是这样的:
<script>
(function (w) {
w.SF = {
staticUrl: "https://static.segmentfault.com/v-5aa63d11"
};
w.SF.token = (function () {
var _PRmciaY = //'Uns'
'f44'+//'71w'
'b1e'+//'C'
'9a'+//'cM'
'e4'+'b75'//'x'
+//'PoE'
'163'+//'jxT'
'2'+'61'//'uuJ'
+'1'//'4jI'
+'5'//'bC'
+'e60'//'1XN'
+//'C'
'C'+'m'//'m'
+'8'//'q5g'
+//'I'
'b1'+//'R'
'b64'+//'1'
'2c', _44R = [[24,25],[24,25]];
for (var i = 0; i < _44R.length; i ++) {
_PRmciaY = _PRmciaY.substring(0, _44R[i][0]) + _PRmciaY.substring(_44R[i][1]);
}
return _PRmciaY;
})();;
})(window);
var lock = {
type: "",
text: '',
table: {"ban_post":[1,"\u4f60\u5df2\u7ecf\u88ab\u7981\u8a00, \u65e0\u6cd5\u8fdb\u884c\u6b64\u64cd\u4f5c, \u5982\u6709\u7591\u4e49\u8bf7\u63d0\u4ea4\u7533\u8bc9, \u6216\u8005\u53d1\u90ae\u4ef6\u5230pr@segmentfault.com"]}
};
var ddosMode = false;
(function (currentUrl) {
if (typeof URL != 'undefined') {
// 测试环境
if ('https://segmentfault.com' === '//localhost:3000') return
var baseUrl = new URL('https://segmentfault.com');
if (baseUrl.protocol != currentUrl.protocol
|| baseUrl.host != currentUrl.host) {
window.location.href = baseUrl.protocol + '//' + baseUrl.host
+ currentUrl.pathname + currentUrl.search + currentUrl.hash;
}
}
})(window.location);
</script>
我们需要的是第一个函数,在get_token()中用正则表达式提取出来。
def get_token(st):
h = re.match('[\s\S]*\(function \(w\) \{[\s\S]+? \}\)\(window\);', st).group()
with PyV8.JSContext() as ctxt:
ctxt.eval("""window={};\n""" + h)
vars = ctxt.locals
token_var = vars.window.SF.token
print token_var
return token_var
到此,所需要的都取得了,接下来就用sesssion.post把参数,cookie,请求头带上,post的url加上查询字符串,就可以成功模拟登陆了。
如有错误请指正~谢谢~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。