Python3爬取有道翻译的两种方法

    xiaoxiao2025-07-20  12

    一. 破解参数加密

    有道翻译的请求是post,携带一系列参数,直接F12刷新进行调试,如下图所示:

    这是一个 post 请求,目标网址是

    'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'

    接下来让我们看看发送该请求需要携带哪些参数

    如图所示,红色方框里的就是需要携带的参数了。

    最后看一看返回的数据

    显而易见,返回的数据是json格式的数据。

    好了,现在我们可以写程序进行爬取了

    # -*-coding:utf-8-*- __Author__ = "Mr.D" __Date__ = '2019\5\26 0026 16:50' from faker import Faker import requests ua = Faker().user_agent() url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' key = input("请输入你需要翻译的内容: ") # 请求头 headers = { 'User-Agent': ua, 'Host': 'fanyi.youdao.com', 'Origin': 'http://fanyi.youdao.com', 'Referer': 'http://fanyi.youdao.com/', } # post请求携带的参数 from_data = { 'i': key, 'from': 'UTO', 'to': 'UTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'salt': 15588802331547, 'sign': 3e91f2d8788201c03bfa0a672b116998, 'ts': 1558880233154, 'bv': '5504a5c7c19867a06038cf79d29f756a', 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_REALTlME' } response = requests.post(url, headers=headers, data=from_data).json() print(response) print(response['translateResult'][0][0]['tgt'])

    运行后发现报错了,"{errorCode: 50}"

    什么原因呢? 让我们分析一下。

    可以自己 重新来翻译一下  "问题" 这个词,然后在看一次此次 post 请求与上一次 post 请求有什么不同之处。

    经过调试,我发现 from_data 中的参数有几个是发生了变化的,分别是 "salt","sign","ts",那么这几个参数是怎么生存的呢?

    经过寻找,发现它们的生存规律在 "http://shared.ydstatic.com/fanyi/newweb/v1.0.17/scripts/newweb/fanyi.min.js" 这个  js 文件中,经过 json 格式化工具(百度)格式化之后,定位到具体的参数生成位置,

    // e 为下面 r(t) 中的 t ,即我们所需要翻译的内容 var r = function(e) { var t = n.md5(navigator.appVersion), r = "" + (new Date).getTime(), i = r + parseInt(10 * Math.random(), 10); return { ts: r, bv: t, salt: i, sign: n.md5("fanyideskweb" + e + i + "n%A-rKaT5fb[Gy?;N5@Tj") } }; t.recordUpdate = function(e) { // 将我们所要翻译的内容赋值给 t var t = e.i, // 将 t 当作参数传入 r() 函数中,返回值赋给 i i = r(t); n.ajax({ type: "POST", contentType: "application/x-www-form-urlencoded; charset=UTF-8", url: "/bettertranslation", // 这里可以看出 data 就是我们post请求携带的参数字典 data: { // e.i 就是我们所要翻译的内容 i: e.i, client: "fanyideskweb", salt: i.salt, sign: i.sign, ts: i.ts, bv: i.bv, tgt: e.tgt, modifiedTgt: e.modifiedTgt, from: e.from, to: e.to }, success: function(e) {}, error: function(e) {} }) }

    从上述代码中,我们可以得出四个参数的信息: ts,bv,salt,sign,他们分别为

    ts: "" + (new Date).getTime(), bv: n.md5(navigator.appVersion), salt: ts + parseInt(10 * Math.random(), 10), // e为所需要翻译的字符串, i 即salt sign: n.md5("fanyideskweb" + e + salt + "n%A-rKaT5fb[Gy?;N5@Tj")

    分析一波:

    bv 是对  navigator.appVersion(这是个浏览器参数,不是字符串"navigator.appVersion")进行 md5 加密,在相同的浏览器下,这个值是固定的(没测试过),所以直接拿F12调试出来的来用就好了。

    ts 是时间戳

    salt 是 ts 加上一个 0 到 10 的随机数(包括0,不包括10)

    sign 是对 "fanyideskweb" + e + salt + "n%A-rKaT5fb[Gy?;N5@Tj" (这个字符串是会更新的,在js文件里可以找到)这个字符串进行 md5 加密

    好了,知道以上信息,我们可以进一步完善我们的代码了,如下图:

    # -*-coding:utf-8-*- __Author__ = "Mr.D" __Date__ = '2019\5\26 0026 16:50' import time from faker import Faker import random import hashlib import requests ua = Faker().user_agent() url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' key = input("请输入你需要翻译的内容: ") //生成时间戳 ts ts = str(time.time() * 1000) // 通过 ts 加 0-10的随机整数字符生成 salt salt = ts + str(random.randint(0, 10)) the_str = "fanyideskweb" + key + salt + "n%A-rKaT5fb[Gy?;N5@Tj" // md5加密生成 sign md5 = hashlib.md5() md5.update(the_str.encode('utf-8')) sign = md5.hexdigest() headers = { 'User-Agent': ua, 'Host': 'fanyi.youdao.com', 'Origin': 'http://fanyi.youdao.com', 'Referer': 'http://fanyi.youdao.com/', } from_data = { 'i': key, 'from': 'UTO', 'to': 'UTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'salt': salt, 'sign': sign, 'ts': ts, 'bv': '5504a5c7c19867a06038cf79d29f756a', 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_REALTlME' } response = requests.post(url, headers=headers, data=from_data).json() print(response) print(response['translateResult'][0][0]['tgt'])

    完成之后再次爬取,发现还是报一样的错误。

    纳尼!! 再三检查代码,没有发现有写错任何地方啊

    既然  from_data 没有写错,那么问题可能是出现在了 headers 上了

    经过调试,发现每次 headers 都会携带 cookie ,而且 cookie 的值每次都不一样

    'Cookie': 'OUTFOX_SEARCH_USER_ID=559238864@10.168.8.61; OUTFOX_SEARCH_USER_ID_NCOO=2061523511.1027195; _ga=GA1.2.1151109878.1551536968; _ntes_nnid=24fe647fc20f952c4040b25650f75604,1553001083850; JSESSIONID=aaaJIa27BLmlI96aStZRw; ___rl__test__cookies=1558881656766'

    不一样的地方在于最后的那个 "__rl__test__cookies=" 后面的字符串不一样,然后去找到它是怎么生成的,最后终于在

    "http://shared.ydstatic.com/js/rlog/v1.js" 这个js文件中找到了它

    原来它也是时间戳,怪不得看起来有点像

    继续完善代码

    # -*-coding:utf-8-*- __Author__ = "Mr.D" __Date__ = '2019\5\26 0026 16:50' import time from faker import Faker import random import hashlib import requests ua = Faker().user_agent() url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' key = input("请输入你需要翻译的内容: ") //生成时间戳 ts ts = str(time.time() * 1000) // 通过 ts 加 0-10的随机整数字符生成 salt salt = ts + str(random.randint(0, 10)) the_str = "fanyideskweb" + key + salt + "@6f#X3=cCuncYssPsuRUE" // md5加密生成 sign md5 = hashlib.md5() md5.update(the_str.encode('utf-8')) sign = md5.hexdigest() headers = { 'User-Agent': ua, 'Host': 'fanyi.youdao.com', 'Origin': 'http://fanyi.youdao.com', 'Referer': 'http://fanyi.youdao.com/', 'Cookie': 'OUTFOX_SEARCH_USER_ID=559238864@10.168.8.61; OUTFOX_SEARCH_USER_ID_NCOO=2061523511.1027195; _ga=GA1.2.1151109878.1551536968; _ntes_nnid=24fe647fc20f952c4040b25650f75604,1553001083850; JSESSIONID=aaaJIa27BLmlI96aStZRw; ___rl__test__cookies=' + ts } from_data = { 'i': key, 'from': 'UTO', 'to': 'UTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'salt': salt, 'sign': sign, 'ts': ts, 'bv': '5504a5c7c19867a06038cf79d29f756a', 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_REALTlME' } response = requests.post(url, headers=headers, data=from_data).json() print(response) print(response['translateResult'][0][0]['tgt'])

    好了,让我们运行代码看看

    大功告成。

    附使用 urllib 库的代码  

    # -*-coding:utf-8-*- __Author__ = "Mr.D" __Date__ = '2019\5\26 0026 18:07' import urllib.request import urllib.parse import json import time import random import hashlib from faker import Faker url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' ua = Faker().user_agent() key = input("请输入你需要翻译的内容: ") ts = str(time.time() * 1000) salt = ts + str(random.randint(0, 10)) the_str = "fanyideskweb" + key + salt + "@6f#X3=cCuncYssPsuRUE" md5 = hashlib.md5() md5.update(the_str.encode('utf-8')) sign = md5.hexdigest() # 请求头 headers = { 'User-Agent': ua, 'Host': 'fanyi.youdao.com', 'Origin': 'http://fanyi.youdao.com', 'Referer': 'http://fanyi.youdao.com/', 'Cookie': 'OUTFOX_SEARCH_USER_ID=559238864@10.168.8.61; OUTFOX_SEARCH_USER_ID_NCOO=2061523511.1027195; _ga=GA1.2.1151109878.1551536968; _ntes_nnid=24fe647fc20f952c4040b25650f75604,1553001083850; JSESSIONID=aaaJIa27BLmlI96aStZRw; ___rl__test__cookies=' + ts } # 表单数据 from_data = { 'i': key, 'from': 'UTO', 'to': 'UTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'salt': salt, 'sign': sign, 'ts': ts, 'bv': '5504a5c7c19867a06038cf79d29f756a', 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_REALTlME' } from_data = urllib.parse.urlencode(from_data).encode('utf-8') request = urllib.request.Request(url, from_data, headers) response = urllib.request.urlopen(request).read().decode("utf-8") target = json.loads(response) result = target['translateResult'][0][0]['tgt'] print(result)

    总结

    用到的知识点:

    1. faker库随机生成 ua

    2. time()函数生成时间戳

    3. hashlib库进行md5加密

    4. js基础知识的掌握

    5. requests库的使用

    其中,第四点最为重要

     

    二.绕过js加密

    代码这个方法非常简单,只需要将 url 中的 _o 去掉就可以了,在传递的from_data中不再需要上述几个加密的参数,只需要我们所要翻译的内容 就可以进行数据获取了

    urllib 库的爬取代码如下

    # -*-coding:utf-8-*- __Author__ = "Mr.D" __Date__ = '2019\5\26 0026 18:07' import urllib.request import urllib.parse import json from faker import Faker // 去掉_o url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule' ua = Faker().user_agent() key = input("请输入你需要翻译的内容: ") # 请求头 headers = { 'User-Agent': ua, 'Host': 'fanyi.youdao.com', 'Origin': 'http://fanyi.youdao.com', 'Referer': 'http://fanyi.youdao.com/', } # 表单数据 from_data = { 'i': key, 'from': 'UTO', 'to': 'UTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_REALTlME' } from_data = urllib.parse.urlencode(from_data).encode('utf-8') request = urllib.request.Request(url, from_data, headers) response = urllib.request.urlopen(request).read().decode("utf-8") target = json.loads(response) result = target['translateResult'][0][0]['tgt'] print(result)

     

    在看完上面的代码之后,可以自己尝试着写出使用第二种方法和requests库进行有道翻译的爬取,来验证代码是否正确

    最后,欢迎大家提问

    最新回复(0)