[Python] Traduisez automatiquement les PDF avec DeepL tout en conservant le format d'origine. [Windows / Word requis]

9/9 postscript

Suppression de l'entrée dans DeepL via le presse-papiers et modification de la méthode utilisant Javascript. Parallèlement à cela, cela correspond à l'utilisation de Selenium en mode sans tête.

9/14 post-scriptum

Résout le problème de la réduction de la disposition autour de la table. Si l'image est incorporée dans le même paragraphe que le texte (comme une formule imagée), il s'avère que l'image disparaît lorsque vous remplacez le texte et qu'elle est exclue de la traduction jusqu'à ce qu'une solution soit trouvée.

Version mise à jour
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') #Annuler le mode sans tête en commentant (Chrome est affiché)


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('La police spécifiée n'existe pas')
        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('Entrez le chemin absolu du PDF (le glisser-déposer est également possible):     ')
    print('Veuillez sélectionner une police')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Autre'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Autre': font = input('Veuillez saisir le nom de la police:     ')
    multiThreadTranslate(file_path, font=font)

9/15 post-scriptum

-Le problème ci-dessus a été résolu pour le moment avec la version 1 thread. -Résolution du problème que la taille de la police a été ajustée sans autorisation et a secoué, et le problème que des retraits étranges ont été insérés.

Version de la solution (thread unique) pour le moment
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('Veuillez saisir le chemin absolu du PDF:     ')
    print('Veuillez sélectionner une police')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Autre'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Autre': font = input('Veuillez saisir le nom de la police:     ')
    Deeptrans(file_path, font)

introduction

J'ai déjà écrit un article sur la traduction automatique de PDF, ** Après tout, je souhaite conserver la forme originale des images, des formules, des colonnes, etc.! ** ** J'avais un regret, alors quand j'ai cherché une méthode, je suis arrivé à une méthode utilisant Word, alors j'aimerais la présenter. Cependant, en fonction de la compatibilité entre PDF et Word, il peut ne pas être possible de le traiter très bien.

Exemple d'utilisation

J'ai emprunté le PDF d'ici → https://mirela.net.technion.ac.il/publications/ La position n'est pas alignée en raison de la largeur des caractères et du nombre de caractères. EN→JA

Les choses nécessaires

・ PC Windows ・ Microsoft Word

couler

*** Début du programme   ↓ Ouvrez le PDF cible en tant que dox dans Word   ↓ Obtenez des phrases pour chaque paragraphe   ↓ Traduction DeepL avec Selenium   ↓ Réécrire via Word   ↓ Enregistrer au format PDF   ↓ La fin du programme ***

la mise en oeuvre

Cela prend du temps pour le faire paragraphe par paragraphe, j'ai donc décidé de l'exécuter dans plusieurs threads. Si pour une raison quelconque le numéro qui gère la position du paragraphe change, cela prendra du temps, mais nous publierons également une version qui traduit chaque paragraphe, alors essayez-le.

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 #Masquer Word en commentant
    doc = app.Documents.Open(file_path)
    try:
        doc.Paragraphs(1).Range.Font.Name = font
    except:
        print('La police spécifiée n'existe pas')
        doc.Close(SaveChanges=0)
        app.Quit()
        return
    length = doc.Paragraphs.Count
    n = 9 #Ouvrez 9 Chrome et exécutez en même temps
    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('Veuillez saisir le chemin absolu du PDF:     ')
    print('Veuillez sélectionner une police')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Autre'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Autre': font = input('Veuillez saisir le nom de la police:     ')
    multiThreadTranslate(file_path, font=font)
Un paragraphe à la fois ver. (Avec un bonus de barre de progression)
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('Veuillez saisir le chemin absolu du PDF:     ')
    print('Veuillez sélectionner une police')
    fonts = {'1': 'Yu Mincho', '2': 'Meilio', '3': 'BIZ UDP Mincho Medium', '4': 'Autre'}
    font = fonts[input('   '.join(
        [", ".join(list(fonts.items())[i])
         for i in range(len(fonts))]) + ":     ")]
    if font == 'Autre': font = input('Veuillez saisir le nom de la police:     ')
    Deeptrans(file_path, font)

Comment utiliser

Pour l'utiliser, il suffit de l'enregistrer et de l'exécuter à partir de la ligne de commande (veuillez installer les bibliothèques requises séparément). Après un certain temps, le fichier ʻoriginal name_jp.pdf` sera sorti dans le même répertoire que le fichier original.

Tâche

Il est difficile de faire la distinction entre les formules mathématiques et les phrases locales, et elles peuvent perdre leur forme ou disparaître. Je l'ai traité avec une lame collante, mais au contraire, certaines phrases n'ont pas été traduites. Vous cherchez un bon moyen.

Résumé

M. Word. Si vous êtes intéressé, essayez-le.

Recommended Posts

[Python] Traduisez automatiquement les PDF avec DeepL tout en conservant le format d'origine. [Windows / Word requis]
Programme de livre de mots anglais lié à des documents Google
[Python] Traduisez automatiquement les PDF avec DeepL tout en conservant le format d'origine. [Windows / Word requis]
Essayez de traduire avec Python tout en conservant la mise en page PDF
Traduisez automatiquement DeepL en anglais avec Python et Selenium
[Python] Utiliser automatiquement le navigateur avec Selenium
[Python] Traduisons automatiquement le PDF anglais (mais sans s'y limiter) avec la traduction DeepL ou Google pour en faire un fichier texte.
[Automation] Extraire le tableau en PDF avec Python
Formater automatiquement le code Python en code compatible PEP8 avec Emacs
Convertissez l'image au format .zip en PDF avec Python
Obtenez des résultats au format dict avec Python psycopg2
Suite [Python] Traduisons automatiquement le PDF anglais (mais sans s'y limiter) avec la traduction DeepL ou Google dans un fichier texte, pas de HTML.