手把手教你用 Python 腳本調(diào)用 DeepL API Pro 進(jìn)電子書的行進(jìn)行中英文自動翻譯
大家好,我是我是Python進(jìn)階者。
一、前言
前幾天有個叫【張茜】的粉絲找我看了一個代碼,關(guān)于電子書中英文自動翻譯的,感覺挺有意思,這里拿出來給大家分享下。
二、簡介
這個小項目是git上一個叫【xiaolai】的大佬分享的,看上去還是挺新的,發(fā)布不太久,14天前發(fā)布的。
一本書中文譯文大約 39 萬字的書,差不多用 1.5 小時就可以處理完畢(包括基本的格式編輯),這速度恐怖如斯!下面一起來看看這款神器的使用方法吧!
三、電子書格式轉(zhuǎn)換路徑
首先,需要將電子書從 Kindle 中導(dǎo)出來,并用 ePubor 進(jìn)行 deDRM,而后將電子書轉(zhuǎn)換成 epub 文件。
我都是在 Amazon 上直接買,而后在電腦上安裝一個老版本的 Kindle App,用鼠標(biāo)右鍵點擊書名,下載,并不打開該電子書,而后退出 Kindle。
ePubor Ultimate 也是個收費軟件,能把舊版 Kindle 下載的電子書的 DRM 去掉;將 awz 文件轉(zhuǎn)換成 epub 文件。(可參考這個網(wǎng)頁)
然后,再用免費軟件 Calibre 將 epub 轉(zhuǎn)換成 htmlz 文件(一個壓縮包)。(我嘗試過使用命令行工具包 pandoc,但,比較之后,發(fā)現(xiàn) Calibre 在保留樣式方面可能更好一點……)
在 Terminal 里用 unzip 命令解開 htmlz 壓縮包。
四、選擇 html 格式作為翻譯格式的原因
可以保留書中大量的腳注、尾注及其鏈接;DeepL 有專門的 API 參數(shù)處理 xml tag,tag_handling="xml";
可以通過 css 文件隨意設(shè)置顯示樣式,比較靈活;
可以通過插入 javascript 函數(shù)指定某種特定語言的顯示(比如,只顯示中文);
可以用來作為源文件轉(zhuǎn)換成任意格式的電子書……
另外,在調(diào)用 tag_handling="xml" 之后,DeepL API 返回的譯文非常規(guī)整,能夠保留所有 html tag;并且,“返回字符串” 與 “原字符串” 相同,可以作為一個判斷依據(jù) —— 該行有沒有被翻譯,如果沒有,在生成的譯文 html 文件中,該行沒必要重復(fù)出現(xiàn)……
五、清理 html
html 文件整理起來比較麻煩,一個比較方便的手段是使用 BeautifulSoup 模塊。BeautifulSoup 本來是爬蟲工具,但,它又很方便的手段可以清理 html 文件。
以下腳本主要完成以下工作:
首先將 html 文件里的所有 \n 去掉;將所有
單獨放在一行;將所有
也單獨放在一行;將
內(nèi)部的所有 \n 全都去掉;并在之前加上一個空行;…… 當(dāng)然,你可以在這里做更多你自己喜歡做的格式清理。為了方便起見,path 和 source_filename 以及 target_filename 都單獨指定。代碼如下:
- import bs4
- import re
- path = "John Law/" # 文件夾名稱末尾得有 /
- source_filename = "index.html"
- target_filename = "index2.html"
- html = open(path+source_filename)
- htmltext = html.read()
- soup = bs4.BeautifulSoup(htmltext)
- # 將所有的 \n 去掉……
- htmltext = str(bs4.BeautifulSoup(htmltext)).replace("\n", "")
- # <h... 之前添加空行
- pttn = r'<h'
- rpl = r'\n\n<h'
- re.findall(pttn, htmltext)
- htmltext = re.sub(pttn, rpl, htmltext)
- # <div... 之前添加空行
- pttn = r'<div'
- rpl = r'\n\n<div'
- re.findall(pttn, htmltext)
- htmltext = re.sub(pttn, rpl, htmltext)
- # </div> 之前添加空行
- pttn = r'</div>'
- rpl = r'\n\n</div>'
- re.findall(pttn, htmltext)
- htmltext = re.sub(pttn, rpl, htmltext)
- # <p... 之前添加空行
- pttn = r'<p'
- rpl = r'\n\n<p'
- re.findall(pttn, htmltext)
- htmltext = re.sub(pttn, rpl, htmltext)
- fileSave = open(path+target_filename, "w")
- fileSave.write(htmltext)
- print(htmltext)
六、逐行提交 DeepL API Pro 進(jìn)行翻譯
將清理過的 html 交給以下腳本,逐行提交給 DeepL 翻譯,并返回。
為了方便起見,path 和 source_filename 以及 target_filename 都單獨指定。
lines 是 source_filename 的內(nèi)容 new_lines 是將要放到 target_filename 中的內(nèi)容 startline 是 “從哪一行開始提交 DeepL 翻譯” endline 是 “到哪一行開始結(jié)束提交 DeepL 翻譯”。代碼如下:
- import re
- import requests
- auth_key = "<your DeepL API Pro authentication key>" # 注意,要訂閱的是 DeepL API Pro
- target_language = "ZH" ## 當(dāng)然,你可以將目標(biāo)語言設(shè)置成任何 DeepL 支持的語言
- path = "John Law/" # 文件夾名稱末尾得有 /
- source_filename = "index2.html" # 上一步生成的文件,成為這一步的 “源文件”
- target_filename = "index3.html"
- def translate(text):
- result = requests.get(
- "https://api.deepl.com/v2/translate",
- params={
- "auth_key": auth_key,
- "target_lang": target_language,
- "text": text,
- "tag_handling": "xml", # 這個參數(shù)確保 DeepL 正確處理 html tags
- },
- )
- return result.json()["translations"][0]["text"]
- def add_language_tag_en(html):
- pttn = re.compile(r'^<(.*?) class="(.*?)">', re.M)
- rpl = r'<\1 class="\2 en">'
- re.findall(pttn, html)
- html = re.sub(pttn, rpl, html)
- return html
- def add_language_tag_cn(html):
- pttn = re.compile(r'^<(.*?) class="(.*?)">', re.M)
- rpl = r'<\1 class="\2 cn">'
- re.findall(pttn, html)
- html = re.sub(pttn, rpl, html)
- return html
- lines = open(path+source_filename, "r").readlines()
- new_lines = []
- line_count = 0
- startline = 16
- endline = 4032
- for line in lines:
- line_count += 1
- if line_count < startline or line_count > endline or line.strip() == '':
- new_lines.append(line)
- print(line)
- continue
- succeeded = False
- while not succeeded:
- # 以下比較粗暴的 try... except,用來防止執(zhí)行過程中出現(xiàn) DeepL 連接錯誤而導(dǎo)致翻譯任務(wù)中斷……
- try:
- line_translated = translate(line)
- # 以下一行確保將返回的字符串轉(zhuǎn)換成一整行,而非含有 \n 的多行文本
- line_translated = line_translated.replace("\n", "")
- succeeded = True
- except:
- succeeded = False
- if line.strip() == line_translated.strip():
- #返回的字符串與原字符串相同,說明 html tag 之間的內(nèi)容無需翻譯
- new_lines.append(line)
- print(line)
- else:
- line = add_language_tag_en(line)
- line_translated = add_language_tag_cn(line_translated)
- new_lines.append(line)
- print(line)
- new_lines.append(line_translated)
- print(line_translated)
- with open(path+target_filename, 'w') as f:
- f.write("\n".join(new_lines))
七、結(jié)果展示
1、運行代碼之后,會自動讀取待翻譯的文件,然后進(jìn)行翻譯,如下圖所示:
2、運行完程序之后,可以得到想要的結(jié)果,如下圖所示:
八、總結(jié)
大家好,我是Python進(jìn)階者。這篇文章主要給大家介紹了使用Python腳本調(diào)用DeepL API Pro進(jìn)電子書的行中英文自動翻譯的方法,代碼親測可行,歡迎大家積極嘗試,下次再遇到需要自動翻譯的時候,不妨調(diào)用下這個API,興許事半功倍呢!