天天看点

有道翻译的实践

在网上看了好几个用python调用网易有道翻译的教学贴,可惜对我等小白来说,放眼望去都是不懂的坑,感觉python还是需要实践来学习,就先把找到的填平这些坑的办法记录一下,可能涉及转载。

1. 各参数的获得

各参数的获得,是这个项目的关键点。

  • 使用chrome-检查-network,然后在网页中输入需要翻译的内容,点击翻译,在检查中找到新生成的tranlate开头的name,进入
有道翻译的实践
  • 进入translate以后,点击headers,会发现真实的request url以及form data,这时会发现form data中的salt、sign、lts、bv这四个参数都是长串无规则字符串。多生成几次translate以后,发现bv字符串是固定的,lts13位,salt比lts多一位无规则数字,sign一直变化。推测应该是在js中用了加密
  • 点击network-Initiator,发现全部指向同一个js
    有道翻译的实践
  • 点击进入 fanyi.min.js:1,点击pretty print(页面下方的{} 也行),直接进入fanyi.min.js:1所在行数,同时也把js代码格式化了。
  • 通过breakpoint的形式寻找,链接就是真实的request url,在XHR/fetch Breakpoint中填入。再次在网页上点击翻译,检查中页面会自动停下。
    有道翻译的实践
  • 点击上图中右侧的call stack,寻找t.translate,会看到salt,ts,bv,sign生成之后的数据,点击generatesSaltSign(n)回溯过去。最终找到。
    有道翻译的实践

2. 时间戳

python中时间戳是10位,但是在java中是13位,需要用到时间戳的时候代码如下:

import time

t = time.time() # 生成一个以秒为单位的10位时间戳,float类型的浮点数
t =int(t)  # 对t取整,不要小数
print(t)

# jave中需要13位时间戳,可以把秒转换为毫秒
millis = int(round(time.time()* 1000))  # round()是四省五入,其实不要round也没事
print(millis)

# 13位时间戳转换成现在时间
now = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(millis/1000))
print(now)
           

3. salt的构成

salt的值是i,而i = r + parseInt(10* Math.random(), 10)。

Math.random()是js中的函数,随机生成[0,1)随机数,而10*Math.random() 就是生成[0,10)中的一个随机数。

parseInt(string, radix), 其中string就是字符串,radix表示进制,可选从2到32,譬如10就是十进制,16就是十六进制,2就是二进制。

4. sign的构成

sign的值是 n.md5(“fanyideskweb” + e + i +‘Y2FYu%TNSbMCxc3t2u^XT’),(最后一个值可能每人都不一样),i是salt,e是输入的值。关于e到底是怎么来的,我觉得应该从function(e)引出的,说明e是function的输入变量。

5. bv的构成

bv的值是n.md5(navigator.appVersion),是固定的,实际就是浏览器版本。appVersion可以通过鼠标悬停的方式获得

有道翻译的实践

6. 最终的代码

最终的代码基本复制了大神的,确实写的简洁有力,记录一下。

# 向有道词典发送数据并获得翻译结果
import requests
import json
import time
import hashlib
import random

class YoudaoCrawl(object):

    def __init__(self, word):
        self.url = " http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
            "Cookie": '[email protected]; JSESSIONID=aaa6iBvh3WJaGgn8RPGBx; OUTFOX_SEARCH_USER_ID_NCOO=1574258758.1928287; ___rl__test__cookies=1610087834528',
            "Referer": "http://fanyi.youdao.com/"
        }
        self.word = word
        self.post_body = {}

    def generator_post_body(self):
        ts = str(int(time.time()*1000))    # ts是string型数据

        num = int(random.random() * 10)
        salt = ts + str(num)    # salt是string型数据


        str_sign = 'fanyideskweb' + self.word + salt + 'Y2FYu%TNSbMCxc3t2u^XT'
        md5 = hashlib.md5()  # md5加密
        md5.update(str_sign.encode('utf-8'))
        sign = md5.hexdigest()  # sign是string型数据


        appVersion = '5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome' \
                     '/92.0.4515.159 Safari/537.36'
        m_bv = hashlib.md5()
        m_bv.update(appVersion.encode('utf-8'))
        bv = m_bv.hexdigest()  # bv是string型数据


        self.post_body = {
            "i": self.word,
            "from": "AUTO",
            "to": "AUTO",
            "smartresult": "dict",
            "client": "fanyideskweb",
            "salt": salt,
            "sign": sign,
            "lts": ts,
            "bv": bv,
            "doctype": "json",
            "version": "2.1",
            "keyfrom": "fanyi.web",
            "action": "FY_BY_REALTIME",
        }


    def send_request(self):
        response =requests.post(self.url, headers=self.headers, data=self.post_body)
        return response.json()

    def parser_response(self, ret_dict):
        """从字典中提取翻译结果"""
        ret = ret_dict['translateResult'][0][0]['tgt']
        print("翻译的文本: {} , 翻译的结果 :{}".format(self.word, ret))

    def run(self):
        """运行函数"""
        self.generator_post_body()
        ret_dict = self.send_request()    # ???函数也能用self/???
        self.parser_response(ret_dict)

if __name__ == "__main__" :
    data = input("请输入需要翻译的内容: ")
    spider = YoudaoCrawl(data)
    spider.run()
           

时间戳参考链接

打点参考

代码参考