Python实现google翻译

前言

由于最近APP需要增加对其它语言的支持,因此需要有个可以实现翻译的脚本,摸索了两三天,虽然最后感觉脚本不怎么完美,但还是记录下这期间遇到的问题:

过程

在网上搜了一些如何用python实现google脚本,大致有三种:
1.调用google API的
2.使用别人已经封装好的库
3.类似爬虫方式获取(我没爬过,也不知道算不算)
这里采用第三种,主要是看了利用python调用谷歌翻译API这篇文章,感觉蛮简单,也感觉比较靠谱,然后就开搞了。

按照利用python调用谷歌翻译API这篇文章实现脚本以后,发现只能翻译成中文,而且不适合翻译多个句子。

最后自己摸索了一下,将这个脚本稍微改了下,支持翻译多条语句:

import requests
import json
import execjs  # 必须,需要先用pip 安装,用来执行js脚本
from urllib.parse import quote
# 用来判断是否需要打印日志
debug = True

class Py4Js:

    def __init__(self):
        self.ctx = execjs.compile(""" 
            function TL(a) { 
                var k = ""; 
                var b = 406644; 
                var b1 = 3293161072;       
                var jd = "."; 
                var $b = "+-a^+6"; 
                var Zb = "+-3^+b+-f";    
                for (var e = [], f = 0, g = 0; g < a.length; g++) { 
                    var m = a.charCodeAt(g); 
                    128 > m ? e[f++] = m : (2048 > m ? e[f++] = m >> 6 | 192 : (55296 == (m & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (m = 65536 + ((m & 1023) << 10) + (a.charCodeAt(++g) & 1023), 
                    e[f++] = m >> 18 | 240, 
                    e[f++] = m >> 12 & 63 | 128) : e[f++] = m >> 12 | 224, 
                    e[f++] = m >> 6 & 63 | 128), 
                    e[f++] = m & 63 | 128) 
                } 
                a = b; 
                for (f = 0; f < e.length; f++) a += e[f], 
                a = RL(a, $b); 
                a = RL(a, Zb); 
                a ^= b1 || 0; 
                0 > a && (a = (a & 2147483647) + 2147483648); 
                a %= 1E6; 
                return a.toString() + jd + (a ^ b) 
            };      
            function RL(a, b) { 
                var t = "a"; 
                var Yb = "+"; 
                for (var c = 0; c < b.length - 2; c += 3) { 
                    var d = b.charAt(c + 2), 
                    d = d >= t ? d.charCodeAt(0) - 87 : Number(d), 
                    d = b.charAt(c + 1) == Yb ? a >>> d: a << d; 
                    a = b.charAt(c) == Yb ? a + d & 4294967295 : a ^ d 
                } 
                return a 
            }
        """)

    def get_tk(self, text):
        return self.ctx.call("TL", text)


def build_url(text, tk, tl='zh-CN'):
    """
    需要用转URLEncoder
    :param text:
    :param tk:
    :param tl:
    :return:
    """
    return 'https://translate.google.cn/translate_a/single?client=webapp&sl=auto&tl=' + tl + '&hl=zh-CN&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&source=btn&ssel=0&tsel=0&kc=0&tk=' \
           + str(tk) + '&q=' + quote(text, encoding='utf-8')


