[Python] PDF automatisch mit DeepL übersetzen, dabei das Originalformat beibehalten. [Windows / Word erforderlich]

9/9 Nachtrag

Die Eingabe in DeepL über die Zwischenablage wurde aufgehoben und mithilfe von Javascript in die Methode geändert. Zusammen mit dem entspricht es der Verwendung von Selen im kopflosen Modus.

9/14 Nachtrag

Behebt das Problem des Zusammenbruchs des Layouts um die Tabelle. Wenn das Bild in denselben Absatz wie der Text eingebettet ist (z. B. eine abgebildete Formel), wird das Bild beim Ersetzen des Textes ausgeblendet und von der Übersetzung ausgeschlossen, bis eine Lösung gefunden wird.

Aktualisierte Version
import win32com.client
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time
import re
from math import ceil
from threading import Thread

DRIVER_PATH = 'chromedriver.exe'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
options = Options()
options.add_argument(f'--user-agent={user_agent}')
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--start-maximized')
options.add_argument('--headless') #Brechen Sie den Headless-Modus durch Auskommentieren ab (Chrome wird angezeigt).


def Deeptrans(t, driver):
    global translated_texts
    stextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__source_textarea.lmt__textarea_base_style')
    ttextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__target_textarea.lmt__textarea_base_style')
    for i in range(t * unit, min((t + 1) * unit, length)):
        if sourse_texts[i]: sourse_text = sourse_texts[i]
        else: continue
        if not sourse_text.strip():
            continue
        driver.execute_script(
            f'$(".lmt__source_textarea").val({repr(sourse_text)});')
        stextarea.send_keys(Keys.RIGHT)
        translated_text = ""
        while not translated_text:
            time.sleep(1)
            translated_text = ttextarea.get_property("value")
        stextarea.send_keys(Keys.CONTROL, "a")
        stextarea.send_keys(Keys.BACKSPACE)
        translated_texts.append({"index": i + 1, "text": translated_text})


def runDriver(t):
    global options
    driver = webdriver.Chrome(executable_path=DRIVER_PATH, options=options)
    url = 'https://www.deepl.com/ja/translator'
    driver.get(url)
    Deeptrans(t, driver)
    driver.quit()


def multiThreadTranslate(file_path, font):
    global length, unit, sourse_texts, translated_texts
    app = win32com.client.Dispatch("Word.Application")
    #app.Visible = True
    doc = app.Documents.Open(file_path)
    try:
        doc.Paragraphs(1).Range.Font.Name = font
    except:
        print('Die angegebene Schriftart existiert nicht')
        return
    length = doc.Paragraphs.Count
    n = 9
    unit = ceil(length / n)
    sourse_texts = [
        doc.Paragraphs(i + 1).Range.Text if
        (str(doc.Paragraphs(i + 1).Range.Style) != "TableGrid" and
         str(doc.Paragraphs(min(length, i + 2)).Range.Style) != "TableGrid" and doc.Paragraphs(i + 1).Range.InlineShapes.Count)
        else None for i in range(length)
    ]
    translated_texts = []
    threads = []
    for t in range(n):
        thread = Thread(target=runDriver, args=(t, ))
        thread.setDaemon(True)
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()
    for translated_text in sorted(translated_texts, key=lambda i: i["index"]):
        doc.Paragraphs(translated_text["index"]
                       ).Range.Text = translated_text["text"].replace(
                           '\n', '\r')
        doc.Paragraphs(translated_text["index"]).Range.Font.Name = font
    doc.SaveAs2(FileName=re.sub("(.+)(\.pdf)", r"\1_jp.pdf", file_path),
                FileFormat=17)
    doc.Close(SaveChanges=0)
    app.Quit()
    print('Process is completed.')


if __name__ == '__main__':
    file_path = input('Geben Sie den absoluten Pfad der PDF ein (Drag & Drop ist ebenfalls möglich).:     ')
    print('Bitte wählen Sie eine Schriftart')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Andere'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Andere': font = input('Bitte geben Sie den Schriftnamen ein:     ')
    multiThreadTranslate(file_path, font=font)

9/15 Nachtrag

-Das obige Problem wurde vorerst mit der 1-Thread-Version gelöst.

Lösungsversion (einzelner Thread) vorerst
import win32com.client
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time
import re
from tqdm import tqdm

DRIVER_PATH = 'chromedriver.exe'
options = Options()
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--start-maximized')


