天天看點

手把手教你用Python腳本調用 DeepL API Pro 進電子書的行進行中英文自動翻譯

大家好,我是我是Python進階者。

一、前言

前幾天有個叫【張茜】的粉絲找我看了一個代碼,關于電子書中英文自動翻譯的,感覺挺有意思,這裡拿出來給大家分享下。

二、簡介

這個小項目是git上一個叫【xiaolai】的大佬分享的,看上去還是挺新的,釋出不太久,14天前釋出的。

手把手教你用Python腳本調用 DeepL API Pro 進電子書的行進行中英文自動翻譯

一本書中文譯文大約 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、運作代碼之後,會自動讀取待翻譯的檔案,然後進行翻譯,如下圖所示:

手把手教你用Python腳本調用 DeepL API Pro 進電子書的行進行中英文自動翻譯

2、運作完程式之後,可以得到想要的結果,如下圖所示:

手把手教你用Python腳本調用 DeepL API Pro 進電子書的行進行中英文自動翻譯

八、總結

大家好,我是Python進階者。這篇文章主要給大家介紹了使用Python腳本調用DeepL API Pro進電子書的行中英文自動翻譯的方法,代碼親測可行,歡迎大家積極嘗試,下次再遇到需要自動翻譯的時候,不妨調用下這個API,興許事半功倍呢!

------------------- End -------------------