介绍
本教程的目的是教你如何用Python爬虫实现有道词典和有道翻译两个版本的功能,让你可以输入任意文字和目标语言,得到对应的翻译结果。本教程的难度适中,适合有一定Python基础和爬虫经验的读者。
有道词典和有道翻译的网页地址和请求参数
有道词典和有道翻译是两个不同的网页,它们的网页地址分别是:
- 有道词典:[http://fanyi.youdao.com/]
- 有道翻译:[http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule]
它们的请求参数也不同,有道词典的请求参数包括:
- i:要翻译的文字
- from:源语言
- to:目标语言
- smartresult:智能结果
- client:客户端
- salt:时间戳
- sign:签名
- lts:时间戳
- bv:浏览器版本
- doctype:文档类型
- version:版本
- keyfrom:来源
- action:动作
有道翻译的请求参数包括:
- i:要翻译的文字
- from:源语言
- to:目标语言
- smartresult:智能结果
- client:客户端
- salt:时间戳
- sign:签名
- lts:时间戳
- bv:浏览器版本
- doctype:文档类型
- version:版本
我们可以用Python的urllib库来构造请求URL和请求头,例如:
import urllib.parse
# 有道词典请求URL和请求头示例
word = "hello" # 要翻译的文字
from_lang = "AUTO" # 源语言,自动检测
to_lang = "zh" # 目标语言,中文
# 其他参数需要根据加密机制生成,后面会介绍
youdao_dict_url = "http://fanyi.youdao.com/" # 有道词典网页地址
youdao_dict_data = { # 有道词典请求参数字典
"i": word,
"from": from_lang,
"to": to_lang,
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"lts": lts,
"bv": bv,
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTlME"
}
youdao_dict_data = urllib.parse.urlencode(youdao_dict_data).encode("utf-8") # 将请求参数字典转换为URL编码格式
youdao_dict_headers = { # 有道词典请求头字典
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",
"Referer": youdao_dict_url,
"Cookie": "_ntes_nnid=...; OUTFOX_SEARCH_USER_ID_NCOO=...; OUTFOX_SEARCH_USER_ID=...; JSESSIONID=...; ___rl__test__cookies=..."
}
# 有道翻译请求URL和请求头示例
word = "hello" # 要翻译的文字
from_lang = "AUTO" # 源语言,自动检测
to_lang = "zh" # 目标语言,中文
# 其他参数需要根据加密机制生成,后面会介绍
youdao_trans_url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule" # 有道翻译网页地址
youdao_trans_data = { # 有道翻译请求参数字典
"i": word,
"from": from_lang,
"to": to_lang,
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"lts": lts,
"bv": bv,
"doctype": "json",
"version": "2.1"
}
youdao_trans_data = urllib.parse.urlencode(youdao_trans_data).encode("utf-8") # 将请求参数字典转换为URL编码格式
youdao_trans_headers = { # 有道翻译请求头字典
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",
"Referer": youdao_trans_url,
"Cookie": "_ntes_nnid=...; OUTFOX_SEARCH_USER_ID_NCOO=...; OUTFOX_SEARCH_USER_ID=...; JSESSIONID=...; ___rl__test__cookies=..."
}
有道词典和有道翻译的加密机制
有道词典和有道翻译的请求参数中,有几个参数是需要根据一定的加密机制生成的,这些参数分别是:
- salt:时间戳,表示当前的毫秒数
- sign:签名,表示对要翻译的文字和其他参数进行加密后的结果
- lts:时间戳,表示当前的秒数
- bv:浏览器版本,表示对浏览器的User-Agent进行加密后的结果
我们可以通过分析网页的JavaScript代码,找到加密算法的实现,并用Python来模拟。具体来说:
- salt和lts可以用Python的time库来获取,例如:
import time salt = str(int(time.time() * 1000)) # 获取当前的毫秒数 lts = salt[:-3] # 获取当前的秒数
- sign可以用Python的hashlib库来实现MD5加密,以及用Python内置的exec函数来执行JavaScript代码,例如:
import hashlib import execjs word = "hello" # 要翻译的文字 # 有道词典的sign加密算法 youdao_dict_sign_js = """ function e(r, o) { var t = n.md5(navigator.appVersion), e = "" + (new Date).getTime(), i = e + parseInt(10 * Math.random(), 10); return { ts: e, bv: t, salt: i, sign: n.md5("fanyideskweb" + r + i + o) } } """ youdao_dict_sign_node = execjs.get() # 获取一个JavaScript运行环境 youdao_dict_sign_func = youdao_dict_sign_node.compile(youdao_dict_sign_js) # 编译JavaScript代码 youdao_dict_sign_key = "97_3(jkMYg@T[KZQmqjTK" # 有道词典的sign加密密钥 youdao_dict_sign_result = youdao_dict_sign_func.call("e", word, youdao_dict_sign_key) # 调用JavaScript函数,传入要翻译的文字和密钥,得到加密结果 sign = youdao_dict_sign_result["sign"] # 获取sign参数 # 有道翻译的sign加密算法 youdao_trans_sign_js = """ function a(r) { if (Array.isArray(r)) { for (var o = 0, t = Array(r.length); o < r.length; o++) t[o] = r
有道词典翻译代码
from hashlib import md5
import requests
def get_form_data(text, le):
"""
构建表单参数
:param :text:翻译内容
:param :le:目标语言
"""
# 固定值
w = 'Mk6hqtUp33DGGtoS63tTJbMUYjRrG1Lu'
v = 'webdict'
_ = 'web'
r = text + v
time = len(r) % 10
o = md5(r.encode('utf-8')).hexdigest()
n = _ + text + str(time) + w + o
f = md5(n.encode('utf-8')).hexdigest()
form_data = {
'q': text,
'le': le,
't': time,
'client': _,
'sign': f,
'keyfrom': v,
}
return form_data
def translate(query, to_lan):
"""
启动翻译
:param query: 翻译内容
:param to_lan: 目标语言
:return:
"""
# 有道词典网页请求参数
url = 'https://dict.youdao.com/jsonapi_s?doctype=json&jsonversion=4'
form_data = get_form_data(query, to_lan)
try:
res = requests.post(url, data=form_data).json()
# 取第一个网络释义
result = res['web_trans']['web-translation'][0]['trans'][0]['value']
return result
except Exception as e:
print('翻译失败:', e)
return '翻译失败:' + query
if __name__ == '__main__':
"""
# 有道词典语言选项
lang = {
'自动检测语言': '',
'中英': 'en',
'中法': 'fr',
'中韩': 'ko',
'中日': 'ja',
}
"""
word = input("请输入你要翻译的文字: ")
# ret = translate('早上好', 'ja')
# ret = translate('你好', 'fr')
# ret = translate('你好', 'ko')
# ret = translate('你好', '')
# ret = translate('你好', 'en')
ret = translate(word, 'ja')
print('翻译结果:\n', ret)
有道文本翻译代码
import hashlib
import base64
import requests
import json
import time
from urllib.parse import urlencode
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad, pad
class AESCipher(object):
key = b'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'
iv = b'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'
iv = hashlib.md5(iv).digest()
key = hashlib.md5(key).digest()
@staticmethod
def decrypt(data):
# AES解密
cipher = AES.new(AESCipher.key, AES.MODE_CBC, iv=AESCipher.iv)
decrypted = cipher.decrypt(base64.b64decode(data, b'-_'))
unpadded_message = unpad(decrypted, AES.block_size).decode()
return unpadded_message
@staticmethod
def encrypt(plaintext: str):
# AES加密
cipher = AES.new(AESCipher.key, AES.MODE_CBC, iv=AESCipher.iv)
plaintext = plaintext.encode()
padded_message = pad(plaintext, AES.block_size)
encrypted = cipher.encrypt(padded_message)
encrypted = base64.b64encode(encrypted, b'-_')
return encrypted
def get_form_data(sentence, from_lang, to_lang):
"""
构建表单参数
:param :sentence:翻译内容
:param from_lang:源语言
:param to_lang:目标语言
:return:
"""
e = 'fsdsogkndfokasodnaso'
d = 'fanyideskweb'
u = 'webfanyi'
m = 'client,mysticTime,product'
p = '1.0.0'
b = 'web'
f = 'fanyi.web'
t = time.time()
query = {
'client': d,
'mysticTime': t,
'product': u,
'key': e
}
# 获取sign值 - -密钥值
h = hashlib.md5(urlencode(query).encode('utf-8')).hexdigest()
form_data = {
'i': sentence,
'from': from_lang,
'to': to_lang,
'domain': 0,
'dictResult': 'true',
'keyid': u,
'sign': h,
'client': d,
'product': u,
'appVersion': p,
'vendor': b,
'pointParam': m,
'mysticTime': t,
'keyfrom': f
}
return form_data
def translate(sentence, from_lang='auto', to_lang=''):
"""
:param sentence:需翻译的句子
:param from_lang:源语言
:param to_lang:目标语言
:return:
"""
# 有道翻译网页请求参数
url = 'https://dict.youdao.com/webtranslate'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
'referer': 'https://fanyi.youdao.com/',
'cookie': 'OUTFOX_SEARCH_USER_ID=-805044645@10.112.57.88; OUTFOX_SEARCH_USER_ID_NCOO=818822109.5585971;'
}
params = get_form_data(sentence, from_lang, to_lang)
try:
res = requests.post(url, headers=headers, data=params)
# 翻译结果进行AES解密
cipher = AESCipher
ret = json.loads(cipher.decrypt(res.text))
tgt = ret['translateResult'][0][0]['tgt']
return tgt
except Exception as e:
print('翻译失败:', e)
return '翻译失败:' + sentence
if __name__ == '__main__':
word = input("请输入你要翻译的文字: ")
# result = translate(word)
result = translate(word, 'zh-CHS', 'ja')
print('翻译结果:\n', result)
有道文本翻译旧版代码
import requests
def translate(content):
"""
默认汉译英-英译汉的翻译
:param content:要翻译的文本
:return: 返回翻译后的结果
"""
url = 'https://fanyi.youdao.com/translate'
data = {'doctype': 'json',
'i': content}
try:
r = requests.get(url, params=data)
res_json = r.json()
tgt = res_json['translateResult'][0][0]['tgt']
return tgt
except Exception as e:
print('翻译失败:', e)
return '翻译失败:' + content
if __name__ == '__main__':
word = input("请输入需翻译的文字: ")
res = translate(word)
print('翻译结果:\n', res)
注意
对AES解密需要安装pycryptodome:$ pip install pycryptodome
本教程根据:作者是cherish1112365,发表在CSDN博客
没有回复内容