Python 实现的 Google 批量翻译功能


Posted in Python onAugust 26, 2019

首先声明,没有什么不良动机,因为经常会用 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 requests
import re
import json
import time
class 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 time
from GoogleTranslator import GoogleTranslator
def 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 paragraph
main.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 相关文章推荐
使用Python的Tornado框架实现一个Web端图书展示页面
Jul 11 Python
Python基于Socket实现的简单聊天程序示例
Aug 05 Python
python、java等哪一门编程语言适合人工智能?
Nov 13 Python
python pandas中对Series数据进行轴向连接的实例
Jun 08 Python
Python实现简单石头剪刀布游戏
Jan 20 Python
对python dataframe逻辑取值的方法详解
Jan 30 Python
Python学习笔记基本数据结构之序列类型list tuple range用法分析
Jun 08 Python
Python全栈之列表数据类型详解
Oct 01 Python
Python单元测试与测试用例简析
Nov 09 Python
python-numpy-指数分布实例详解
Dec 07 Python
Python 如何定义匿名或内联函数
Aug 01 Python
Python二元算术运算常用方法解析
Sep 15 Python
python自动化工具之pywinauto实例详解
Aug 26 #Python
Python3简单爬虫抓取网页图片代码实例
Aug 26 #Python
python 数据提取及拆分的实现代码
Aug 26 #Python
Python3 使用pillow库生成随机验证码
Aug 26 #Python
python excel转换csv代码实例
Aug 26 #Python
对YOLOv3模型调用时候的python接口详解
Aug 26 #Python
pandas条件组合筛选和按范围筛选的示例代码
Aug 26 #Python
You might like
php数据库连接时容易出错的特殊符号问题
2010/09/01 PHP
比较详细PHP生成静态页面教程
2012/01/10 PHP
PHP实现算式验证码和汉字验证码实例
2015/03/09 PHP
phpStudy中升级MySQL版本到5.7.17的方法步骤
2017/08/03 PHP
php实现微信发红包功能
2018/07/13 PHP
YII框架模块化处理操作示例
2019/04/26 PHP
laradock环境docker-compose操作详解
2019/07/29 PHP
javascript的trim,ltrim,rtrim自定义函数
2008/09/21 Javascript
javascript 树形导航菜单实例代码
2013/08/13 Javascript
JS获取各种浏览器窗口大小的方法
2014/01/14 Javascript
EasyUI中combobox默认值注意事项
2015/03/01 Javascript
javascript实时获取鼠标坐标值并显示的方法
2015/04/30 Javascript
详解js运算符单竖杠“|”与“||”的用法和作用介绍
2016/11/04 Javascript
html判断当前页面是否在iframe中的实例
2016/11/30 Javascript
Vue下的国际化处理方法
2017/12/18 Javascript
微信小程序实现获取小程序码和二维码java接口开发
2019/03/29 Javascript
详解Vue后台管理系统开发日常总结(组件PageHeader)
2019/11/01 Javascript
微信小程序swiper组件实现抖音翻页切换视频功能的实例代码
2020/06/24 Javascript
React中使用Vditor自定义图片详解
2020/12/25 Javascript
pygame学习笔记(1):矩形、圆型画图实例
2015/04/15 Python
Python设计模式之命令模式简单示例
2018/01/10 Python
Django项目中model的数据处理以及页面交互方法
2018/05/30 Python
Python在cmd上打印彩色文字实现过程详解
2019/08/07 Python
Python面向对象之Web静态服务器
2019/09/03 Python
土耳其时尚潮流在线购物网站:Trendyol
2017/10/10 全球购物
车间班长岗位职责
2013/11/30 职场文书
元旦晚会邀请函
2014/02/01 职场文书
水毁工程实施方案
2014/04/01 职场文书
法制宣传日活动总结
2014/04/29 职场文书
处级领导班子全部召开专题民主生活会情况汇报
2014/09/27 职场文书
护士长2014年终工作总结
2014/11/11 职场文书
丽江古城导游词
2015/02/03 职场文书
爱心捐书倡议书
2015/04/27 职场文书
2016年社区综治宣传月活动总结
2016/03/16 职场文书
浅谈Java父子类加载顺序
2021/08/04 Java/Android
Java异常体系非正常停止和分类
2022/06/14 Java/Android