用Python爬虫轻松实现有道翻译-Python论坛-编程语言区-资源工坊-游戏模组资源分享

用Python爬虫轻松实现有道翻译

介绍

本教程的目的是教你如何用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博客

请登录后发表评论

    没有回复内容