1. 前言
- 本篇文章,旨在破解有道翻譯 http://fanyi.youdao.com/ 部分請求參數的 JS 加密方法,從而構造請求訪問站點;
2. 分析
- 輸入字符 “蘋果”,得到翻譯的結果;
- 右鍵查看網頁源碼,ctrl + F 彈出搜索框,在網頁源碼中搜索 蘋果,發現網頁源碼中并沒有 蘋果;
- 搜索 apple 同樣也不能找到;
- 這說明 蘋果、apple 這些輸入輸出的字符串,并不是在網頁上的靜態內容,而是動態加載的;
image.png
3. 抓包
- 右鍵檢查網頁,點擊 Network,調出網頁抓包工具;
- 在網頁上重新點擊 翻譯 按鈕,在抓到的數據包中找到含有輸出信息的包;
image.png
- 在網頁輸入框重新輸入 西瓜 并再次抓包,分析數據包的參數,發現參數有如下規律:
-- i ------------------------------------------------------------------------ 輸入的字符串,例如:西瓜、蘋果;
-- from: AUTO---------------------------------------------------------- 不變參數;
-- to: AUTO------------------------------------------------------------- 不變參數;
-- smartresult: dict --------------------------------------------------- 不變參數;
-- client: fanyideskweb --------------------------------------------- 不變參數;
-- salt: 15929685900475 ------------------------------------------ 未知參數;
-- sign: e8aeb3b7429d2198356378746cf291d1 ------------ 未知參數;
-- ts: 1592968590047 ---------------------------------------------- 未知參數;
-- bv: 02a6ad4308a3443b3732d855273259bf -------------- 未知參數,多次抓包發現此參數值固定,換瀏覽器后變化;
-- doctype: json ------------------------------------------------------ 不變參數;
-- version: 2.1 -------------------------------------------------------- 不變參數;
-- keyfrom: fanyi.web ---------------------------------------------- 不變參數;
-- action: FY_BY_CLICKBUTTION ---------------------------- 不變參數;
image.png
4. 搜索參數,尋找代碼
- ctrl + shift + F 打開全局搜索,輸入 sign 搜索,按下圖所示步驟尋找代碼;
image.png
- 說明:
-- 在 4、5 兩步搜索的過程中,需要結合上下文仔細分析代碼內容;
-- 很多情況下,目標代碼是以 代碼塊 的形式,集中在一起 出現的;
-- 一個文件中會有多處代碼有相同關鍵字,對于這類相同的關鍵字,可以多次搜索不同的關鍵字,對比分析不同的代碼塊中,關鍵字的區別,推測可能性最大的代碼塊;
5. 下斷調試
- 在目標代碼位置下斷點;
- 在網頁重新點擊 翻譯 按鈕;
-- 注意:此處動作不可以用 刷新 替代,很多時候 刷新 并不能完成請求的再次發送; - 參考下圖,在斷點分析代碼,
image.png
- 通過分析,得到下面的結果:
-- i,即代碼中的 e,表示輸入的字符串;
-- bv,即代碼中的 t,是對瀏覽器版本字符串(注意:需要剔除 Mozilla/ 字符串!!!)的 md5 處理;
-- ts,即代碼中的 r,是 13 位時間戳;
-- salt,即代碼中的 i,是 r 值尾部加上一個 0~9 隨機整數;
-- sign,是對 "fanyideskweb" + e + i + "mmbP%A-r6U3Nw(n]BjuEU" 字符串的 md5 處理;
6. 代碼實現
import requests
import hashlib
import time
import random
def youdao(keyword):
url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Content-Length": "251",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "OUTFOX_SEARCH_USER_ID=794950846@10.169.0.82; JSESSIONID=aaatjBaH10pyw8bRkOHlx; OUTFOX_SEARCH_USER_ID_NCOO=947970453.2625253; ___rl__test__cookies=1592932488300",
"Host": "fanyi.youdao.com",
"Origin": "http://fanyi.youdao.com",
"Referer": "http://fanyi.youdao.com/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
bv = hashlib.md5('5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'.encode("utf-8")).hexdigest()
print(bv)
ts = str(int(round(time.time() * 1000)))
salt = ts + str(random.randint(0, 9))
sign = hashlib.md5("fanyideskweb{}{}mmbP%A-r6U3Nw(n]BjuEU".format(keyword, salt).encode("utf-8")).hexdigest()
form_data = {
"i": keyword,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"ts": ts,
"bv": bv,
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTlME"
}
print(form_data)
response = requests.post(url=url, headers=headers, data=form_data).text
return response
def main():
keyword = '西瓜'
response = youdao(keyword=keyword)
print(response)
if __name__ == '__main__':
main()