此次想试一试模拟登录,觉得应该会很顺利,可是遇到了各类问题,因此记录总结一下。
参考文章:请点击这里html
参考文章使用的node.js
,感受没有python
用起来方便。node
python2.7
Chrome浏览器
requests
PyV8
lxml
首先进入segmentfault的登录页面。
能够随便输入错误密码点击登录,使用Chrome
查看请求发到了哪一个url
。
另外看post的参数,这里有三个:remember
, username
和 password
。
而后能够顺便按照Requests Headers
把请求头设置好(照抄到代码里)。python
requests
库的session
对象可以帮咱们跨请求保持某些参数,也会在同一个session
实例发出的全部请求之间保持cookies
。
使用:正则表达式
# 建立一个session对象 session = requests.session() # 用session对象发出get请求 response = session.get('https://segmentfault.com/user/login') # 获取cookie cookies = response.cookies
设置了请求头,cookie也拿到了,看看post的urlsegmentfault
发现这段url后面是带了查询字符串的,每次发请求都会变化。
只有明白它是如何生成的才能取得咱们要post的url,这里我卡了很久,去寻找答案,才找到了参考文章,这里面提供了思路获取js中生成的token。api
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
cookie
分析:回到login
文件发现token
是html
中的script
标签中一个函数生成的,而html可使用requests.get
取得,而后能够经过python
的re
模块用正则表达式提取出所须要的函数,这时还须要python
中的PyV8
模块来执行js函数。
执行:分析html的DOM节点,发现函数的位置,使用xpath取得那个script标签session
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目前是这样的:python2.7
<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加上查询字符串,就能够成功模拟登录了。
若有错误请指正~谢谢~