def Deeptrans(file_path, font):
    app = win32com.client.Dispatch("Word.Application")
    app.Visible = True
    doc = app.Documents.Open(file_path)
    driver = webdriver.Chrome(executable_path=DRIVER_PATH,
                              chrome_options=options)
    url = 'https://www.deepl.com/ja/translator#en/ja'
    driver.get(url)
    stextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__source_textarea.lmt__textarea_base_style')
    ttextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__target_textarea.lmt__textarea_base_style')

    length = doc.Paragraphs.Count
    for i in tqdm(range(length)):
        if str(doc.Paragraphs(i + 1).Range.Style) == "TableGrid":
            continue
        sourse_text = doc.Paragraphs(i + 1).Range.Text
        fs = doc.Paragraphs(i + 1).Range.Font.Size
        alignment = doc.Paragraphs(i + 1).Alignment
        lindent = doc.Paragraphs(i + 1).LeftIndent
        rindent = doc.Paragraphs(i + 1).RightIndent
        if doc.Paragraphs(i + 1).Range.InlineShapes.Count:
            if sourse_text.strip() == "/": continue
            doc.Paragraphs(i + 1).Range.Font.Name = font
            t = ""
            te = []
            cnt = 0
            for j in range(doc.Paragraphs(i + 1).Range.Words.Count):
                if "/" not in doc.Paragraphs(i + 1).Range.Words(j + 1).Text:
                    t += doc.Paragraphs(i + 1).Range.Words(j + 1).Text
                    doc.Paragraphs(i + 1).Range.Words(j + 1).Text = "'' "
                else:
                    te.append(t)
                    t = ""
                    cnt += 1
            if t: te.append(t)

            for j, sourse_text in enumerate(te):
                if len(sourse_text.strip()) > 5:
                    driver.execute_script(
                        f'$(".lmt__source_textarea").val({repr(sourse_text)});'
                    )
                    stextarea.send_keys(Keys.RIGHT)
                    translated_text = ""
                    while not translated_text:
                        time.sleep(1)
                        translated_text = driver.find_element_by_css_selector(
                            '.lmt__textarea.lmt__target_textarea.lmt__textarea_base_style'
                        ).get_property("value")
                    stextarea.send_keys(Keys.CONTROL, "a")
                    stextarea.send_keys(Keys.BACKSPACE)
                    te[j] = translated_text

            g = (j for j in te)
            c = 0
            for j in doc.Paragraphs(i + 1).Range.Words:
                if j.Text == "'' ":
                    j.Text = ""
                elif "/" in j.Text:
                    try:
                        j.InsertBefore(g.__next__())
                        c += 1
                        if c == cnt:
                            j.InsertAfter(g.__next__())
                    except:
                        pass
            doc.Paragraphs(i + 1).Alignment = alignment
            doc.Paragraphs(i + 1).Range.Font.Size = fs
            doc.Paragraphs(i + 1).LeftIndent = lindent
            doc.Paragraphs(i + 1).RightIndent = rindent
            continue

        if re.search(r"[\x00-\x1F\x7F]",
                     sourse_text.strip()) or len(sourse_text.strip()) < 5:
            continue
        driver.execute_script(
            f'$(".lmt__source_textarea").val({repr(sourse_text)});')
        stextarea.send_keys(Keys.RIGHT)
        translated_text = ""
        while not translated_text:
            time.sleep(1)
            translated_text = driver.find_element_by_css_selector(
                '.lmt__textarea.lmt__target_textarea.lmt__textarea_base_style'
            ).get_property("value")
        stextarea.send_keys(Keys.CONTROL, "a")
        stextarea.send_keys(Keys.BACKSPACE)
        doc.Paragraphs(i + 1).Range.Text = translated_text
        doc.Paragraphs(i + 1).Range.Font.Name = font
        doc.Paragraphs(i + 1).Alignment = alignment
        doc.Paragraphs(i + 1).Range.Font.Size = fs
        doc.Paragraphs(i + 1).LeftIndent = lindent
        doc.Paragraphs(i + 1).RightIndent = rindent
    driver.quit()
    doc.SaveAs2(FileName=re.sub("(.+)(\.pdf)", r"\1_jp.pdf", file_path),
                FileFormat=17)
    doc.Close(SaveChanges=0)
    app.Quit()
    print('Process is completed.')


if __name__ == '__main__':
    file_path = input('Bitte geben Sie den absoluten Pfad des PDF ein:     ')
    print('Bitte wählen Sie eine Schriftart')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Andere'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Andere': font = input('Bitte geben Sie den Schriftnamen ein:     ')
    Deeptrans(file_path, font)

