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('<b><i>', ' ').replace('</i></b>', '')
                    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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章