• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья Перевод текста в переводчике DeepL с использованием Selenium в Python

Когда вы собираетесь читать книгу на иностранном языке, вы либо учите этот язык, для того, чтобы можно было читать тексты в оригинале, либо пользуетесь услугами машинного перевода. Если, конечно, книга уже не переведена на ваш язык опытным переводчиком. И, несомненно, лидерами в области машинного перевода долгое время были программы, которые устанавливались на компьютер, имели собственную базу в соответствии, с которой и переводили с одного языка на другой. Но, появился интернет и все большую популярность стали набирать онлайн переводчики, такие как Google Translate или Яндекс Переводчик. Но, речь сейчас не о них, а об онлайн переводчике, который в области машинного перевода гораздо лучше, чем упомянутые выше гиганты. Речь о DeepL Translate. И все бы хорошо, если бы не одно «но». И вот об этом «но» я и расскажу, как я автоматизировал его с помощью Python.

bigtyx6muc8kgipsaqbn0z7f3r14oh295eljvdw.jpg



Причина создания скрипта

Оговорюсь сразу же: «Эта часть не обязательна и, если вам не особо интересно, что привело к данному скрипту, то можете пропустить этот параграф и перейти сразу же к коду».

Суть проблемы была вот в чем. Когда я начал заниматься программированием, естественно, мне нужно было читать литературу на английском языке или смотреть на нем же видео. Потому как на русском языке подобной литературы или материалов, к сожалению не было. А даже если они и появились бы, то с некоторым опозданием, что не гарантировало бы актуальность материала. Тогда я решил пользоваться переводчиками.

Сначала мой выбор пал на Яндекс Переводчик. И да, раньше он был бесплатен, ведь столько было всяких инструкций по использованию его API. Но, очевидно, что технология была обкатана и перешла на коммерческие рельсы, что явно мне не подходило.

Тогда я начал склонятся в сторону Google Translate. И тут вроде бы все стало получаться. Перевод бесплатный, пусть и немного кривоватый. Но и тут я столкнулся с небольшой проблемой. Дело в том, что я скачивал с YouTube субтитры к видео на английском языке. Чтобы не мучиться вручную, сделал скрипт, который эти субтитры переводил и пересохранял уже на русском языке. Однако, радость моя была недолгой. Через какое-то время работы скрипта он выпал в осадок с ошибкой доступа. Очевидно, что Google не очень понравилось, когда его долбят запросами.

И вот уже совсем недавно я наткнулся на DeepL Translate. Качество перевода очень хорошее. Да, она справляется не со всем, но его переводы хотя бы можно читать без боли, потому, что они ближе всего стоят к естественному языку. Вот только автоматизировать это чудо не очень то получилось. У переводчика есть API. И на бесплатном тарифном плане можно перевести 500 000 знаков в месяц. Но, вот зарегистрироваться на сайте, чтобы получить ключ не представлялось возможным. В связи с недавними событиями доступ для русскоязычной аудитории для регистрации был, очевидно, закрыт. Я попробовал через VPN, но при регистрации нужно вводит данные кредитки. И сгенерированные данные сайт явно не устроили, потому как проводилась проверка и, тут же сообщалось, что такой карты не существует. Тогда я бросил это занятие и стал думать, а как же еще можно подступиться к прелестям автоматизации перевода.

Тогда полез в запросы. И даже их нашел. Конвертировал cURL в код Python и попробовал переводить. Но, через десяток запросов я стал получать ошибку доступа. Явно, что сайт почуял неладное и заблокировал запросы с моего адреса. Тогда я понял, что это тоже тупиковый путь. И подумал о том, что в браузере, теоретически, можно переводить сколько угодно. Ведь я так уже делал, когда достигался лимит, который очевидно как-то писался в куки, я просто чистил историю и начинал с чистого листа. А тогда, почему бы не воспользоваться selenium. И я попробовал. А вот что у меня получилось – об этом немного ниже.


Что понадобиться?

Для скрипта переводчика нужно будет установить selenium, для выполнения перевода текста в браузере и BeautifulSoup, чтобы парсить перевод . Пишем в терминале:

pip install bs4 selenium lxml

Также нужно будет скачать драйвер для браузера, в зависимости от ваших предпочтений: для Fifefox или Chrome. Ссылки на драйвер есть на странице загрузки библиотеки в PyPi. Ну и установить браузер, если у вас он еще не установлен. Я предпочел Firefox, просто потому, что в Linux он присутствует по умолчанию, а Google Chrome мне просто не нравиться.