Einführung

Ich habe vorher einen Artikel über automatische PDF-Übersetzung geschrieben, ** Schließlich möchte ich die ursprüngliche Form von Bildern, Formeln, Spalten usw. beibehalten! ** **. Ich hatte Bedauern, und als ich nach einer Methode suchte, kam ich mit Word zu einer Methode, daher möchte ich sie vorstellen. Abhängig von der Kompatibilität zwischen PDF und Word ist es jedoch möglicherweise nicht möglich, es sehr gut zu verarbeiten.

Anwendungsbeispiel

Ich habe das PDF von hier ausgeliehen → https://mirela.net.technion.ac.il/publications/ Die Position wird aufgrund der Zeichenbreite und der Anzahl der Zeichen verschoben. EN→JA

Dinge notwendig

・ Windows-PC ・ Microsoft Word

fließen

*** Programmstart   ↓ Öffnen Sie die Ziel-PDF als dox in Word   ↓ Holen Sie sich Sätze für jeden Absatz   ↓ DeepL-Übersetzung mit Selen   ↓ Über Word umschreiben   ↓ Als PDF speichern   ↓ Das Ende des Programms ***

Implementierung

Es braucht Zeit, um es Absatz für Absatz zu tun, deshalb habe ich beschlossen, es in mehreren Threads auszuführen. Wenn sich aus irgendeinem Grund die Nummer, die die Position des Absatzes verwaltet, verschiebt, wird es einige Zeit dauern, aber wir werden auch eine Version veröffentlichen, die jeden Absatz übersetzt. Versuchen Sie es also bitte.

import win32com.client
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time
import re
import pyperclip as ppc
from math import ceil
from threading import Thread, Lock

DRIVER_PATH = 'chromedriver.exe'
options = Options()
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--start-maximized')


def Deeptrans(t, driver):
    global translated_texts
    stextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__source_textarea.lmt__textarea_base_style')
    ttextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__target_textarea.lmt__textarea_base_style')
    for i in range(t * unit, min((t + 1) * unit, length)):
        sourse_text = sourse_texts[i]
        if re.search(r"[\x00-\x1F\x7F]",
                     sourse_text.strip()) or len(sourse_text.strip()) < 5:
            continue
        lock.acquire()
        ppc.copy(sourse_text)
        stextarea.send_keys(Keys.CONTROL, "v")
        lock.release()
        translated_text = ""
        while not translated_text:
            time.sleep(1)
            translated_text = ttextarea.get_property("value")
        stextarea.send_keys(Keys.CONTROL, "a")
        stextarea.send_keys(Keys.BACKSPACE)
        translated_texts[str(i + 1)] = translated_text


def runDriver(t):
    driver = webdriver.Chrome(DRIVER_PATH)
    url = 'https://www.deepl.com/ja/translator'
    driver.get(url)
    Deeptrans(t, driver)
    driver.quit()


def multiThreadTranslate(file_path, font):
    global lock, length, unit, sourse_texts, translated_texts
    app = win32com.client.Dispatch("Word.Application")
    app.Visible = True #Verstecke Word durch Auskommentieren
    doc = app.Documents.Open(file_path)
    try:
        doc.Paragraphs(1).Range.Font.Name = font
    except:
        print('Die angegebene Schriftart existiert nicht')
        doc.Close(SaveChanges=0)
        app.Quit()
        return
    length = doc.Paragraphs.Count
    n = 9 #Öffnen Sie 9 Chrome und führen Sie es gleichzeitig aus
    unit = ceil(length / n)
    lock = Lock()
    clipboard = ppc.paste()
    sourse_texts = [doc.Paragraphs(i + 1).Range.Text for i in range(length)]
    translated_texts = {}
    threads = []
    for t in range(n):
        thread = Thread(target=runDriver, args=(t, ))
        thread.setDaemon(True)
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()
    for k, v in translated_texts.items():
        doc.Paragraphs(int(k)).Range.Text = v.replace('\n', '\r')
        doc.Paragraphs(int(k)).Range.Font.Name = font
    doc.SaveAs2(FileName=re.sub("(.+)(\.pdf)", r"\1_jp.pdf", file_path),
                FileFormat=17)
    doc.Close(SaveChanges=0)
    app.Quit()
    print('Process is completed.')
    ppc.copy(clipboard)


if __name__ == '__main__':
    file_path = input('Bitte geben Sie den absoluten Pfad des PDF ein:     ')
    print('Bitte wählen Sie eine Schriftart')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Andere'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Andere': font = input('Bitte geben Sie den Schriftnamen ein:     ')
    multiThreadTranslate(file_path, font=font)
