python爬蟲之JS逆向

2022-06-11 12:00:26

Python爬蟲之JS逆向案例

由於在爬取資料時,遇到請求頭限制屬性為動態生成,現將解決方式整理如下:

JS逆向有兩種思路:

一種是整理出js檔案在Python中直接使用execjs呼叫js檔案(可見我的另一篇文章《 python爬蟲之企某科技JS逆向》)。

一種是根據JS中的邏輯,使用Python重寫相應的方法。


本文介紹的是第二種使用Python重寫JS的方法

需求:爬取某區塊鏈網站https://www.oklink.com/zh-cn/btc/tx-list?limit=20&pageNum=1資料

遇到的問題:目標網站的資料是通過ajax請求相應的介面獲取資料,在請求頭中需要攜帶x-apiKey(根據時間動態生成的),我們需要解決的就是整理出動態生成x-apiKey的方法。

解決思路:根據關鍵字"x-apiKey」在網站的JS中找到相應的定義,然後使用python重寫方法,在請求介面時實時生成相應的x-apiKey

第一步:在瀏覽器中使用開發者工具找到相應的介面

請求地址:https://www.oklink.com/api/explorer/v1/btc/transactionsNoRestrict?t=1654916647499&limit=20&offset=0

請求型別:GET

請求頭:x-apiKey:
LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3NjYwMjc3NTg2MTAzNjk=

UntitledImage

第二步:找到x-apiKey的定義方法

t.headers.common["x-apiKey"] = n.Z.getApiKey()

UntitledImage

根據上面的程式碼中看到x-apiKey是由getApiKey這個方法返回的,通過getApiKey搜尋找到相應的定義如下:

UntitledImage

1.接下就是解析這個getApiKey方法了。

{
                    key: "getApiKey",
                    value: function() {
                        var t = (new Date).getTime()
                          , e = this.encryptApiKey();
                        return t = this.encryptTime(t),
                        this.comb(e, t)
                    }
                }

1).變數t就是獲取當前時間戳

2).變數e是呼叫encryptApiKey這個方法

3).變數t是encryptTime(t)這個方法處理後的返回

4).最後通過comb(e,t)個方法生成最終的apiKey

2.encryptTime方法

key: "encryptApiKey",
                    value: function() {
                        var t = this.API_KEY
                          , e = t.split("")
                          , r = e.splice(0, 8);
                        return e.concat(r).join("")
                    }

1).變數t是一個常數字串API_KEY,往上找到初始化值為this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"

2).變數e是將上面的t分隔成陣列

3).變數r:從變數e中刪除前8個字串,並將e的前8個元素組成的陣列賦值給r。同時變數e刪除了前8個元素

4).最終將e和r合併在一起並轉為字串

3.encryptTime方法

key: "encryptTime",
                    value: function(t) {
                        var e = (1 * t + 1111111111111).toString().split("")
                          , r = parseInt(10 * Math.random(), 10)
                          , n = parseInt(10 * Math.random(), 10)
                          , o = parseInt(10 * Math.random(), 10);
                        return e.concat([r, n, o]).join("")
                    }

1).變數e為將入參t加上1111111111111然後轉為字串,分隔為陣列

2).變數r、n、o三個是生成10以內的隨機整數

3).最後返回的是e和[r,n,o]陣列合併,轉為字串返回

 

4.comb方法

key: "comb",
                    value: function(t, e) {
                        var r = "".concat(t, "|").concat(e);
                        return window.btoa(r)
                    }

1).變數r是由入參t和e中間加上|然後拼在一起的

2).window.btoa是返回的base64加密編碼

3)comb方法最終返回的就是我們需要的x-apiKey的值了

 

5.將上面的JS邏輯轉為Python程式碼如下:

def get_api_key():
    cur_time = int(time.time() * 1000)
    api_key = 'a2c903cc-b31e-4547-9299-b6d07b7631ab'
    key_1 = api_key[0:8]
    key_2 = api_key[8:]
    encrypt_api_key = key_2 + key_1
    string = str(cur_time + 1111111111111)
    r = random.randint(0, 9)
    n = random.randint(0, 9)
    o = random.randint(0, 9)
    encrypt_time = '%s%s%s%s' % (string, r, n, o)
    new_key = encrypt_api_key + '|' + encrypt_time
    # 轉為bytes-like object
    new_key = new_key.encode('utf-8')

    # 將bytes-like object轉成字串型別
    return str(base64.b64encode(new_key), encoding='utf-8')

至此,我們就得到了動態生成的x-apiKey,接下來繼續操作吧。