Python爬蟲計算sign參數

在構造爬蟲請求時,通過瀏覽器抓包發現請求參數中帶了一個sign參數:


抓包

使用requests包構造爬蟲請求,發現如果缺少這個sign字段或者sign計算的不正確,則只能得到“invalid signature”的服務端返回結果,無法得到正確的結果。因此還是只能研究一下sign是如何計算出來的。

通過觀察sign的字符串大致能夠猜到,是用了類似于md5的一種加密計算方式,加密用到的字段可能包括發送的messages,以及發送的“time”時間戳字段。之后,在服務端使用相同加密方式計算哈希值,如果結果一致才能正確返回結果,不一致則會返回錯誤。

要計算哈希值,肯定這段函數是放在js里的,所以我們在開發者工具中進入到“調試器”,然后全局搜索我們抓包的API路徑:


search for api path

這樣就能定位到發送請求的那一段js代碼,而這段代碼中肯定就包含請求中的“sign”字段是從哪個變量取的,之后我們就可以看到“sign”字段的變量是如何被計算出來的。


post params

為了能夠實現跳轉函數定義,我們可以把整個js文件拷貝到vscode中,然后格式化代碼,這樣讀起來更容易。定位到最終計算哈希值的函數:


sign function

可以看到sign字段是由時間戳+message字段計算的一個SHA256哈希值,為了能在爬蟲代碼中調用這段函數得到sign字段,我們需要安裝一個python第三方庫,用于在python代碼中執行js函數:

pip install PyExecJS

不過,我們需要先注意到,這段js函數是異步的(async),也就是如果直接調用函數的話,你其實拿不到任何返回值,js中想要獲取異步函數的值,都是通過函數執行完成之后的回調實現的,而我們要在python代碼中執行js的話,顯然是沒法回調的。所以我們最佳的辦法是不用異步函數,想辦法尋找同步函數作為替代。

分析這段js代碼可以看到,異步的地方主要在于crypto.subtle包,所以上網一搜,有一個同步的函數也能達到同樣的效果,于是我們的js代碼就可以變為:

var crypto = require('crypto');
function sha256(content) {  
    // https://stackoverflow.com/questions/57626477/using-javascript-crypto-subtle-in-synchronous-function
    return crypto.createHash('sha256').update(content).digest('hex')
  }

function getSign(t, msg) {
    n = {}.PUBLIC_SECRET_KEY,
    a = `${t}:${msg}:${n}`;
    sign = sha256(a)
    return sign
};

之后,在python代碼中調用這段js函數,傳入時間戳和message參數,然后獲取函數返回結果:

import execjs
import time

js_sha = '''
    var crypto = require('crypto');
    function sha256(content) {
        return crypto.createHash('sha256').update(content).digest('hex')
    }
    function getSign(t, msg) {
        n = {}.PUBLIC_SECRET_KEY,
        a = `${t}:${msg}:${n}`;
        sign = sha256(a)
        return sign
    };
'''
time_now = int(time.time())
msg = "XXXX"
signature = execjs.compile(js_sha).call('getSign', time_now, msg)

之后,在requests請求的表單數據中加入計算得到的sign參數,就能得到服務端的正常返回了。

參考:https://www.bilibili.com/read/cv19971275/

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容