PHP基於laravel框架獲取微博資料之一 模擬新浪微博登入

大尾狼發表於2019-02-16
參考資料:
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中實現的,也沒有太深入分析。

PS:網上資料來源比較亂,不知道phpcms實現模擬微博登入的原作是不是csdn的t0mCl0nes,本篇介紹php模擬登入的核心借鑑的就是這篇文章。以下提及這篇文章以phpcms方案指代。

使用PHP模擬登入新浪微博和Python還是有些區別的,其中也存在一些問題,在這裡我就簡單分析一下PHP模擬新浪微博登入的過程和存在的問題。

專案地址:
https://github.com/daweilang/…

標題名“基於laravel框架”,因為整個獲取新浪微博資料的系統是用的lavarel框架搭建的,使用了lavarel佇列、命令等等工具。其實模擬新浪微博登入這部分完全可以用簡單php程式頁面實現,希望我下面的分析能夠幫助感興趣的朋友實現自己的模擬登入程式。
PS:AppHttpControllersAdminAuthorizeController控制器是本文的主程式,以下提及的程式碼都在github該程式中。

這裡所介紹的模擬新浪微博登入,具體是指通過新浪通行證模擬登入。新浪通行證是新浪的統一登入模式,新浪網(sina.com.cn)和微博(weibo.com)是兩個不同的頂級域,正是通過新浪通行證,微博實現了跨域登入。對於跨域登入瞭解不多,不過新浪網使用的這種方式技術上應該是很深入的。

具體登入引數的抓包分析請參考上面和網上的一些文章,其中固定引數可以參考我的程式碼“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”這個引數。

phpcms方案中將請求返回的這些引數儲存到cookie中,我的程式碼是儲存到檔案中,引數的取得和儲存程式碼參見GetWeiboCookie類的getPreUrl()方法。

PHP模擬登入新浪微博的核心,也是與Python模擬登入最大的不同,密碼加密。

網上的文章都已經介紹了微博密碼加密原理,使用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) + `	` + str(nonce) + `
` + 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/…
這個專案還在調整階段,還有很多缺陷需要完善,待功能成熟後,我也會圍繞專案的設計目標,介紹一下實現方案。

相關文章