最近想要用kindle看些英文原著(《权力的游戏》),但是水平不够,看起来很累,就想找找双语版的,一行英文、一行中文的那种,但是网上几乎找不到。所以就打算自己动手写个python程序,提取英文原著中的每一行英文,翻译后输出在下面。不需要很高的准确率,只要知道大致意思,能够提高我的英文阅读速度就行,所以用机器翻译就可以满足。
我之前用过Google的中文翻英文,觉得比有道、百度不知道高到哪里去,但是今天试了Google、有道、百度三家的英文转中文,感觉都差不多,都不是很准。所以我最终选了有道的,不过API还挺贵的,送了100块钱,估计翻译完一本小说也就差不多了。我发现有直接可以免费使用的API,准确率很低。不过重要的不是API,反正可以随便换,重要的是代码。
整个程序最耗时的操作在调用接口获取翻译上,所以这部分要用多线程。但问题是我需要按照顺序,先输出一行英文,接着在底下输出一行中文,多线程并发是无序的,怎么保证按顺序输出?
我没想到什么高大上的方法,就只好搞两个数组,一个存放原文(这里不考虑内存的问题,一部小说最多也就几M而已),一个存放翻译后的中文,调用函数时传入一个下标作为标志。代码如下:
# -*- coding:utf-8 -*-
# @Time: 2018/8/28 19:13
import requests
import json
import logging
import random
import hashlib
from threading import *
logging.basicConfig(level=logging.INFO)
def translate(q, index, _from='EN', _to='zh_CH'):
url = 'https://openapi.youdao.com/api'
app_key = ''
salt = random.randint(0, 100)
app_secret = ''
data = app_key + q + str(salt) + app_secret
sign = hashlib.md5(data.encode(encoding='UTF-8')).hexdigest()
query_data = {
'q': q,
'from': _from,
'to': _to,
'appKey': app_key,
'salt': salt,
'sign': sign
}
response = requests.get(url, params=query_data).content.decode('utf-8')
logging.debug(response)
translation = json.loads(response)['translation'][0]
trans_list.insert(index, translation)
logging.debug("序号" + str(index) + "的翻译结果:" + translation)
return translation
def readFromFile(file):
with open(file) as f:
origin_list = [line for line in f]
return origin_list
if __name__ == '__main__':
trans_list = []
threads = []
origin_list = readFromFile('GameOfThrones.txt')
# for i in range(0,len(origin_list)):
for i in range(0, 100):
if origin_list[i] == '\n':
trans_list.insert(i, '\n')
continue
t = Thread(target=translate, args=(origin_list[i], i))
t.start()
threads.append(t)
for t in threads:
t.join()
f = open('GameOfThronesDualLanguage.txt', 'w')
for i in range(0, len(trans_list)):
logging.debug(origin_list[i])
f.write(origin_list[i])
if trans_list[i] == '\n':
continue
logging.debug(" " + trans_list[i])
f.write(" " + trans_list[i])
f.close()
运行结果
现在总结下多线程的一些知识(不定期更新):
- join()函数可使主线程进入阻塞状态,即子线程结束后主线程才会进行下一步操作。我刚开始没有使用threads数组,没有给每个线程设置join(),导致直接运行时打印的trans_list为空,因为子线程们还没产生结果程序就运行完了。
- setDaemon(True)可以理解为和join()相反,当父线程(进程)结束后子线程会跟着结束。言下之意就是setDaemon(False)即便父线程退出,子线程仍在运行
网友评论