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=
第二步:找到x-apiKey的定義方法
t.headers.common["x-apiKey"] = n.Z.getApiKey()
根據上面的程式碼中看到x-apiKey是由getApiKey這個方法返回的,通過getApiKey搜尋找到相應的定義如下:
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,接下來繼續操作吧。