在網上看了好幾個用python調用網易有道翻譯的教學貼,可惜對我等小白來說,放眼望去都是不懂的坑,感覺python還是需要實踐來學習,就先把找到的填平這些坑的辦法記錄一下,可能涉及轉載。
1. 各參數的獲得
各參數的獲得,是這個項目的關鍵點。
- 使用chrome-檢查-network,然後在網頁中輸入需要翻譯的内容,點選翻譯,在檢查中找到新生成的tranlate開頭的name,進入

- 進入translate以後,點選headers,會發現真實的request url以及form data,這時會發現form data中的salt、sign、lts、bv這四個參數都是長串無規則字元串。多生成幾次translate以後,發現bv字元串是固定的,lts13位,salt比lts多一位無規則數字,sign一直變化。推測應該是在js中用了加密
- 點選network-Initiator,發現全部指向同一個js
有道翻譯的實踐 - 點選進入 fanyi.min.js:1,點選pretty print(頁面下方的{} 也行),直接進入fanyi.min.js:1所在行數,同時也把js代碼格式化了。
- 通過breakpoint的形式尋找,連結就是真實的request url,在XHR/fetch Breakpoint中填入。再次在網頁上點選翻譯,檢查中頁面會自動停下。
有道翻譯的實踐 - 點選上圖中右側的call stack,尋找t.translate,會看到salt,ts,bv,sign生成之後的資料,點選generatesSaltSign(n)回溯過去。最終找到。
有道翻譯的實踐
2. 時間戳
python中時間戳是10位,但是在java中是13位,需要用到時間戳的時候代碼如下:
import time
t = time.time() # 生成一個以秒為機關的10位時間戳,float類型的浮點數
t =int(t) # 對t取整,不要小數
print(t)
# jave中需要13位時間戳,可以把秒轉換為毫秒
millis = int(round(time.time()* 1000)) # round()是四省五入,其實不要round也沒事
print(millis)
# 13位時間戳轉換成現在時間
now = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(millis/1000))
print(now)
3. salt的構成
salt的值是i,而i = r + parseInt(10* Math.random(), 10)。
Math.random()是js中的函數,随機生成[0,1)随機數,而10*Math.random() 就是生成[0,10)中的一個随機數。
parseInt(string, radix), 其中string就是字元串,radix表示進制,可選從2到32,譬如10就是十進制,16就是十六進制,2就是二進制。
4. sign的構成
sign的值是 n.md5(“fanyideskweb” + e + i +‘Y2FYu%TNSbMCxc3t2u^XT’),(最後一個值可能每人都不一樣),i是salt,e是輸入的值。關于e到底是怎麼來的,我覺得應該從function(e)引出的,說明e是function的輸入變量。
5. bv的構成
bv的值是n.md5(navigator.appVersion),是固定的,實際就是浏覽器版本。appVersion可以通過滑鼠懸停的方式獲得
6. 最終的代碼
最終的代碼基本複制了大神的,确實寫的簡潔有力,記錄一下。
# 向有道詞典發送資料并獲得翻譯結果
import requests
import json
import time
import hashlib
import random
class YoudaoCrawl(object):
def __init__(self, word):
self.url = " http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
self.headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
"Cookie": '[email protected]; JSESSIONID=aaa6iBvh3WJaGgn8RPGBx; OUTFOX_SEARCH_USER_ID_NCOO=1574258758.1928287; ___rl__test__cookies=1610087834528',
"Referer": "http://fanyi.youdao.com/"
}
self.word = word
self.post_body = {}
def generator_post_body(self):
ts = str(int(time.time()*1000)) # ts是string型資料
num = int(random.random() * 10)
salt = ts + str(num) # salt是string型資料
str_sign = 'fanyideskweb' + self.word + salt + 'Y2FYu%TNSbMCxc3t2u^XT'
md5 = hashlib.md5() # md5加密
md5.update(str_sign.encode('utf-8'))
sign = md5.hexdigest() # sign是string型資料
appVersion = '5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome' \
'/92.0.4515.159 Safari/537.36'
m_bv = hashlib.md5()
m_bv.update(appVersion.encode('utf-8'))
bv = m_bv.hexdigest() # bv是string型資料
self.post_body = {
"i": self.word,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"lts": ts,
"bv": bv,
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTIME",
}
def send_request(self):
response =requests.post(self.url, headers=self.headers, data=self.post_body)
return response.json()
def parser_response(self, ret_dict):
"""從字典中提取翻譯結果"""
ret = ret_dict['translateResult'][0][0]['tgt']
print("翻譯的文本: {} , 翻譯的結果 :{}".format(self.word, ret))
def run(self):
"""運作函數"""
self.generator_post_body()
ret_dict = self.send_request() # ???函數也能用self/???
self.parser_response(ret_dict)
if __name__ == "__main__" :
data = input("請輸入需要翻譯的内容: ")
spider = YoudaoCrawl(data)
spider.run()
時間戳參考連結
打點參考
代碼參考