侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Python 实现的 Google 批量翻译功能

Python  /  管理员 发布于 8年前   328

首先声明,没有什么不良动机,因为经常会用 translate.google.cn,就想着用 Python 模拟网页提交实现文档的批量翻译。据说有 API,可是要收费。

生成 Token

Google 为防爬虫而生成 token 的代码是 Javascript 的,且是根据网站的 TKK 值和提交的文本动态生成。更新规律未知,只好定时去取一下了。

网上能找到的 Python 代码大部分是去调用 PyExecJS 库,先不说执行效率的高低(大概是差一个数量级),首先是舍近求远,不纯粹,本人不喜欢。

好不容易找到了一段 Python 代码还有点小 Bug,且缺少动态获取 TKK 的步骤。最后还是对照 Javascript 代码自己改成 Python 了。方法很简单,先转成易懂的 Javascript,再转成 Python。Javascript 代码来自C#实现谷歌翻译API。

原始(晦涩) Javascript 代码

var b = function (a, b) { for (var d = 0; d < b.length - 2; d += 3) { var c = b.charAt(d + 2),  c = "a" <= c ? c.charCodeAt(0) - 87 : Number(c),  c = "+" == b.charAt(d + 1) ? a >>> c : a << c; a = "+" == b.charAt(d) ? a + c & 4294967295 : a ^ c } return a}var tk = function (a,TKK) { for (var e = TKK.split("."), h = Number(e[0]) || 0, g = [], d = 0, f = 0; f < a.length; f++) { var c = a.charCodeAt(f); 128 > c ? g[d++] = c : (2048 > c ? g[d++] = c >> 6 | 192 : (55296 == (c & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ? (c = 65536 + ((c & 1023) << 10) + (a.charCodeAt(++f) & 1023), g[d++] = c >> 18 | 240, g[d++] = c >> 12 & 63 | 128) : g[d++] = c >> 12 | 224, g[d++] = c >> 6 & 63 | 128), g[d++] = c & 63 | 128) } a = h; for (d = 0; d < g.length; d++) a += g[d], a = b(a, "+-a^+6"); a = b(a, "+-3^+b+-f"); a ^= Number(e[1]) || 0; 0 > a && (a = (a & 2147483647) + 2147483648); a %= 1E6; return a.toString() + "." + (a ^ h)}

易懂的 Javascript 代码

function RL(a, b) { for (var d = 0; d < b.length - 2; d += 3) { var c = b.charAt(d + 2); c = "a" <= c ? c.charCodeAt(0) - 87 : Number(c); c = "+" == b.charAt(d + 1) ? a >>> c : a << c; a = "+" == b.charAt(d) ? a + c & 4294967295 : a ^ c; } return a}function TL(a,TKK) { var e = TKK.split("."); var h = Number(e[0]) || 0; var g = []; var d = 0; for (var f = 0; f < a.length; f++) { var c = a.charCodeAt(f); if (128 > c) {  g[d++] = c; }  else {  if (2048 > c)  {  g[d++] = c >> 6 | 192;  }  else  {  if (55296 == (c & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512))  {   c = 65536 + ((c & 1023) << 10) + (a.charCodeAt(++f) & 1023);   g[d++] = c >> 18 | 240;   g[d++] = c >> 12 & 63 | 128;  }  else  {   g[d++] = c >> 12 | 224;   g[d++] = c >> 6 & 63 | 128;  }  }  g[d++] = c & 63 | 128; } } a = h; for (var d = 0; d < g.length; d++) { a += g[d]; a = b(a, "+-a^+6"); } a = b(a, "+-3^+b+-f"); a ^= Number(e[1]) || 0; 0 > a && (a = (a & 2147483647) + 2147483648); a %= 1E6; return a.toString() + "." + (a ^ h)}

Python 代码

def getGoogleToken(a, TKK): def RL(a, b): for d in range(0, len(b)-2, 3):  c = b[d + 2]  c = ord(c[0]) - 87 if 'a' <= c else int(c)  c = a >> c if '+' == b[d + 1] else a << c  a = a + c & 4294967295 if '+' == b[d] else a ^ c return a g = [] f = 0 while f < len(a): c = ord(a[f]) if 128 > c:  g.append(c) else:  if 2048 > c:  g.append((c >> 6) | 192)  else:  if (55296 == (c & 64512)) and (f + 1 < len(a)) and (56320 == (ord(a[f+1]) & 64512)):   f += 1   c = 65536 + ((c & 1023) << 10) + (ord(a[f]) & 1023)   g.append((c >> 18) | 240)   g.append((c >> 12) & 63 | 128)  else:   g.append((c >> 12) | 224)   g.append((c >> 6) & 63 | 128)  g.append((c & 63) | 128) f += 1 e = TKK.split('.') h = int(e[0]) or 0 t = h for item in g: t += item t = RL(t, '+-a^+6') t = RL(t, '+-3^+b+-f') t ^= int(e[1]) or 0 if 0 > t: t = (t & 2147483647) + 2147483648 result = t % 1000000 return str(result) + '.' + str(result ^ h)

获取 Token Key

Google 的 TKK 可以通过访问网站 https://translate.google.cn 获取,里面有段脚本里包含了“tkk:('xxxxxx.xxxxxx')”,用正则表达式截取即可。

res = requests.get('https://translate.google.cn', timeout = 3) res.raise_for_status() result = re.search(r'tkk\:\'(\d+\.\d+)?\'', res.text).group(1)

划分文章段落

因为常从 PDF 里复制文本翻译,这样就不能依赖换行符来划分段落了。只能判断空行,作为段落的分界。

另外 Google 返回的结果 Json 里,会以英文句点作为分隔符,每一句译文均作为数组的一项分开。所以最后得合并一下,成为一个段落。

完整代码

代码不长,全文黏贴如下。

GoogleTranslator.py:import requestsimport reimport jsonimport timeclass GoogleTranslator (): _host = 'translate.google.cn' _headers = { 'Host': _host, 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Mobile Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8', 'Referer': 'https://' + _host, 'Connection': 'keep-alive', 'Cache-Control': 'max-age=0' } _language = { 'afrikaans': 'af', 'arabic': 'ar', 'belarusian': 'be', 'bulgarian': 'bg', 'catalan': 'ca', 'czech': 'cs', 'welsh': 'cy', 'danish': 'da', 'german': 'de', 'greek': 'el', 'english': 'en', 'esperanto': 'eo', 'spanish': 'es', 'estonian': 'et', 'persian': 'fa', 'finnish': 'fi', 'french': 'fr', 'irish': 'ga', 'galician': 'gl', 'hindi': 'hi', 'croatian': 'hr', 'hungarian': 'hu', 'indonesian': 'id', 'icelandic': 'is', 'italian': 'it', 'hebrew': 'iw', 'japanese': 'ja', 'korean': 'ko', 'latin': 'la', 'lithuanian': 'lt', 'latvian': 'lv', 'macedonian': 'mk', 'malay': 'ms', 'maltese': 'mt', 'dutch': 'nl', 'norwegian': 'no', 'polish': 'pl', 'portuguese': 'pt', 'romanian': 'ro', 'russian': 'ru', 'slovak': 'sk', 'slovenian': 'sl', 'albanian': 'sq', 'serbian': 'sr', 'swedish': 'sv', 'swahili': 'sw', 'thai': 'th', 'filipino': 'tl', 'turkish': 'tr', 'ukrainian': 'uk', 'vietnamese': 'vi', 'yiddish': 'yi', 'chinese_simplified': 'zh-CN', 'chinese_traditional': 'zh-TW', 'auto': 'auto' } _url = 'https://' + _host + '/translate_a/single' _params = {  'client': 'webapp',  'sl': 'en',  'tl': 'zh-CN',  'hl': 'zh-CN',  'dt': 'at',  'dt': 'bd',  'dt': 'ex',  'dt': 'ld',  'dt': 'md',  'dt': 'qca',  'dt': 'rw',  'dt': 'rm',  'dt': 'ss',  'dt': 't',  'otf': '1',  'ssel': '0',  'tsel': '0',  'kc': '1' } __cookies = None __googleTokenKey = '376032.257956' __googleTokenKeyUpdataTime = 600.0 __googleTokenKeyRetireTime = time.time() + 600.0 def __init__(self, src = 'en', dest = 'zh-CN', tkkUpdataTime = 600.0): if src not in self._language and src not in self._language.values():  src = 'auto' if dest not in self._language and dest not in self._language.values():  dest = 'auto' self._params['sl'] = src self._params['tl'] = dest self.googleTokenKeyUpdataTime = tkkUpdataTime self.__updateGoogleTokenKey() def __updateGoogleTokenKey(self): self.__googleTokenKey = self.__getGoogleTokenKey() self.__googleTokenKeyRetireTime = time.time() + self.__googleTokenKeyUpdataTime def __getGoogleTokenKey(self): """Get the Google TKK from https://translate.google.cn""" # TKK example: '435075.3634891900' result = '' try:  res = requests.get('https://' + self._host, timeout = 3)  res.raise_for_status()  self.__cookies = res.cookies  result = re.search(r'tkk\:\'(\d+\.\d+)?\'', res.text).group(1) except requests.exceptions.ReadTimeout as ex:  print('ERROR: ' + str(ex))  time.sleep(1) return result def __getGoogleToken(self, a, TKK): """Calculate Google tk from TKK """ # https://www.cnblogs.com/chicsky/p/7443830.html # if text = 'Tablet Developer' and TKK = '435102.3120524463', then tk = '315066.159012' def RL(a, b):  for d in range(0, len(b)-2, 3):  c = b[d + 2]  c = ord(c[0]) - 87 if 'a' <= c else int(c)  c = a >> c if '+' == b[d + 1] else a << c  a = a + c & 4294967295 if '+' == b[d] else a ^ c  return a g = [] f = 0 while f < len(a):  c = ord(a[f])  if 128 > c:  g.append(c)  else:  if 2048 > c:   g.append((c >> 6) | 192)  else:   if (55296 == (c & 64512)) and (f + 1 < len(a)) and (56320 == (ord(a[f+1]) & 64512)):   f += 1   c = 65536 + ((c & 1023) << 10) + (ord(a[f]) & 1023)   g.append((c >> 18) | 240)   g.append((c >> 12) & 63 | 128)   else:   g.append((c >> 12) | 224)   g.append((c >> 6) & 63 | 128)  g.append((c & 63) | 128)  f += 1 e = TKK.split('.') h = int(e[0]) or 0 t = h for item in g:  t += item  t = RL(t, '+-a^+6') t = RL(t, '+-3^+b+-f') t ^= int(e[1]) or 0 if 0 > t:  t = (t & 2147483647) + 2147483648 result = t % 1000000 return str(result) + '.' + str(result ^ h) def translate(self, text): if time.time() > self.__googleTokenKeyRetireTime:  self.__updateGoogleTokenKey() data = {'q': text} self._params['tk'] = self.__getGoogleToken(text, self.__googleTokenKey) result = '' try:  res = requests.post(self._url,    headers = self._headers,    cookies = self.__cookies,    data = data,    params = self._params,    timeout = 6)  res.raise_for_status()  jsonText = res.text  if len(jsonText)>0:  jsonResult = json.loads(jsonText)  if len(jsonResult[0])>0:   for item in jsonResult[0]:   result += item[0]  return result except Exception as ex:  print('ERROR: ' + str(ex))  return ''import timefrom GoogleTranslator import GoogleTranslatordef readFile(fileName): with open(fileName, 'r') as f: paragraph = '' for line in f:  if line[0]!='\n':  paragraph += line.strip('\n')  else:  if len(paragraph)>0:   yield paragraph   paragraph = '' if len(paragraph)>0:  yield paragraphmain.py:def main(): translator = GoogleTranslator() count = 0 with open('C:\\dx\\python\\d.txt', 'w', encoding='utf-8') as df: for line in readFile('C:\\dx\\python\\s.txt'):  if len(line) > 1:  count += 1  print('\r' + str(count), end = '', flush = True)  df.write(line.strip() + "\n")  result = translator.translate(line)  df.write(result.strip() + "\n\n")if __name__ == "__main__": startTime = time.time() main() print() print('%.2f seconds' % (time.time() - startTime))

总结

以上所述是小编给大家介绍的Python 实现的 Google 批量翻译功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!


  • 上一条:
    Python类中的魔法方法之 __slots__原理解析
    下一条:
    Python3简单爬虫抓取网页图片代码实例
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • AI Agent
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • OpenAI GPT-5.5正式发布:更会编程和使用计算机的最强模型!(0个评论)
    • opencode AI智能体自主规划开发游戏:王者荣耀模拟战游戏初体验!英雄角色开发中...(0个评论)
    • opencode AI智能体自主规划开发游戏:王者荣耀模拟战游戏初体验!(0个评论)
    • opencode + Oh-my-openagent,我的第一个免费的ai编程智能体管家:Sisyphus(0个评论)
    • Google AI Studio升级全栈 vibe coding体验,可直接构建带登录和数据库的应用(0个评论)
    • Apifox桌面端被曝遭供应链投毒:CDN 脚本被篡改,窃取 SSH 密钥与 Git 凭证(0个评论)
    • 在go语言中实现字符串可逆性压缩及解压缩功能(0个评论)
    • 使用go + gin + jwt + qrcode实现网站生成登录二维码在app中扫码登录功能(0个评论)
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 近期评论
    • test1 在

      opencode + Oh-my-openagent,我的第一个免费的ai编程智能体管家:Sisyphus中评论 test..
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • Zita 在

      Google AI Studio升级全栈 vibe coding体验,可直接构建带登录和数据库的应用中评论 111222..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客