Почему я не воспользовался для парсинга selenium, тут все просто. Да, я нашел поле для ввода текста и текст вводить в него у меня получилось, хоть и не без некоторых трудностей поначалу. А вот поле, в котором текст отображается я хоть и нашел, получить из него текст не удалось. Может быть я плохо старался, не знаю. Но там текст отображается не в одном, а нескольких тегах. То есть, основной перевод и, если перевод не очень большой, предлагаются еще его варианты. Эти поля присутствуют постоянно. Но, почему-то всегда возвращалось пустое значение. Тогда я просто стал передавать код страницы в BeautifulSoup и уже в ней парсить поле, в котором и отображался переведенный текст.

Давайте приступим к написанию кода.

Для начала импортируем все нужные нам библиотеки в скрипт:

Python:
import os.path
from platform import system
from time import sleep

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service

Для начала напишем функцию, которая будет парсить перевод. По сути, в ней и будет происходить все основное действие. Я назвал ее browser_get_html(path_text, num). Здесь на входе передается путь к тексту или текст для перевода, в зависимости от того, что выберет пользователь в стартовом меню. А также параметр num, который принимает значение 0 или 1 и обозначает, что выбрал пользователь. Если 0, переводим простой текст. Если 1 значит в переменной содержится путь к текстовому файлу из которого и берется текст для перевода.

Python:
def browser_get_html(path_text, num):
    options = Options()
    options.headless = False
    browser = ''

    if system() == "Windows":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver.exe')))
    elif system() == "Linux":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver')))

    if num == 0:
        browser.get('https://www.deepl.com/translator#en/ru/')
        sleep(2)
        field = browser.find_element(By.XPATH, '/html/body/div[3]/main/div[4]/div[3]/section[1]/div[3]/div[2]/textarea')
        field.send_keys(path_text.strip())

        sleep(10)
        html = browser.page_source
        soup = BeautifulSoup(html, 'lxml')
        translation = soup.find('div', id='target-dummydiv')
        print(f'\n{translation.text}')

        browser.close()
        browser.quit()
    elif num == 1:
        name_translate = ''
        if system() == "Windows":
            name_translate = os.path.split(path_text)[1].removesuffix(".txt")
        elif system() == "Linux":
            name_translate = os.path.split(path_text)[1][0:-4]
        browser.get('https://www.deepl.com/translator')
        sleep(2)
        field = browser.find_element(By.XPATH, '/html/body/div[3]/main/div[4]/div[3]/section[1]/div[3]/div[2]/textarea')

        with open(path_text, 'r', encoding='utf-8') as file:
            read = file.read().split("\n")

        for line in read:
            if len(line.strip()) > 5000:
                print(f'[-] Количество введенных знаков: {len(line.strip())}\n   '
                      f'- Онлайн перевод не поддерживает более 5000 знаков в тексте одновременно\n'
                      f'   - Уберите лишнее кол-во знаков')
                main()
                return

            field.send_keys(line.strip())

            sleep(10)
            html = browser.page_source
            soup = BeautifulSoup(html, 'lxml')
            translation = soup.find('div', id='target-dummydiv')
            print(translation.text)

            with open(os.path.join(os.getcwd(), f'{name_translate}_tr.txt'), 'a', encoding='utf-8') as file:
                file.write(translation.text)
            field.clear()

        browser.close()
        browser.quit()

Для начала устанавливаем настройки браузера. Создаем параметр options, в котором они и будут содержаться. Далее, устанавливаем одну опцию: options.headless в значение False, что значит показывать браузер пользователю. Если же вы хотите отключить показ браузера, поставьте у данной опции значение True. И определяем, переменную browser, чтобы к ней был доступ из всего последующего кода.

Python:
    options = Options()
    options.headless = False
    browser = ''

Затем нам нужно инициализировать драйвер браузера, а значит передать в него опции, путь к драйверу и параметр, отвечающий за вывод лога работы драйвера. Поэтому определяем версию операционной системы. Если Windows, указываем одни параметры, Linux – чуть другие. И в том, и в том случае драйвер, согласно кода, должен лежать в папке «geckodriver», которая должна находиться в папке со скриптом. Ну, или можете прописать в путь к драйверу в переменных средах. Если речь идет о Windows.

Python:
    if system() == "Windows":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver.exe')))
    elif system() == "Linux":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver')))

Затем определяем, что выбрал пользователь. Если пришел 0, то значит пользователь переводи текст из командной строки. Здесь запускаем браузер, переходим на страницу переводчика. Спим две секунды, для того, чтобы подождать, пока прогрузиться страница. Ищем поле ввода текста по элементу XPATH, куда и вставляем полученный от пользователя текст. Затем спим еще 10 секунд. Тут с параметром можно поэкспериментировать. Можно 10 секунд и не спать. Это я несколько перестраховался. Но, тут все зависит от того, какой величины текст отправит пользователь. Ведь тут перевод проходит не мгновенно, а потому, на то, чтобы он отобразился в поле вывода нужно некоторое время. Затем передаем HTML в BeautifulSoup. Ищем по id тег, куда выводится перевод и принтуем его в терминал. После этого закрываем браузер.

