- 有道是怎么翻译的
- 构造请求
- 代码实现
先打开有道翻译,在里面输出英文进行翻译,左侧出现翻译结果。
初步推测这些信息是由xhr控制,所以我打开了开发者工具,选择网络这一栏,并重新翻译一次,并勾选Fech/XHR
发现有一个xhr请求,点开看看是不是我们需要的。
好像是我们需要的,也就是说我们只需要进行请求这个链接,就可以获得数据。
看一下这链接请求正文,发现这个是POST请求。
在看一下这个链接的表单数据:
经过多次翻译,发现有几个参数不变:
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_CLICKBUTTION"
以上参数没有变化
i这个参数是要翻译的单词,其他参数现在并不知道是怎么来的。
推测是js加密的,接着去网页源代码中找js文件
在源代码最下方,发现有三个js文件,我们把js文件内容经过js美化进行关键字搜索,第三个是我们需要的。
再这个文件里,发现这些
function(e, t) {
var n = e("./jquery-1.7");
e("./utils");
e("./md5");
var r = function(e) {
var t = n.md5(navigator.appVersion), // 这里对应着bv
r = "" + (new Date).getTime(), // 这里对应着lts
i = r + parseInt(10 * Math.random(), 10); // 这里对应着salt
return {
ts: r,
bv: t,
salt: i,
sign: n.md5("fanyideskweb" + e + i + "Y2FYu%TNSbMCxc3t2u^XT") //这里对应着sign
}
};
t.recordUpdate = function(e) {
var t = e.i,
i = r(t);
n.ajax({
type: "POST",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
url: "/bettertranslation",
data: {
i: e.i,
client: "fanyideskweb",
salt: i.salt, //这里
sign: i.sign, //这里
lts: i.ts, //这里
bv: i.bv, //这里
tgt: e.tgt,
modifiedTgt: e.modifiedTgt,
from: e.from,
to: e.to
},
success: function(e) {},
error: function(e) {}
})
},
从以上代码中得到了我们想要的东西:
t = n.md5(navigator.appVersion), // 这里对应着bv
r = "" + (new Date).getTime(), // 这里对应着lts
i = r + parseInt(10 * Math.random(), 10); // 这里对应着salt
sign: n.md5("fanyideskweb" + e + i + "Y2FYu%TNSbMCxc3t2u^XT") //这里对应着sign
发现navigator.appVersion是User-Agent,也就是说bv是User-Agentmd5值
所以bv参数可以构造成这样
bv = md5(headers["User-Agent"].encode("utf-8")).hexdigest()
md5加密需要用到hashlib这个标准库,为了防止乱码,先将要加密的对象转成utf-8的格式,先创建MD5对象,将需要加密的对象传入进入,再通过hexdigest()获得加密值。
继续在控制台输出(new Date).getTime(),发现是时间戳,
所以lts可以这样构造,因为(new Date).getTime()是毫秒,而python的time.time()是秒,所以需要乘1000,然后再去除多余的小数,最后再转换成字符串形式。
lts = str(time.time() * 1000).split(".")[0]
接着分析salt
i = r + parseInt(10 * Math.random(), 10); // 这里对应着salt
parseInt(string,radix) 函数解析字符串并返回整数。radix 参数用于指定使用哪种数字系统。10就代表十进制。
Math.random()是系统随机选取大于等于 0.0 且小于 1.0 的随机 double 值
这个r代表lts
所以salt是时间戳加一个随机0-10整数
salt = lts + str(random.randint(0, 10))
最后分析sign
sign: n.md5("fanyideskweb" + e + i + "Y2FYu%TNSbMCxc3t2u^XT") //这里对应着sign
e上下文分析是我们要翻译的单词,这个i是上面的salt,也就是说:sign是
"fanyideskweb" + 要翻译的单词 + salt + "Y2FYu%TNSbMCxc3t2u^XT"的md5值
用python实现是这样的
sign = md5(("fanyideskweb" + word + salt + "Y2FYu%TNSbMCxc3t2u^XT").encode("utf-8")).hexdigest()
代码实现
全部代码实现是这样的
import requests
from hashlib import md5
import time
import random
import re
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/92.0.4515.107 Safari/537.36 Edg/92.0.902.62",
"Referer": "https://fanyi.youdao.com/",
"cookie": "OUTFOX_SEARCH_USER_ID=512688694@10.169.0.102; JSESSIonID=aaaxkb_sIz1dThPLLogSx; OUTFOX_SEARCH_USER_ID_NCOO=68588117.42891903; fanyi-ad-id=113723; fanyi-ad-closed=1; ___rl__test__cookies=1627897214144"
}
while(1):
word = input("请输入英文单词:")
mach = re.match("^[A-Za-z]+$", word)
if mach:
break
else:
print("不要输入其他东西哦!")
lts = str(time.time() * 1000).split(".")[0]
salt = lts + str(random.randint(0, 10))
sign = md5(("fanyideskweb" + word + salt + "Y2FYu%TNSbMCxc3t2u^XT").encode("utf-8")).hexdigest()
bv = md5(headers["User-Agent"].encode("utf-8")).hexdigest()
data = {
"i": word,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"lts": lts,
"bv": bv,
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_CLICKBUTTION"
}
resp = requests.post(url, headers=headers, data=data).json()
if resp['errorCode'] == 0:
result = resp["translateResult"][0][0]['tgt']
detail_result = resp['smartResult']['entries']
print("--------------------------------------------")
print("翻译结果:")
print(result)
print("-------------------------")
print(word)
for i in detail_result:
print(i)
print("--------------------------------------------")
elif resp['errorCode'] == 40:
print("没有查询到这个单词!")
else:
print("有道翻译接口解析失败,请重新分析!")



