概述
分析
- i:输入的需要翻译的字词;
- salt、sign、Its、bv:各种加密字符,需要处理。
![四个加密字符](https://img-blog.csdnimg.cn/cc60dbe3d5c245ddbc66ea28bca7121e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiA5YyXRE1Z,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
- i值不同很容易理解,因为需要翻译的字词不同,而salt与sign这两个值每次请求都不同,一般是两种情况:一是请求翻译浏览器会从服务器获取这两个值;二是本地JS代码生成。
- 对于第一种情况,每次发送翻译请求时,在network请求项目栏中并没有多余的对这两个值进行请求的链接,猜测应该是第二种情况。
- JS、CSS等一般是静态资源,打开Sources栏目,经过一番寻找可找到一个fanyi.min.js文件,点击蓝色箭头所指的大括号进行格式化,如下图。
![找到fanyi.min.js文件](https://img-blog.csdnimg.cn/9e4a12d4d4744328a4c71655c6449780.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiA5YyXRE1Z,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
- 按下ctrl+f进行查找,键入salt,共有12个salt变量,可知这些变量是在JS中计算得出的,故需要处理其生成机制,模仿生成加密变量。
处理加密
- 在查找salt变量时,可见位于8383行的函数中,有对ts、bv、salt、sign的明显的定义。
![定义变量](https://img-blog.csdnimg.cn/52ca1a5a76424ccfbab224ccc21f529c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiA5YyXRE1Z,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
- 首先是ts(应该对应Its),如图ts值为r,而在8385行
r = "" + (new Date).getTime()
,JS中.getTime()为获取当前时间戳,空字符与其相加意为转为字符串。Python中使用time.time()获取时间戳,对比发现位数少三位,故Python中操作应为str(int(time.time()*1000))
,其中使用int()是为了消除小数位。
- bv值为t,而在8384行
t = n.md5(navigator.appVersion)
,其中navigator.appVersion为获取浏览器信息,如Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
。 - md5为一种加密方式,Python中可用hashlib库下的md5()方法生成,传入的参数按要求需要先encode(),最后再使用hexdigest()方法返回摘要,作为十六进制数据字符串值。即
(hashlib.md5(appVersion.encode())).hexdigest()
。
- salt值为i,而在8386行
i = r + parseInt(10 * Math.random(), 10)
,其中r的值在上述过程中已知,JS中parseInt()解析一个字符串,并返回一个整数。第一个参数必需,为要被解析的字符串;第二个参数可选,表示要解析的数字的基数,上述为10可理解为形容第一个参数为10进制,在函数执行后均变为10进制。 - 故Python操作下,salt变量应为
Its + str(random.randint(0,9))
- sign的值为
n.md5("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5")
,同样是md5加密,需加密的字符串首位固定,i值由上述已知。故仅需找到e值。 - 由于e变量太多,考虑ts、bv、salt、sign四个变量一般同时出现,可观察周围对e是否有定义或者一些线索。
- 注意到8394行的函数,函数中封装了data,sign值为i.sign,而i在此函数开头8396行定义为
i = r(t)
。此r()函数即为8383行函数,传入的参数t于8395行定义为var t = e.i
。结合r()函数在8383行的定义,可知8395行传入的e.i的值即为8383行的e参数,且8402行i(这个i在data字典中,而字典的i在请求头中可知其为输入的字词)值为e.i,可知sign值中的e值即为输入的字词。
代码
- 至此,在明白四个变量的加密规则后,即可使用Python代码模拟计算得出。代码如下。
import requests
import hashlib
import time
import random
appVersion = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"
def makeMD5(word):
res = hashlib.md5(word.encode())
return res.hexdigest()
def youdao(e):
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
Its = str(int(time.time()*1000))
i = Its + str(random.randint(0,9))
sign = "fanyideskweb" + e + i + "mmbP%A-r6U3Nw(n]BjuEU"
headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-Length': '242',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': 'OUTFOX_SEARCH_USER_ID=-1270532315@112.28.191.238; _ntes_nnid=dd32e418bcc6e0bb2ae87c7ef2a74e43,1582685944025; OUTFOX_SEARCH_USER_ID_NCOO=1448366101.8020096; UM_distinctid=17245fd071a226-0081a02b10c39f-46531b29-1fa400-17245fd071b4d; JSESSIONID=aaaYkkUvQE5KD6ybVGVox; ___rl__test__cookies=1596377462367',
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Pragma': 'no-cache',
'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'
}
FormData = {
'i': e,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': i,
'sign': makeMD5(sign),
'Its': Its,
'bv': makeMD5(appVersion),
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
response = requests.post(url, data=FormData, headers=headers)
return response.json()
while True:
content = input('输入:')
result = youdao(content)
print(result)