【js逆向爬蟲】-有道翻譯js逆向?qū)崙?zhàn)
最近在螞蟻老師群里js逆向的話題比較火熱,各位大佬都在研究,自己又對這方面比較好奇,學(xué)習(xí)了一點視頻課程,找一個簡單點的網(wǎng)站我也來練練手。
網(wǎng)頁分析

打開網(wǎng)頁,隨意輸入幾個單詞,發(fā)現(xiàn)網(wǎng)頁不是靜態(tài)加載的。不著急,我們換方式,抓包。

通過查找,我們在Payload里面發(fā)現(xiàn)了輸入的需要翻譯的信息,比如我這里的“人民”,然后在Preview里面發(fā)現(xiàn)了返回的翻譯信息,這里我沒有上傳圖片,接著繼續(xù)看Headers里面的數(shù)據(jù),通過觀察,會發(fā)現(xiàn)網(wǎng)頁是post請求,大概的思路就已經(jīng)出來了,先嘗試寫一下。
初步代碼實現(xiàn)
post請求需要攜帶的參數(shù)我這里就不再說明了,headers,cookies,data等等基本上都會添加。這里需要說明的一點,如參數(shù)補全后還報錯的話,重新抓取請求,我就是在這里卡了好久,后來換了下面的“生活”一詞。
import?requests
url?=?"https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
headers={
????"User-Agent":"Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/96.0.4664.93?Safari/537.36",
????"Cookie":?"[email protected];?JSESSIONID=aaaL9cZGnEYP5anryhK2x;?OUTFOX_SEARCH_USER_ID_NCOO=624916323.622491;?DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|;?JSESSIONID=abcbn5lLEK4FC4F7BhK2x;?___rl__test__cookies=1639138497978",
????"Referer":?"https://fanyi.youdao.com",
????"Content-Length":?"252"
????}
Payload?=?{
????"i":"生活",
????"smartresult":?"dict",
????"client":?"fanyideskweb",
????"salt":?"16391384979865",
????"sign":?"b1e30cb6bb14501ea6827a83a554dcae",
????"lts":?"1639138497986",
????"bv":?"e70edeacd2efbca394a58b9e43a6ed2a",
????"doctype":?"json",
????"version":?"2.1",
????"keyfrom":?"fanyi.web",
????"action":?"FY_BY_REALTlME"
????}
res?=?requests.post(url,?headers=headers,?data=Payload)
print(res.status_code)
print(res.text)
第一步基本上就成功了,看一下返回后的結(jié)果:

可是當我們想更換一個單詞的時候,系統(tǒng)又會報錯,比如,我這里換了太陽:

那怎么辦呢?我們開始第二步,也就是js逆向
逆向查找參數(shù)
通過對上面的代碼進行分析我們可以看出,"salt"、"sign"、"lts"、"bv"這四個參數(shù)不清楚怎么回事,那就需要打開Initiator下面的js代碼去一一查找,定位。

打開后,按ctrl+f搜索,比如我這里搜索的第一個參數(shù)“salt”,這里一共12,通過觀察找到這一個:

然后將需要的代碼復(fù)制到Console,回車運行查找規(guī)律。比如我這里salt: i,然后i = r + parseInt(10 * Math.random(), 10),r = "" + (new Date).getTime(),通過在console運行后發(fā)現(xiàn),“parseInt(10 * Math.random(), 10)”的意思是隨機生成一個0-9的隨機數(shù);(new Date).getTime()是當前的一個時間,也叫時間戳。再觀察又發(fā)現(xiàn)ts: r,bv: t,t = n.md5(navigator.appVersion),運行后得知,t就是我們在發(fā)起請求時的 "User-Agent"