def translate(js, text, tl='zh-CN'):
    """
    tl为要翻译的语言
    de:德语
    ja:日语
    sv:瑞典语
    nl:荷兰语
    ar:阿拉伯语
    ko:韩语
    pt:葡萄牙语
    zh-CN:中文简体
    zh-TW:中文繁体
    """

    header = {
        'authority': 'translate.google.cn',
        'method': 'GET',
        'path': '',
        'scheme': 'https',
        'accept': '*/*',
        'accept-encoding': 'gzip, deflate, br',
        'accept-language': 'zh-CN,zh;q=0.9,ja;q=0.8',
        # 'cookie': '_ga=GA1.3.110668007.1547438795; _gid=GA1.3.791931751.1548053917; 1P_JAR=2019-1-23-1; NID=156=biJbQQ3j2gPAJVBfdgBjWHjpC5m9vPqwJ6n6gxTvY8n1eyM8LY5tkYDRsYvacEnWNtMh3ux0-lUJr439QFquSoqEIByw7al6n_yrHqhFNnb5fKyIWMewmqoOJ2fyNaZWrCwl7MA8P_qqPDM5uRIm9SAc5ybSGZijsjalN8YDkxQ',
         'cookie':'_ga=GA1.3.110668007.1547438795; _gid=GA1.3.1522575542.1548327032; 1P_JAR=2019-1-24-10; NID=156=ELGmtJHel1YG9Q3RxRI4HTgAc3l1n7Y6PAxGwvecTJDJ2ScgW2p-CXdvh88XFb9dTbYEBkoayWb-2vjJbB-Rhf6auRj-M-2QRUKdZG04lt7ybh8GgffGtepoA4oPN9OO9TeAoWDY0HJHDWCUwCpYzlaQK-gKCh5aVC4HVMeoppI',
        # 'cookie': '',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64)  AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36',
        'x-client-data': 'CKi1yQEIhrbJAQijtskBCMG2yQEIqZ3KAQioo8oBCL+nygEI7KfKAQjiqMoBGPmlygE='
    }
    url = build_url(text, js.get_tk(text), tl)
    res = []
    try:
        r = requests.get(url, headers=header)
        result = json.loads(r.text)
        r.encoding = "UTF-8"
        if debug:
            print(r.url)
            print(r.headers)
            print(r.request.headers)
            print(result)

        res = result[0]
        if res is None:
            if result[7] is not None:
                # 如果我们文本输错,提示你是不是要找xxx的话,那么重新把xxx正确的翻译之后返回
                try:
                    correct_text = result[7][0].replace('', ' ').replace('', '')
                    if debug:
                        print(correct_text)
                    correct_url = build_url(correct_text, js.get_tk(correct_text), tl)
                    correct_response = requests.get(correct_url)
                    correct_result = json.loads(correct_response.text)
                    res = correct_result[0]
                except Exception as e:
                    if debug:
                        print(e)
                    res = []

    except Exception as e:
        res = []
        if debug:
            print(url)
            print("翻译" + text + "失败")
            print("错误信息:")
            print(e)
    finally:
        return res


def get_translate(word, tl):
    js = Py4Js()
    translate_result = translate(js, word, tl)

    if debug:
        print("word== %s, tl== %s" % (word, tl))
        print(translate_result)
    return translate_result


if __name__ == '__main__':
    debug = True
    translate_text = '3.Hear voice prompt \"start configuration mode\". click \"reset successfully\" button\n'
    results = get_translate(translate_text, 'cs')
    translate_result = ""

    if "." in translate_text or "?" in translate_text:
        for result in results:
            translate_result += result[0]
    else:
        result_translate = results[0]

    if debug:
        print("translate_result:" + translate_result)

其中: tl 是要进行翻译的其它国家语言的缩写

遇到的问题

1.由于需要翻译上千条字段,于是开启多线程翻译,并且每次请求间隔很短,导致很多请求超时
想到的解决方式是:每次请求翻译尽量多的字段

2.在翻译多个字段的时候,返回的子列表比要翻译的字段多,如:

'3.Hear voice prompt \"start configuration mode\". click \"reset successfully\" button\n'

该字符串中在APP中是一个字段,但是包含两个句子,因为中间包含英文句号’.’,其返回结果

[
['3. Hlasová výzva "start konfigurační režim". ', '3.Hear voice prompt "start configuration mode".', None, None, 3], 
['klikněte na tlačítko "obnovit úspěšně"', 'click "reset successfully" button', None, None, 3]
]

备注:最内层的每个列表(一个列表表示一句)就是翻译结果,列表的第1项为翻译结果,第2项为对应要翻译的内容。

因此,遇到有多个句子的字段需要单独翻译

备注:英文句号“.”,问号“?”,换行符“\n”,都会导致返回结果,因此猜测,其它分割语句的符号也是,但是目前脚本没有做其它分割语句的处理。

3.翻译结果符号问题
3.1 莫名多出空格,如:格式化字符串 %d会在中间多出空格:% d,/前后会多出空格等
3.2 要在Android 资源文件中使用,需要注意翻译结果是否出现单引号,出现单引号需要加斜杠’'处理,如果需要显示双引号,也需要加斜杠处理。

附脚本

脚本
该脚本翻译内容从Excel获取,然后将结果放到另一个Excel中。

参考:

利用python调用谷歌翻译API

你可能感兴趣的:(python)