Python:
    if num == 0:
        browser.get('https://www.deepl.com/translator#en/ru/')
        sleep(2)
        field = browser.find_element(By.XPATH, '/html/body/div[3]/main/div[4]/div[3]/section[1]/div[3]/div[2]/textarea')
        field.send_keys(path_text.strip())

        sleep(10)
        html = browser.page_source
        soup = BeautifulSoup(html, 'lxml')
        translation = soup.find('div', id='target-dummydiv')
        print(f'\n{translation.text}')

        browser.close()
        browser.quit()

Если же была получена 1, тогда в переменно path_text содержится путь к текстовому документу. Получаем из пути имя для будущего файла с переводом. Открываем файл, разбиваем по «\n». В итоге у нас получается список с абзацами и в цикле отправляем каждый абзац для перевода. Парсим перевод и сохраняем в тестовый документ.

Python:
        name_translate = ''
        if system() == "Windows":
            name_translate = os.path.split(path_text)[1].removesuffix(".txt")
        elif system() == "Linux":
            name_translate = os.path.split(path_text)[1][0:-4]
        browser.get('https://www.deepl.com/translator#en/ru/')
        sleep(2)
        field = browser.find_element(By.XPATH, '/html/body/div[3]/main/div[4]/div[3]/section[1]/div[3]/div[2]/textarea')

        with open(path_text, 'r', encoding='utf-8') as file:
            read = file.read().split("\n")

        for line in read:
            if len(line.strip()) > 5000:
                print(f'[-] Количество введенных знаков: {len(line.strip())}\n   '
                      f'- Онлайн перевод не поддерживает более 5000 знаков в тексте одновременно\n'
                      f'   - Уберите лишнее кол-во знаков')
                main()
                return

            field.send_keys(line.strip())

            sleep(10)
            html = browser.page_source
            soup = BeautifulSoup(html, 'lxml')
            translation = soup.find('div', id='target-dummydiv')
            print(translation.text)

            with open(os.path.join(os.getcwd(), f'{name_translate}_tr.txt'), 'a', encoding='utf-8') as file:
                file.write(translation.text)
            field.clear()

Тут надо сказать, что текстовый документ должен быть отформатирован соответствующим образом, то есть, подготовлен к переводу. И сырой текст тут явно не подойдет. Нужно убрать все переносы строк внутри параграфа, оставить их только между. Для того, чтобы разбивка текста происходила корректно. Еще переносы строк надо убрать для того, чтобы перевод был как можно более точный. Ведь смысл переводимого текста еще и зависит от того, как составлено предложение. А если у вас посреди строки будет стоять перевод на следующую строку, переводчик и будет воспринимать это как два отдельных текста. А следовательно, перевод будет очень уж приблизительным.

С помощью Python пока эту задачу не решал. А решил ее вручную с помощью Notepad ++. У него есть такая замечательная штука, как запись макросов и функция «Объдинить строки». Записываю макрос и подготавливаю документ к переводу.

Ну и функция пользовательского выбора. Тут особо рассказывать не о чем. Идет выбор пользователем действий и в зависимости от выбора проводиться проверка на корректность выбора и на длину введенного текста. Дело в том, что переводчик позволяет перевести только 5000 символов с пробелами. А значит, если текст будет больше, он просто обрежется. Поэтому, перед тем как начать перевод проводится проверка на его длину. Так что, старайтесь разбивать абзацы не более 5000 символов.

Python:
def main():
    print("\nДля перевода текста из текстового файла текст должен быть отформатирован надлежащим образом.\nА именно:\n"
          "   - убраны пробелы между связанными словами предложения. Или, если вы хотите перевести сразу целый абзац,\n"
          "     нужно убрать переносы строки;\n"
          "   - между абзацами наоборот, должен стоять перенос сторки, так как именно по переносу строки происходит\n"
          "     разделение текста\n   пример смотрите в файле: example.txt")
    user_change = input('\n[+] Выберите направление для перевода:\n   [1] Текст в консоли\n   [2] Текстовый файл\n   '
                        '[3] Выход\n   >>> ')
    if user_change == "1":
        path_text = input('[+] Введите текст для перевода: ')
        if len(path_text) > 5000:
            print(f'[-] Количество введенных знаков: {len(path_text)}\n   '
                  f'- Онлайн перевод не поддерживает более 5000 знаков в тексте одновременно\n'
                  f'   - Уберите лишнее кол-во знаков')
            main()
        browser_get_html(path_text, 0)
    elif user_change == "2":
        path_text = input('[+] Введите путь к текстовому файлу для перевода: ')
        if not os.path.exists(path_text):
            print('[-] Файла по введенному вами пути не обнаружено')
            main()
        if not path_text.endswith(".txt"):
            print('[-] Формат файла не поддерживается. Нужен текстовый документ')
            main()
        browser_get_html(path_text, 1)
    elif user_change == "3":
        exit(0)
    else:
        print("[-] Неопознанный ввод. Повторите попытку")
        main()

