LoginSignup
6
3

More than 1 year has passed since last update.

【Python】DeepLを用いた自動翻訳をdiscord botに導入してみた

Last updated at Posted at 2021-07-29

目標

PDFなどをコピペした英文を投げたら自動で改行調整をし、日本語訳を返すコードをPythonで書いたのでそれをdiscord botに導入してみる。

注意 seleniumが並列化できていないため、飽くまで個人用です。 (複数人で共有するとタブクラッシュするかも)

メリット

discord botに翻訳を返してもらえるメリットを挙げると
-記録が残せる
-Shaperを使うのと違ってタブが増殖しない

翻訳コード

とりあえずコードを載せる。

translate.py
import time
from selenium import webdriver
import chromedriver_binary
from xml.sax.saxutils import unescape
def deepl(text):
    text = ' '.join(text.splitlines())

    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    url="https://www.deepl.com/ja/translator"
    driver =webdriver.Chrome(options=options)
    driver.get(url)

    insec="#dl_translator > div.lmt__text > div.lmt__sides_container > div.lmt__side_container.lmt__side_container--source > div.lmt__textarea_container > div.lmt__inner_textarea_container > textarea"
    driver.find_element_by_css_selector(insec).send_keys(text)

    outsec="#target-dummydiv"
    while 1:
        Outputtext =  driver.find_element_by_css_selector(outsec).get_attribute("innerHTML")
        if Outputtext != "\r\n" :
            break
        time.sleep(1)
    driver.quit
    Outputtext=Outputtext.rstrip("\r\n")
    Outputtext=unescape(Outputtext)
    return Outputtext

英文の改行コードを空白にする

PDFをコピペすると勝手に改行されてイライラするのでとりあえず改行を消して半角空白にする。

text = ' '.join(text.splitlines())

seleniumを使ってDeeplにアクセス

options = webdriver.ChromeOptions() #事前にimportしたchromeのwebdriverを使う
options.add_argument('--headless') #実行の際Chromeを開かないよう指定
url="https://www.deepl.com/ja/translator" #DeepL(ja)のURL
driver =webdriver.Chrome(options=options) #driverを指定
driver.get(url) #DeepLにアクセス

webdriver.ChromeOptionsについては@hanzawak様のこの記事を参照するといいかも。

DeepLに英文を入れる

手法1

https://www.deepl.com/translator#en/ja/英文
にアクセスすることで翻訳を行う。

問題点

例えば文章中にX/Yなどがあるとする。そしたらURLにアクセスする際これをスラッシュと認識して英文が/で途切れてしまう。(%2Fでも同じだった)

手法2

DeepLのサイト内で入力を行う。
まずDeepL内で文入力のsectorを探した。すると

#dl_translator > div.lmt__text > div.lmt__sides_container > div.lmt__side_container.lmt__side_container--source > div.lmt__textarea_container > div.lmt__inner_textarea_container > textarea

にあることが分かった。
ここをfindしてtextを入れる。

insec="#dl_translator > div.lmt__text > div.lmt__sides_container > div.lmt__side_container.lmt__side_container--source > div.lmt__textarea_container > div.lmt__inner_textarea_container > textarea"
driver.find_element_by_css_selector(insec).send_keys(text)

訳文を抽出する

上と同様にtextareaを見つけて抽出しようとしたができなかった。
そのため別のところを探すと
#target-dummydiv のinnerHTMLにあることが分かった。

image.png
※訂正

"#dl_translator > div.lmt__text > div.lmt__sides_container > div.lmt__side_container.lmt__side_container--target > div.lmt__textarea_container > div.lmt__inner_textarea_container > textarea"

の"value"にありました

あとはここをfindしてinnerHTML valueを取り出す。
ここで翻訳が終わっていないと"\r\n"が取り出されるため、それ以外のものが取れるまで1秒ごとに操作を行う。

outsec="#dl_translator > div.lmt__text > div.lmt__sides_container > div.lmt__side_container.lmt__side_container--target > div.lmt__textarea_container > div.lmt__inner_textarea_container > textarea"
while 1:
    Outputtext =  driver.find_element_by_css_selector(outsec).get_attribute("value")
    if Outputtext != "" :
        break
    time.sleep(1)
driver.quit

最後に末尾の"\r\n"を取って訳文Outputtextを獲得...と行きたいところだが、ここでHTML上では特殊文字について、例えば">"は"&gt ;"で書かれているからそれを普通の記号に変換するためにunescapeに通す。

Outputtext=unescape(Outputtext)
return Outputtext

これで翻訳については完了。
あとはこれをBOTに入れるだけである。

BOT作成

BOTについては基本的な動作を行うだけなため@1ntegrale9様のこの記事を参考にするといいかも。
またseleniumとchromedriver_binaryをHerokuで使う際、Setting->Buildpacksに以下の二つのURLを入れることに注意。
https://github.com/heroku/heroku-buildpack-google-chrome.git
https://github.com/heroku/heroku-buildpack-chromedriver.git

deeplbot.py
import translate.py
import discord
import asyncio
TOKEN = '自分のtokenを入れてね'
client = discord.Client()
@client.event
async def on_message(message):
    author=message.author
    dm=await author.create_dm()
    if message.channel==dm:
        honyaku = translate.deepl(message.content)
        await message.channel.send(honyaku)
client.run(TOKEN)

関数内を簡単に説明すると上から
メッセージ(英文)が送ると
まず送ってきた人をauthorとする。
そしてその人とのDMをdmとする。
そしてその人の送ってきた文章がDMからなら実行し、それ以外なら実行しない(大量のグループ内で起動すると迷惑になりそうなので)
あとはtranslate.py内の翻訳関数に通して出力をDMに再び返す。

といった感じである。

async def on_message(message):
    author=message.author #メッセージの送り主を特定
    dm=await author.create_dm() #送り主のDMを特定
    if message.channel==dm: #送ってきたチャンネルがDMか判断
        if __name__ == '__main__': 
            honyaku = deepl2.deepl(message.content) #翻訳関数実行
            await message.channel.send(honyaku) #送り主のDMに返す

実行してみた

image.png
15秒ぐらいで返ってきた。(まぁ妥協点?)

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3