此次想試一試模擬登錄,覺得應該會很順利,可是遇到了各類問題,因此記錄總結一下。
參考文章:請點擊這裏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加上查詢字符串,就能夠成功模擬登錄了。
若有錯誤請指正~謝謝~