本文已獲原作者授權發布。
原文連結:http://www.jianshu.com/p/816594c83c74
文 | resolvewang
最近由於需要一直在研究微博的爬蟲,第一步便是模擬登陸,從開始摸索到走通模擬登陸這條路其實還是挺艱難的,需要一定的經驗,為了讓朋友們以後少走點彎路,這裡我把我的分析過程和代碼都附上來。
首先,我們先用正常的帳號登陸,具體看會有些什麼請求。這裡我用的是 Http Analyzer 抓包(Filders 也是一個不錯的選擇)。下面是正常登陸流程的截圖:
圖 1
接下來我會詳細說明各個過程。
第一步:預登陸。
現在微博、空間等大型網站在輸入用戶名後基本都會做編碼或者加密處理,這裡在用戶名輸入框輸入我的帳號,通過抓包工具可以看到伺服器會返回一段字符串:
圖 2
這一步就是預登陸過程,同學們可以自己試試。登陸的時候我們需要用到其中的 servertime、nonce、pubkey 等欄位。當然這個不是我自己猜想的,後面的步驟會做說明。
還有一點,就是預登陸的 url:
http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.18)&_=1461819359582
這裡 su 的值是自己用戶名經過 base64 編碼的值。但可能你們會問我是如何知道的呢,待會兒我會講到。經過實測,如果我們這裡不給 su 傳參數,其實也是可以的。為了最真實的模擬用戶登錄,我們最好還是帶上它的值。
請看圖一的第一條 js 請求http://i.sso.sina.com.cn/js/ssologin.js,同學們可以點進去看,這個就是前面提到的加密用戶名和密碼等一系列的加密文件了,如果有同學非要問我是怎麼找到這個加密文件的,我也只有說:反覆抓包,從在瀏覽器輸入 weibo.com 過後就找 js 文件請求路徑,然後再用代碼格式化工具打開,挨著一個一個看,在代碼中搜關鍵字,比如這裡我們可以搜"nonce"、"servertime"等,就能找到加密文件了。
打開加密文件我們可以看到加密用戶名的代碼,在加密 js 文件中搜索'username',可以看到有一行代碼為:
_username = sinaSSOEncoder.base64.encode(urlencode(username)); _現在我們可以直接查找 encode 方法(代碼太多就不貼上來了),即可查找到對應方法了,為了驗證我們的猜想,我們可以在 webstorm 中 copy 這個 encode 函數帶上自己的用戶名運行,返回的結果就是 su 的值,這個值在之後進行 post 提交的時候也會用到。如果對加密有一定經驗的同學可能一眼就會看出這個是 base64 編碼,python 中有個 base64 模塊可以幹這個事情。我們再回到圖一,http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)這個地址就是進行 post 提交數據的地址,下面是我自己提交的數據:
圖三
這裡我們需要自己構造 su(加密後的用戶名),sp(加密後的密碼),servertime,nonce,rsakv 等數據,其它數據都不用變。有同學問我為哈其它數據不用變?你自己可以多登陸幾次,看變化的值,那麼那些值就是需要構造的值,其它值就直接拿過來用就行了。這裡的 su,servertime,nonce,rsakv 都已經拿到了,所以當前需要的就只是 sp 的值了。我們還是按照原來的方法在 js 文件中查找"sp",可以找到requests.sp=password這段代碼,所以我們就只需要看 password 怎麼構造的了。通過查找可以看到關鍵加密代碼:
password = RSAKey.encrypt([me.servertime,me.nonce].join("t") "n" password)
這一段代碼便是加密密碼的代碼,有經驗的同學一看就知道是用的 RSA 加密,python 中也有相應的 rsa 加密庫可用。但是我們假設大家都沒看出來或者不知道 python 中有 rsa 這個第三方庫。這時候就要給大家介紹一些我的經驗了,我現在已經知道的有三種模擬登陸方案:a) 最簡單暴力,效率也是最高的,直接把 js 源碼轉化為相應的 python 代碼,模擬加密流程進行加密 b) 使用 selenium phantomjs/firefox 的方案直接模擬人的操作填寫表單提交數據進行模擬登陸,這種方式最為簡單,效率稍微低一些。如果有同學對這種簡單暴力的方式感興趣,可以到我的 github 上查看一下源碼 c) 比較折中的方案,通過 pyv8/pyexecjs 等渲染 js 代碼進行執行,本文主要就是講的這種方式。第一種方式如果是遇到微博調整了登陸加密算法,就必須改加密代碼,第二種方式和第三種方式不存在這個問題。
由於我用的是 Python3,並不支持 PyV8,所以我選了和它類似的 PyexecJS,這個也可以直接執行 js 代碼。我也不是很熟悉 Javascript 代碼,所以我直接定義了一個函數處理加密密碼,並沒對其加密原始碼修改太多:
function get_pass(mypass,nonce,servertime,rsakey){
varRSAKey = newsinaSSOEncoder.RSAKey();
RSAKey.setPublic(rsakey,"10001");
password= RSAKey.encrypt([servertime,nonce].join("t") "n" mypass)
return password
}
這個函數中的東西其實就是 copy 的加密文件的加密過程代碼。為了試驗,我直接使用之前自己登陸抓到的 nonce、servertime、rsakey 等數據,在 webstorm 中調用這個函數,但是報錯了,提示"navigator is undefined",webstorm 使用的 nodejs 的運行時環境,而 navigator 為瀏覽器的某個屬性,所以運行會出問題。於是我就是用 phantomjs 來作為運行時環境.考慮到有同學不知道 phantomjs 怎麼使用,這裡我簡要說一下吧。使用 windows 的同學先要去 phantomjs 官網下載它的可執行文件,然後設置環境變量。在命令行輸入"phantomjs some.js"即可執行 some.js 文件,其實就和在命令行執行 python 或者 java 文件一樣,如果不清楚的可以百度執行命令行執行 python 的方法,仿照著來就可以了,再不清楚就問我。使用 ubuntu 的同學可以直接用 sudo apt-get install phantomjs,就可以安裝使用了。我直接把加密的 js 文件使用 phantomjs 運行,果然好著呢。原因是因為 phantomjs 其實就是一款無 ui 的瀏覽器,自然支持 navigator、window 等屬性。而 pyexecjs 支持使用 phantomjs 作為運行時環境,具體用法 pyexecjs 的 git 主頁有,我也在代碼中有所體現。
with open('G:/javascript/sinajs.js','r') as f:
source = f.read()
phantom = execjs.get('PhantomJS')
getpass = phantom.compile(source)
mypass = getpass.call('getpass',mypass,nonce,servertime,pubkey)
這段代碼就可以得到加密過後的密碼了。
之後,便可以進行 post 提交,提交地址可以從抓包工具看到:http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)。
根據經驗,到這裡過程基本就完了。但是微博有點坑啊,這裡還需要有一步,就是圖一所示的類似http://passport.weibo.com/wbsso/login?ssosavestate=1493447127&url=http://weibo.com/ajaxlogin.php?framelogin=1&callback;=parent.sinaSSOController.feedBackUrlCallBack&ticket=ST-NTc3NTg1MjMwNw==-1461911127-gz-1DE185DF04280D7E96BDCD14D9D8E235&retcode=0,這一步會將請求重定向,返回當前帳號的登陸信息,如下圖:
圖三
那麼問題來了,怎麼獲取上面的請求地址呢。分析上面地址,有 ticket 欄位,這個應該是讓你登陸的憑據,所以這個地址應該是服務端返回的,如果不是,起碼 ticket 是服務端返回的,於是我們又使用抓包工具查看在請求這段 url 之前返回的信息,發現有和上述 url 吻合的信息:
圖四
這段代碼是使用 post 後回復的內容,所以可以直接從中提取出我們需要的 url。然後再使用 get 方式請求上述的 url,它會經歷一次重定向,直接返回登陸信息。這個時候,就代表成功登陸了。
PS:授人以魚不如授人以漁,這是我一直秉承的信念。可能有的老手覺得我寫得很囉嗦,但其實很多新手可能都不知道這些細節,所以我把我在分析新浪微博模擬登陸的過程全寫了出來。另外,除了這種方式,本文提到的另外兩種方式也有實現。最暴力的方式需要使用 rsa 這個第三方庫,具體我在代碼上有詳細注釋,還有一種是使用 selenium phantomjs 這種方式,我也在代碼中關鍵地方有注釋.
Talk is cheap,show me the code!
最後奉上本文的所有方式的模擬登陸代碼(如果覺得喜歡或者看了對你有幫助,不妨在 github 上給個 star,也歡迎 fork)
代碼連結,歡迎 fork 和 star:https://github.com/w1796246076/smart_login/
題圖:pexels,CC0 授權。
點擊閱讀原文,查看更多 Python 教程和資源。