手把手教你用 Python 腳本調用 DeepL API Pro 進電子書的行進行中英文自動翻譯
大家好,我是我是Python進階者。
一、前言
前幾天有個叫【張茜】的粉絲找我看了一個代碼,關于電子書中英文自動翻譯的,感覺挺有意思,這里拿出來給大家分享下。
二、簡介
這個小項目是git上一個叫【xiaolai】的大佬分享的,看上去還是挺新的,發布不太久,14天前發布的。
一本書中文譯文大約 39 萬字的書,差不多用 1.5 小時就可以處理完畢(包括基本的格式編輯),這速度恐怖如斯!下面一起來看看這款神器的使用方法吧!
三、電子書格式轉換路徑
首先,需要將電子書從 Kindle 中導出來,并用 ePubor 進行 deDRM,而后將電子書轉換成 epub 文件。
我都是在 Amazon 上直接買,而后在電腦上安裝一個老版本的 Kindle App,用鼠標右鍵點擊書名,下載,并不打開該電子書,而后退出 Kindle。
ePubor Ultimate 也是個收費軟件,能把舊版 Kindle 下載的電子書的 DRM 去掉;將 awz 文件轉換成 epub 文件。(可參考這個網頁)
然后,再用免費軟件 Calibre 將 epub 轉換成 htmlz 文件(一個壓縮包)。(我嘗試過使用命令行工具包 pandoc,但,比較之后,發現 Calibre 在保留樣式方面可能更好一點……)
在 Terminal 里用 unzip 命令解開 htmlz 壓縮包。
四、選擇 html 格式作為翻譯格式的原因
可以保留書中大量的腳注、尾注及其鏈接;DeepL 有專門的 API 參數處理 xml tag,tag_handling="xml";
可以通過 css 文件隨意設置顯示樣式,比較靈活;
可以通過插入 javascript 函數指定某種特定語言的顯示(比如,只顯示中文);
可以用來作為源文件轉換成任意格式的電子書……
另外,在調用 tag_handling="xml" 之后,DeepL API 返回的譯文非常規整,能夠保留所有 html tag;并且,“返回字符串” 與 “原字符串” 相同,可以作為一個判斷依據 —— 該行有沒有被翻譯,如果沒有,在生成的譯文 html 文件中,該行沒必要重復出現……
五、清理 html
html 文件整理起來比較麻煩,一個比較方便的手段是使用 BeautifulSoup 模塊。BeautifulSoup 本來是爬蟲工具,但,它又很方便的手段可以清理 html 文件。
以下腳本主要完成以下工作:
首先將 html 文件里的所有 \n 去掉;將所有
單獨放在一行;將所有
也單獨放在一行;將
內部的所有 \n 全都去掉;并在之前加上一個空行;…… 當然,你可以在這里做更多你自己喜歡做的格式清理。為了方便起見,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 進行翻譯
將清理過的 html 交給以下腳本,逐行提交給 DeepL 翻譯,并返回。
為了方便起見,path 和 source_filename 以及 target_filename 都單獨指定。
lines 是 source_filename 的內容 new_lines 是將要放到 target_filename 中的內容 startline 是 “從哪一行開始提交 DeepL 翻譯” endline 是 “到哪一行開始結束提交 DeepL 翻譯”。代碼如下:
- import re
- import requests
- auth_key = "<your DeepL API Pro authentication key>" # 注意,要訂閱的是 DeepL API Pro
- target_language = "ZH" ## 當然,你可以將目標語言設置成任何 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", # 這個參數確保 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,用來防止執行過程中出現 DeepL 連接錯誤而導致翻譯任務中斷……
- try:
- line_translated = translate(line)
- # 以下一行確保將返回的字符串轉換成一整行,而非含有 \n 的多行文本
- line_translated = line_translated.replace("\n", "")
- succeeded = True
- except:
- succeeded = False
- if line.strip() == line_translated.strip():
- #返回的字符串與原字符串相同,說明 html tag 之間的內容無需翻譯
- 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))
七、結果展示
1、運行代碼之后,會自動讀取待翻譯的文件,然后進行翻譯,如下圖所示:
2、運行完程序之后,可以得到想要的結果,如下圖所示:
八、總結
大家好,我是Python進階者。這篇文章主要給大家介紹了使用Python腳本調用DeepL API Pro進電子書的行中英文自動翻譯的方法,代碼親測可行,歡迎大家積極嘗試,下次再遇到需要自動翻譯的時候,不妨調用下這個API,興許事半功倍呢!