那么我們開始代碼實現(xiàn):
先搞定ts
import?time
r?=?time.time()
r?=?int(r*1000)
print(r)
>>>1639141944732
可以看到ts也就是上面的r和Payload里面的“l(fā)ts”已經(jīng)搞定。
再搞定salt
先來生成parseInt(10 * Math.random(), 10)的隨機數(shù):
import?random
s?=?random.randint(0,10)
print(s)
再來實現(xiàn)i = r + parseInt(10 * Math.random(), 10):
import?time
import?random
r?=?time.time()
r?=?int(r*1000)
s?=?random.randint(0,10)
i?=?r+s
print(i)
至此,我們已經(jīng)拿到了三個參數(shù),代碼也可以改寫一下了:
import?requests
import?time
import?random
url?=?"https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
headers={
????"User-Agent":"Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/96.0.4664.93?Safari/537.36",
????"Cookie":?"[email protected];?JSESSIONID=aaaL9cZGnEYP5anryhK2x;?OUTFOX_SEARCH_USER_ID_NCOO=624916323.622491;?DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|;?JSESSIONID=abcbn5lLEK4FC4F7BhK2x;?___rl__test__cookies=1639138497978",
????"Referer":?"https://fanyi.youdao.com",
????"Content-Length":?"252"
????}
#獲取時間戳
r?=?time.time()
r?=?int(r*1000)
#獲取salt
s?=?random.randint(0,10)
i?=?r+s
Payload?=?{
????"i":"太陽",
????"smartresult":?"dict",
????"client":?"fanyideskweb",
????"salt":?i,
????"sign":?"b1e30cb6bb14501ea6827a83a554dcae",
????"lts":?r,
????"bv":?"e70edeacd2efbca394a58b9e43a6ed2a",
????"doctype":?"json",
????"version":?"2.1",
????"keyfrom":?"fanyi.web",
????"action":?"FY_BY_REALTlME"
????}
res?=?requests.post(url,?headers=headers,?data=Payload)
print(res.status_code)
print(res.text)
最后搞定sign
通過觀察可以發(fā)現(xiàn):sign: n.md5("fanyideskweb" + e + i + "Y2FYu%TNSbMCxc3t2u^XT"),能得到的信息有:1.這個是md5加密,2."fanyideskweb"是固定的,3.i前面已經(jīng)生成了,4.e不知道是什么,5."Y2FYu%TNSbMCxc3t2u^XT"這一部分是固定的。
通過斷點調(diào)試后發(fā)現(xiàn),e就是我們輸入的文字。

最后一步,百度md5怎么加密,這里我感覺是最難的地方,說實話這一塊我也不懂,百度的結(jié)果如下:
from?hashlib?import?md5
????string?=?"**********"
????m?=?md5()
????m.update(string.encode())
????sign?=?m.hexdigest()
改寫代碼
import?requests
import?time
import?random
from?hashlib?import?md5
import?json
url?=?"https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
headers={
????"User-Agent":"Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/96.0.4664.93?Safari/537.36",
????"Cookie":?"[email protected];?JSESSIONID=aaaL9cZGnEYP5anryhK2x;?OUTFOX_SEARCH_USER_ID_NCOO=624916323.622491;?DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|;?JSESSIONID=abcbn5lLEK4FC4F7BhK2x;?___rl__test__cookies=1639138497978",
????"Referer":?"https://fanyi.youdao.com",
????"Content-Length":?"252"
????}
def?get_param():
????lts?=?int(time.time()*1000)??#獲取時間戳lts
????random_num?=?random.randint(0,10)
????salt?=?lts+random_num????????#獲取salt
????word?=?input("請輸入需要翻譯的單詞:")
????string?=?"fanyideskweb"?+?word?+?str(salt)?+?"Y2FYu%TNSbMCxc3t2u^XT"
????m?=?md5()
????m.update(string.encode())
????sign?=?m.hexdigest()??#獲取md5加密的sign
????return?word,salt,lts,sign
word,salt,lts,sign?=?get_param()
Payload?=?{
????"i":word,
????"smartresult":?"dict",
????"client":?"fanyideskweb",
????"salt":?salt,
????"sign":?sign,
????"lts":?lts,
????"bv":?"e70edeacd2efbca394a58b9e43a6ed2a",
????"doctype":?"json",
????"version":?"2.1",
????"keyfrom":?"fanyi.web",
????"action":?"FY_BY_REALTlME"
????}
res?=?requests.post(url,?headers=headers,?data=Payload)
#?print(res.text)
data_json?=?json.loads(res.text)
result?=?data_json['translateResult'][0][0]
tgt?=?result['tgt']
src?=?result['src']
print(f"需要翻譯的單詞為:{tgt}")
print(f"翻譯的結(jié)果為:{src}")
成果展示

?最后,推薦螞蟻老師的Python爬蟲數(shù)據(jù)分析課程:
??