Jeweils ein Absatz ver. (Mit einem Fortschrittsbalkenbonus)
import win32com.client
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time
import re
import pyperclip as ppc
from tqdm import tqdm

DRIVER_PATH = 'chromedriver.exe'
options = Options()
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--start-maximized')


def Deeptrans(file_path, font):
    clipboard = ppc.paste()
    app = win32com.client.Dispatch("Word.Application")
    app.Visible = True
    doc = app.Documents.Open(file_path)
    driver = webdriver.Chrome(executable_path=DRIVER_PATH,
                              chrome_options=options)
    url = 'https://www.deepl.com/ja/translator#en/ja'
    driver.get(url)
    stextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__source_textarea.lmt__textarea_base_style')
    ttextarea = driver.find_element_by_css_selector(
        '.lmt__textarea.lmt__target_textarea.lmt__textarea_base_style')

    for i in tqdm(range(doc.Paragraphs.Count)):
        sourse_text = doc.Paragraphs(i + 1).Range.Text
        if re.search(r"[\x00-\x1F\x7F]",
                     sourse_text.strip()) or len(sourse_text.strip()) < 5:
            continue
        ppc.copy(sourse_text)
        stextarea.send_keys(Keys.CONTROL, "v")
        translated_text = ""
        while not translated_text:
            time.sleep(1)
            translated_text = ttextarea.get_property("value")
        stextarea.send_keys(Keys.CONTROL, "a")
        stextarea.send_keys(Keys.BACKSPACE)
        doc.Paragraphs(i + 1).Range.Text = translated_text
        doc.Paragraphs(i + 1).Range.Font.Name = font
    driver.quit()
    doc.SaveAs2(FileName=re.sub("(.+)(\.pdf)", r"\1_jp.pdf", file_path),
                FileFormat=17)
    doc.Close(SaveChanges=0)
    app.Quit()
    print('Process is completed.')
    ppc.copy(clipboard)


if __name__ == '__main__':
    file_path = input('Bitte geben Sie den absoluten Pfad des PDF ein:     ')
    print('Bitte wählen Sie eine Schriftart')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Andere'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Andere': font = input('Bitte geben Sie den Schriftnamen ein:     ')
    Deeptrans(file_path, font)

Wie benutzt man

Um es zu verwenden, speichern Sie es einfach und führen Sie es über die Befehlszeile aus (bitte installieren Sie die erforderlichen Bibliotheken separat). Nach einer Weile wird die Datei "original name_jp.pdf" in dasselbe Verzeichnis wie die ursprüngliche Datei ausgegeben.

Aufgabe

Es ist schwierig, zwischen mathematischen Formeln und lokalen Sätzen zu unterscheiden, und sie können ihre Form verlieren oder verschwinden. Ich habe mich mit einer aufklebbaren Klinge damit befasst, aber im Gegenteil, einige Sätze wurden nicht übersetzt. Auf der Suche nach einem guten Weg.

Zusammenfassung

Mr. Word. Wenn Sie interessiert sind, versuchen Sie es bitte.

Recommended Posts

[Python] PDF automatisch mit DeepL übersetzen, dabei das Originalformat beibehalten. [Windows / Word erforderlich]
Englisches Wortbuchprogramm, das mit Google-Dokumenten verknüpft ist
[Python] PDF automatisch mit DeepL übersetzen, dabei das Originalformat beibehalten. [Windows / Word erforderlich]
Versuchen Sie, mit Python zu übersetzen, während Sie das PDF-Layout beibehalten
Übersetzen Sie DeepL automatisch mit Python und Selen ins Englische
[Python] Betreiben Sie den Browser automatisch mit Selenium
[Python] Lassen Sie uns automatisch englische PDF-Dateien (ohne darauf beschränkt zu sein) mit DeepL- oder Google-Übersetzung übersetzen, um daraus eine Textdatei zu machen.
[Automatisierung] Extrahieren Sie die Tabelle als PDF mit Python
Formatieren Sie Python-Code mit Emacs automatisch in PEP8-kompatiblen Code
Konvertieren Sie das Bild in .zip mit Python in PDF
Mit Python psycopg2 erhalten Sie Ergebnisse im Diktatformat
Fortsetzung [Python] Lassen Sie uns automatisch englische PDF-Dateien (ohne darauf beschränkt zu sein) mit DeepL- oder Google-Übersetzung in eine Textdatei ohne HTML übersetzen.