??免責(zé)聲明:本文章涉及到的代碼僅供學(xué)習(xí)交流使用斩芭,不得用于任何商業(yè)用途,數(shù)據(jù)來源于互聯(lián)網(wǎng)公開內(nèi)容,沒有獲取任何私有和非公開權(quán)限的信息(個人信息等)赘阀。由此引發(fā)的任何法律糾紛與本人無關(guān)。禁止將本文技術(shù)或者本文所關(guān)聯(lián)的Github項(xiàng)目源碼用于任何除學(xué)習(xí)外的目的脑奠。
以影視綜Rank為例基公,分析如何提取某樂指數(shù)網(wǎng)站數(shù)據(jù)。
分析頁面
打開頁面后有劇集榜宋欺、電影榜轰豆、綜藝榜三個頁簽胰伍,每個面簽的加密邏輯相同,這里使用劇集榜做為樣例酸休。
打開開發(fā)者工具骂租,刷新頁面,可以在Fetch/XHR里看到如圖請求斑司。
[圖片上傳失敗...(image-702f69-1707105865422)]
這個請求的頭部和載荷里分別有uuid和sign兩個參數(shù)需要模擬渗饮。
[圖片上傳失敗...(image-269624-1707105865422)]
[圖片上傳失敗...(image-688f94-1707105865422)]
查看響應(yīng)數(shù)據(jù),可以發(fā)現(xiàn)返回的是經(jīng)過加密后的密文宿刮。
[圖片上傳失敗...(image-eaa82d-1707105865422)]
劇集榜參數(shù)特性:
[圖片上傳失敗...(image-83bcdf-1707105865422)]
電影榜參數(shù)特征:
[圖片上傳失敗...(image-f3630-1707105865422)]
綜藝榜參數(shù)特征:
[圖片上傳失敗...(image-d12794-1707105865422)]
由此可以看出互站,“影視綜Rank”里,三個頁簽接口分別對應(yīng)“無參數(shù)”僵缺、“movielist”和“varietylist”胡桃,并且都設(shè)置了相對固定的sign值,理論上可以直接使用磕潮,不用進(jìn)一步分析sign值生成JS翠胰。不過出于興趣,還是看看這個是怎么生成的揉抵,:P
[圖片上傳失敗...(image-f94bfb-1707105865422)]
解密
Sign生成
通過搜索亡容,初步定位到上圖t.sign是參數(shù)生成的地方,在控制臺中確認(rèn)后冤今,確定目標(biāo)就是_t.getSign(t).toString()
阳准。
[圖片上傳失敗...(image-1e387f-1707105865422)]
其中t就是channel參數(shù)析恋。
[圖片上傳失敗...(image-81c56-1707105865422)]
看加密后的結(jié)果是長度32的16進(jìn)制字符串,符合MD5特征,但是用標(biāo)準(zhǔn)MD5算法測試相同的參數(shù)沫勿,發(fā)現(xiàn)生成的字符并不一樣共缕。所以這里的算法或者輸入?yún)?shù)并不是簡單的處理沪斟,需要進(jìn)一步分析JS實(shí)現(xiàn)士飒。
[圖片上傳失敗...(image-d5d9ba-1707105865422)]
通過查看代碼,發(fā)現(xiàn)參數(shù)傳入后讲岁,進(jìn)行了字符串拼接我擂,導(dǎo)致實(shí)際進(jìn)行MD5計算的參數(shù)并不一樣』貉蓿可以看出實(shí)際加密的字符串是“channel_movielist_iIndex”這三個字符串的拼接校摩。這里對Vie()方法測試后,是標(biāo)準(zhǔn)的MD5分組加密結(jié)果阶淘,調(diào)用toString()方法后衙吩,得到的值和標(biāo)準(zhǔn)MD5算法一致。所以這里用的就是標(biāo)準(zhǔn)MD5算法溪窒。
到此坤塞,便可以將網(wǎng)頁中的JS代碼復(fù)制過來冯勉,在本地封裝成JS腳本自己生成sing參數(shù)了。JS 代碼如下:
const CryptoJS = require("crypto-js")
function getSign(e) {
delete e.sign;
for (var t = [], n = Object.keys(e).sort(), r = 0; r < n.length; r++) {
var i = n[r]
, a = e[i];
t.push(i),
t.push(a)
} t.push("iIndex");
var s = t.join("_")
, c = CryptoJS.MD5(s);
return c
}
調(diào)用的Python代碼如下:
import execjs
def get_sign(channel):
with open("Sign.js", "r", encoding="utf-8") as f:
js_file = f.read()
js = execjs.compile(js_file)
return js.call('getSign', channel)
if __name__ == '__main__':
channel = {
"channel": "movielist"
}
print(get_sign(channel))
輸出結(jié)果為5f3cce6a40c09a221b21104cc98436a3
摹芙,與之前抓包的結(jié)果一致灼狰。
返回值解密
對于返回值加密的搜索方法:
- 搜索
json.parse(
關(guān)鍵字 - 搜索
decrypt
關(guān)鍵字 - 搜索攔截器
- 下斷點(diǎn)到類似
.then
的回調(diào)方法
這里先使用搜索json.parse
,搜索結(jié)果很多浮禾,需要縮小范圍伏嗜。
[圖片上傳失敗...(image-364273-1707105865422)]
查看啟動器尋找線索,但并沒有能“望文知義”的地方伐厌,只能確定調(diào)用的內(nèi)容都在index.28827ebe.js
文件中,那么搜索結(jié)果里可以先把其它文件放在一邊裸影,從這個文件入手挣轨。
[圖片上傳失敗...(image-db48fc-1707105865422)]
對28827文件里的搜索結(jié)果中,可能性大的地方進(jìn)行斷點(diǎn)確認(rèn)后轩猩,初步確定了下圖兩個位置入口卷扮。
可能位置1:經(jīng)過查看輸入和輸出,發(fā)現(xiàn)并沒有解密活動均践,所以不是該位置晤锹。
[圖片上傳失敗...(image-fce49d-1707105865422)]
可能位置2:查看輸入和輸出,由密文轉(zhuǎn)換成了明文彤委,所以該方法是目標(biāo)位置鞭铆。
[圖片上傳失敗...(image-d112e4-1707105865422)]
這里也可以使用攔截器的方法進(jìn)行定位。搜索攔截器關(guān)鍵字interceptors
焦影,找到28827文件相關(guān)的位置车遂,查看有關(guān)response的條目。
[圖片上傳失敗...(image-249e49-1707105865422)]
然后在該文件中搜索interceptors.response
關(guān)鍵字斯辰,發(fā)現(xiàn)有3位可疑位置舶担,分別打上斷點(diǎn),刷新頁面后彬呻,在每個斷點(diǎn)查看對應(yīng)的輸入輸出參數(shù)衣陶,定位到如下位置有解密功能,于是確定這里為解密方法闸氮。
[圖片上傳失敗...(image-b7f6b2-1707105865422)]
現(xiàn)在開始分析_t.dataFilter(e.data)
代碼剪况,明確解密算法。跳轉(zhuǎn)到該方法實(shí)現(xiàn)位置湖苞,發(fā)現(xiàn)就是之前搜索到的“可能位置2“拯欧。
根據(jù)方法和參數(shù)信息,可以初步判斷Zie
是對稱加密算法财骨,因?yàn)樗?code>iv參數(shù)镐作。
而加密算法里有CryptoJS.enc.Utf8
同時有parse()
和stringify()
方法藏姐,代入驗(yàn)證后確認(rèn),那么Zie
就是CryptoJS.AES
该贾。根據(jù)這些分析羔杨,可以將這部分代碼在本地改寫為:
var CryptoJS = require('crypto-js')
//encrypt_data為響應(yīng)中的加密數(shù)據(jù),lastFetchTime是響應(yīng)中返回的時間戳
function get_decrypt_data(encrypt_data, lastFetchTime) {
var i = CryptoJS.enc.Utf8.parse(lastFetchTime + "000")
, a = CryptoJS.enc.Utf8.parse(lastFetchTime + "000")
, s = CryptoJS.AES.decrypt(encrypt_data.toString(), i, {
iv: a
})
, l = s.toString(CryptoJS.enc.Utf8);
return JSON.parse(l)
}
通過在Python中調(diào)用這個腳本即可完成解碼杨蛋。
這種方法比較依賴經(jīng)驗(yàn)判斷兜材,還有另外一種不需要經(jīng)驗(yàn)的簡單粗暴方法:
就是查看這個js文件后,可以發(fā)現(xiàn)dataFilter()
方法是獨(dú)立賦給_t
這個對象的逞力,那么就可以直接調(diào)用曙寡。首先直接把index_28827ebe.js
文件全部復(fù)制到本地,去掉不相關(guān)或者報錯的代碼后寇荧,直接把_t.dataFilter()方法封裝成Python中可調(diào)用的方法使用即可举庶。這種方法因?yàn)檫@個js文件代碼有幾萬行,所以會導(dǎo)致電腦突然變慢揩抡,酌情使用:P户侥。
[圖片上傳失敗...(image-33d694-1707105865422)]
獲得了解密方法,就可以通過爬蟲自動抓取數(shù)據(jù)信息了峦嗤。