上一篇文章小試牛刀:使用Python模擬登錄知乎介紹了如何模擬知乎登錄,雖然用到了驗證碼信息,但請求的參數都是原封不動的傳遞,剛開始接觸的時候,覺得難度適中,回頭再看的時候,反而感覺挺容易的。在這篇文章,將繼續介紹模擬登錄。與之前不一樣的是,這次選擇的對象是新浪微博,難度稍微提升了點,好在以往的許多碼友們都留有許多經驗貼,經過幾番斟酌,微博的模擬登錄算是實現了。這兩天還在研究如何高性能地爬取微博數據,業余之際乘着還有點記憶,索性將先前的小實驗加工成文,算是一份小結吧。下面來看看整個實驗過程。
開發工具
一如既往,筆者使用的還是之前的工具,如下:
- Windows 7 + Python 2.75
- Chrome + Fiddler
微博登錄請求過程分析
新浪微博的登錄有多個URL鏈接,筆者在實驗的時候試了兩個,這兩個都是新浪通行證登錄頁面,都是不需要驗證碼的。一個是 【http://login.sina.com.cn】,另一個是 【https://login.sina.com.cn/signup/signin.php?entry=sso】。兩個URL雖然很大部分相同,登錄過程中僅僅是傳遞參數不一樣。第一個URL傳遞的過程對“password”進行了加密,而第二個沒有加密,所以如果使用第二個URL進行模擬登錄,就簡單多了。在這里,筆者決定選擇使用第一種方式進行分析,下面來看詳細過程。
請求登錄過程可歸納為三部分
- 請求登錄login.php頁面前的參數預獲取
- 請求登錄login.php頁面時的參數分析
- 提交POST請求時的參數構造
Step 1:GET方式請求prelogin.php頁面
在模擬登錄之前,先觀察瀏覽器登錄過程中Fiddler抓到的包,在/sso/login.php
打開之前會先使用“GET”方式請求“/sso/prelogin.php”,請求的URL為:【https://login.sina.com.cn/sso/prelogin.php?entry=account&callback=sinaSSOController.preloginCallBack&su=bGl1ZGl3ZWkxOCU0MHNpbmEuY29t&rsakt=mod&client=ssologin.js(v1.4.15)
】,可以看看下面這張圖:
在Fiddler中,可以點擊“Preview”查看具體詳情,也可以直接將Request URL復制到瀏覽器上查看,效果圖如下:
可以看出,這是一個json數據,並且攜帶了幾個參數,我們關心的有以下四個:
- servertime
- nonce
- pubkey
- rsakv
說明一下,之所以認為這幾個參數比較重要,那是因為后面對“password”的加密需要用到,對其他參數沒有提及的原因是在提交POST時其它的參數並沒有用到。好了,為了進行進一步探索,我們從Fiddler的結果可以看出,接下來到了“/sso/login.php”。
Step 2:POST方式請求login.php頁面
從這里開始,就進行“login.php”頁面的請求分析了(詳細的Request URL:【https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)
】,后面的時間戳可省略)。點擊查看詳情,結果圖如下:
可以發現/sso/login.php
頁面有如下參數(From Data):
cdult: 3
domain: sina.com.cn
encoding: UTF-8
entry: account
from:
gateway: 1
nonce: AFE3O9
pagerefer: http://login.sina.com.cn/sso/logout.php
prelt: 41
pwencode: rsa2
returntype: TEXT
rsakv: 1330428213
savestate: 30
servertime: 1478568922
service: sso
sp: password
sr: 1366*768
su: username
useticket: 0
vsnf: 1
到了這里,我們大概可以知道我們需要哪些參數了。在From Data 參數列表中,需要我們指定的參數有下面幾個:
- servertime
- nonce
- rsakv
- sp:加密后的密碼
- su:加密后的用戶名
對於參數“nonce”、“servertime”、“rsakv”,都可以從第一步中的“prelogin.php” 中直接獲取,而“sp”和“su”則是經過加密后的字符串值,至於具體的加密規則,我們下面通過查看源碼分析得出。
Step 3:探索加密規則
首先看看請求“/sso/prelogin.php”的具體情況,看到“client”為“ssologin.js”,見下圖:
然后我們到登錄頁面https://login.sina.com.cn中查看源碼【view-source:https://login.sina.com.cn/】並搜索“ssllogin.js”,接着點擊進入ssologin.js文件,這時我們可在文件中搜索“username”字符串,找到與“username”相應的加密部分(需仔細查看+揣測),接着搜索“password”,找到“password”的加密部分,最后分析出“username”和“password”的加密規則。加密部分的代碼如下圖:
加密用戶名的代碼:
1 |
request.su = sinaSSOEncoder.base64.encode(urlencode(username)); |
加密密碼的代碼:
1 |
if ((me.loginType & rsa) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.RSAKey) { |
微博對於“username”的加密規則比較單一,使用的是“Base64”加密算法,而對“password”的加密規則比較復雜,雖然使用的是“RSA2”(python中需要使用pip install rsa
安裝rsa模塊),但加密的邏輯比較多。根據上面的代碼,可以看出“password”加密是這樣的一個過程:首先創建一個“rsa”公鑰,公鑰的兩個參數都是固定值,第一個參數是登錄過程中“prelogin.php”中的“pubkey”,第二個參數是加密的“js”文件中指定的“10001”(這兩個值需要先從16進制轉換成10進制,把“10001”轉成十進制為“65537”)。最后再加入“servertime”和“nonce”進行進一步加密。
經過上面的分析之后,發起“POST”請求時的“post_data”基本上已經全部可以得到了,接下來就跟模擬登錄其它網站類似了,可以使用“request”,也可以使用“urllib2”。下面來看詳細代碼部分。
源碼實現
Github源碼鏈接:https://github.com/csuldw/WSpider/tree/master/SinaLogin,源碼包括下列文件:
- dataEncode.py:用於對提交POST請求的數據進行編碼處理
- Logger.py:用於打印log
- SinaSpider.py:用於爬取sina微博數據的文件(主文件)
為了方便擴展,筆者將代碼進行了封裝,所以看起來代碼量比較多,不過個人覺得可讀性還是比較良好,算是湊合吧。
1 |
# -*- coding: utf-8 -*- |
1 |
# -*- coding: utf-8 -*- |
1 |
# -*- coding: utf-8 -*- |