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装饰器decorator介绍
Nov 21 Python
python监控文件或目录变化
Jun 07 Python
Python3 socket同步通信简单示例
Jun 07 Python
Django 使用logging打印日志的实例
Apr 28 Python
Python3爬虫教程之利用Python实现发送天气预报邮件
Dec 16 Python
Python爬虫设置代理IP(图文)
Dec 23 Python
详解Python绘图Turtle库
Oct 12 Python
keras .h5转移动端的.tflite文件实现方式
May 25 Python
pytorch随机采样操作SubsetRandomSampler()
Jul 07 Python
python re模块常见用法例举
Mar 01 Python
Python 中数组和数字相乘时的注意事项说明
May 10 Python
Python中的xlrd模块使用整理
Jun 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 Memcache 中实现消息队列
2009/11/24 PHP
PHP empty函数报错解决办法
2014/03/06 PHP
linux中cd命令使用详解
2015/01/08 PHP
laravel学习教程之关联模型
2016/07/30 PHP
JavaScript使用prototype定义对象类型
2007/02/07 Javascript
限制文本框输入N个字符的js代码
2010/05/13 Javascript
js 调用父窗口的具体实现代码
2013/07/15 Javascript
GridView中获取被点击行中的DropDownList和TextBox中的值
2013/07/18 Javascript
Jquery插件实现点击获取验证码后60秒内禁止重新获取
2015/03/13 Javascript
js实现支持手机滑动切换的轮播图片效果实例
2015/04/29 Javascript
js实现非常简单的焦点图切换特效实例
2015/05/07 Javascript
jQuery插件简单实现方法
2015/07/18 Javascript
jQuery实现下拉框选择图片功能实例
2015/08/08 Javascript
js实现input框文字动态变换显示效果
2015/08/19 Javascript
js鼠标点击图片切换效果代码分享
2015/08/26 Javascript
JS中用try catch对代码运行的性能影响分析
2016/12/26 Javascript
微信小程序 Button 组件详解及简单实例
2017/01/10 Javascript
jQuery.cookie.js实现记录最近浏览过的商品功能示例
2017/01/23 Javascript
Easyui在treegrid添加控件的实现方法
2017/06/23 Javascript
深入理解Node module模块
2018/03/26 Javascript
详解ES6中的 Set Map 数据结构学习总结
2018/11/06 Javascript
深入了解query和params的使用区别
2019/06/24 Javascript
django 自定义用户user模型的三种方法
2014/11/18 Python
python如何把嵌套列表转变成普通列表
2018/03/20 Python
python如何获取列表中每个元素的下标位置
2019/07/01 Python
numpy.array 操作使用简单总结
2019/11/08 Python
Python3+Selenium+Chrome实现自动填写WPS表单
2020/02/12 Python
python实现数字炸弹游戏
2020/07/17 Python
pytorch中index_select()的用法详解
2021/01/06 Python
python Matplotlib基础--如何添加文本和标注
2021/01/26 Python
IE滤镜与CSS3效果(详细整理分享)
2013/01/25 HTML / CSS
澳大利亚领先的运动鞋商店:Hype DC
2018/03/31 全球购物
俄罗斯宠物用品网上商店:ZooMag
2019/12/12 全球购物
助学感谢信范文
2015/01/21 职场文书
Go 语言下基于Redis分布式锁的实现方式
2021/06/28 Golang
MySQL的存储过程和相关函数
2022/04/26 MySQL