參考資料: http://www.csuldw.com/2016/11/10/2016-11-10-simulate-sina-login/ http://blog.csdn.net/fly_leopard/article/details/51148904 http://www.tuicool.com/articles/uIJzYff http://blog.csdn.net/u010029983/article/details/46364113 等
模擬新浪微博登陸是抓取新浪數據的基礎,網上的參考資料大多介紹的是用Python開發,有一篇使用php模擬登陸的資料仍是在phpcms中實現的,也沒有太深刻分析。 javascript
PS:網上資料來源比較亂,不知道phpcms實現模擬微博登陸的原做是否是csdn的t0mCl0nes,本篇介紹php模擬登陸的核心借鑑的就是這篇文章。如下說起這篇文章以phpcms方案指代。php
使用PHP模擬登陸新浪微博和Python仍是有些區別的,其中也存在一些問題,在這裏我就簡單分析一下PHP模擬新浪微博登陸的過程和存在的問題。java
項目地址:
https://github.com/daweilang/...laravel
標題名「基於laravel框架」,由於整個獲取新浪微博數據的系統是用的lavarel框架搭建的,使用了lavarel隊列、命令等等工具。其實模擬新浪微博登陸這部分徹底能夠用簡單php程序頁面實現,但願我下面的分析可以幫助感興趣的朋友實現本身的模擬登陸程序。
PS:App\Http\Controllers\Admin\AuthorizeController
控制器是本文的主程序,如下說起的代碼都在github該程序中。git
這裏所介紹的模擬新浪微博登陸,具體是指經過新浪通行證模擬登陸。新浪通行證是新浪的統一登陸模式,新浪網(sina.com.cn)和微博(weibo.com)是兩個不一樣的頂級域,正是經過新浪通行證,微博實現了跨域登陸。對於跨域登陸瞭解很少,不過新浪網使用的這種方式技術上應該是很深刻的。github
具體登陸參數的抓包分析請參考上面和網上的一些文章,其中固定參數能夠參考個人代碼「config/weibo.php
」的curl數組。算法
這裏主要對 預登陸和預登陸返回的參數 結合PHP程序進一步說明。跨域
當用戶輸入用戶名而且焦點離開輸入框後,登陸頁面會向 http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=%s&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.18)&_=%s
發送一次GET請求,其中用戶名是通過base64_encode加密的,最後是個毫秒級的時間戳,其餘參數能夠固定。數組
該請求返回了一些參數,網上資料已經介紹了後面主要用到了 "servertime"、」nonce"和"rsakv" 這三個參數,不過其實 「showpin」和「pcid」 這兩個參數也很重要,showpin爲1的時候表明須要填寫驗證碼,而驗證碼的生成須要「pcid」這個參數。cookie
phpcms方案中將請求返回的這些參數儲存到cookie中,個人代碼是儲存到文件中,參數的取得和儲存代碼參見GetWeiboCookie
類的getPreUrl()
方法。
網上的文章都已經介紹了微博密碼加密原理,使用RSA2算法,「首先建立一個 rsa 公鑰,公鑰的兩個參數都是固定值,第一個參數是登陸過程當中 prelogin.php 中的 pubkey ,第二個參數是加密的 js 文件中指定的」10001」(這兩個值須要先從16進制轉換成10進制,把「10001」轉成十進制爲「65537」)。最後再加入 servertime 和 nonce 進行進一步加密。」
新浪通行證的流程是,在用戶填寫完用戶名和密碼提交後,請求「https://login.sina.com.cn/js/sso/ssologin.js
」 頁面,這個js頁面裏就是上面的加密算法,使用js將密碼加密。
這個流程使用Python模擬的代碼是這樣的:
RSAKey = rsa.PublicKey(rsaPubkey, 65537) #建立公鑰 #根據js拼接方式構造明文 codeStr = str(servertime) + '\t' + str(nonce) + '\n' + str(password) pwd = rsa.encrypt(codeStr, RSAKey) #使用rsa進行加密
短短三行代碼,只須要安裝rsa包。。。
百度了很久,沒有找到php實現生成rsa公鑰方法。
phpcms方案實現了一種解決方法,也就是按照新浪通行證的流程來實現,用ssologin的js方法來加密。phpcms方案對sso加密算法進行了一次封裝,csdn博客上有該段js代碼。個人js水平不高,徹底借鑑了這段代碼,在此基礎上將加密算法提取到一個js文件中。
<script type='text/javascript' src='/js/prelogin.js'></script> <script type="text/javascript"> function getpass(pwd,servicetime,nonce,rsaPubkey){ var RSAKey=new sinaSSOEncoder.RSAKey(); RSAKey.setPublic(rsaPubkey,'10001'); var password=RSAKey.encrypt([servicetime,nonce].join('\\t')+'\\n'+pwd); return password; } </script>
這種作法有個很大的缺點,須要一個單獨的頁面來生成加密後的密碼,而且將密碼傳給最後的提交頁面,也就是說頁面須要屢次跳轉。
var encrpt = getpass('{$preParam['sp']}', '{$preParam['servertime']}', '{$preParam['nonce']}', '{$preParam['pubkey']}' ); // document.write(encrpt); window.location.href='/admin/authorize/browserLogin/?sp='+encrpt;
最後將加密的密碼傳遞給最後的提交頁,見getRsaPwd()
方法。
我是在最終提交頁browserLogin中將以前儲存在文件中的各類參數提取與加密後的密碼組合,最後post給新浪通行證登陸頁登陸。
這裏還有一點是以前介紹過的,須要填寫驗證碼狀況,若是預登陸返回的showpin參數爲1,須要得到驗證碼圖片,填寫驗證碼登陸。驗證碼圖片地址是
http://login.sina.com.cn/cgi/pin.php?r={$randInt}&s=0&p={$preParam['pcid']}
r是隨機8位數字,p是預登錄返回的pcid。若是有驗證碼就多了一次手動填寫驗證碼的流程。
具體代碼參考browserLogin()
方法。
這種方法與Python相比最大的缺點是不能自動登陸,也就是後臺登陸,Python不須要人爲觸發,有用戶名和密碼後徹底可使用程序模擬登陸,而php實現須要人爲觸發登陸。
另外,若是須要填寫驗證碼,Python也有工具能夠識別驗證碼,作到自動打碼,全程自動登陸,這點php實現起來也比較困難。
以後的curl登陸沒有什麼須要特別說明的,應該是在參數裏面設置了入口weibo,因此返回的cookie能夠直接使用到微博中,理論上這種方式能夠在新浪全站模擬登陸,不過我並無試過其餘子站。新浪只是在密碼覈驗上比較嚴格,對於模擬登陸的限制並很少。
綜上,雖然使用PHP實現了模擬新浪微博登陸,但比之Python仍是很不方便的,畢竟Python作爬蟲的有不少工具。不過在模擬登陸微博的基礎上獲取微博數據過程當中,使用lavarel這種框架實現了不少腳本功能,大大提升了抓取數據效率,這也是我使用lavarel開發這個小項目的緣由。
https://github.com/daweilang/...
已經實現模擬新浪微博登陸的功能,以後再也不更新。
後續的新浪微博數據抓取分析,請關注 https://github.com/daweilang/...這個項目還在調整階段,還有不少缺陷須要完善,待功能成熟後,我也會圍繞項目的設計目標,介紹一下實現方案。