Вот, в принципе, и все. Во вложение добавлю перевод первой главы книги Эрика Чоу - Освоение сетевых технологий Python. Ее я как раз перевел с помощью данного скрипта. Да, перевод длится не пять секунд, а потому придется подождать. Тут львиную долю занимает время ожидания загрузки перевода. Но, тем не менее, медленно, но верно перевод выполняется. И это все не вручную. Нет необходимости переключатся между переводчиком, блокнотом для правки текста, книгой для копирования и Word для его вставки.

Python:
# pip install bs4 selenium

import os.path
from platform import system
from time import sleep

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service


# запуск браузера и цикла для перевода текста,
# а также сохранение переведенного текста в файл
def browser_get_html(path_text, num):
    options = Options()
    options.headless = False
    browser = ''

    if system() == "Windows":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver.exe')))
    elif system() == "Linux":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver')))

    if num == 0:
        browser.get('https://www.deepl.com/translator#en/ru/')
        sleep(2)
        field = browser.find_element(By.XPATH, '/html/body/div[3]/main/div[4]/div[3]/section[1]/div[3]/div[2]/textarea')
        field.send_keys(path_text.strip())

        sleep(10)
        html = browser.page_source
        soup = BeautifulSoup(html, 'lxml')
        translation = soup.find('div', id='target-dummydiv')
        print(f'\n{translation.text}')

        browser.close()
        browser.quit()
    elif num == 1:
        name_translate = ''
        if system() == "Windows":
            name_translate = os.path.split(path_text)[1].removesuffix(".txt")
        elif system() == "Linux":
            name_translate = os.path.split(path_text)[1][0:-4]
        browser.get('https://www.deepl.com/translator#en/ru/')
        sleep(2)
        field = browser.find_element(By.XPATH, '/html/body/div[3]/main/div[4]/div[3]/section[1]/div[3]/div[2]/textarea')

        with open(path_text, 'r', encoding='utf-8') as file:
            read = file.read().split("\n")

        for line in read:
            if len(line.strip()) > 5000:
                print(f'[-] Количество введенных знаков: {len(line.strip())}\n   '
                      f'- Онлайн перевод не поддерживает более 5000 знаков в тексте одновременно\n'
                      f'   - Уберите лишнее кол-во знаков')
                main()
                return

            field.send_keys(line.strip())

            sleep(10)
            html = browser.page_source
            soup = BeautifulSoup(html, 'lxml')
            translation = soup.find('div', id='target-dummydiv')
            print(translation.text)

            with open(os.path.join(os.getcwd(), f'{name_translate}_tr.txt'), 'a', encoding='utf-8') as file:
                file.write(translation.text)
            field.clear()

        browser.close()
        browser.quit()


# получение пути к файлу для перевода
# запуск функции парсинга
def main():
    print("\nДля перевода текста из текстового файла текст должен быть отформатирован надлежащим образом.\nА именно:\n"
          "   - убраны пробелы между связанными словами предложения. Или, если вы хотите перевести сразу целый абзац,\n"
          "     нужно убрать переносы строки;\n"
          "   - между абзацами наоборот, должен стоять перенос сторки, так как именно по переносу строки происходит\n"
          "     разделение текста\n   пример смотрите в файле: example.txt")
    user_change = input('\n[+] Выберите направление для перевода:\n   [1] Текст в консоли\n   [2] Текстовый файл\n   '
                        '[3] Выход\n   >>> ')
    if user_change == "1":
        path_text = input('[+] Введите текст для перевода: ')
        if len(path_text) > 5000:
            print(f'[-] Количество введенных знаков: {len(path_text)}\n   '
                  f'- Онлайн перевод не поддерживает более 5000 знаков в тексте одновременно\n'
                  f'   - Уберите лишнее кол-во знаков')
            main()
        browser_get_html(path_text, 0)
    elif user_change == "2":
        path_text = input('[+] Введите путь к текстовому файлу для перевода: ')
        if not os.path.exists(path_text):
            print('[-] Файла по введенному вами пути не обнаружено')
            main()
        if not path_text.endswith(".txt"):
            print('[-] Формат файла не поддерживается. Нужен текстовый документ')
            main()
        browser_get_html(path_text, 1)
    elif user_change == "3":
        exit(0)
    else:
        print("[-] Неопознанный ввод. Повторите попытку")
        main()


if __name__ == "__main__":
    main()

Пример форматирования текста также будет во вложении.

Спасибо за внимание. Надеюсь, что данная статья будет вам полезна
 

Вложения

  • example.zip
    1,3 МБ · Просмотры: 232
Последнее редактирование:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!