知る人ぞ知るDeepL翻訳に関する内容です。
そもそも、DeepL翻訳を利用したことがありますか?
利用したことがない方は、是非1度試してみてください。
https://www.deepl.com/translator
正直、Google翻訳を超えています。
おそらく世界最高レベルだと思います。
DeepL翻訳を使い出すと、Google翻訳はもう使えません。
Google翻訳で感動していた時代もありましたが・・・
それだけ精度の高いDeepL翻訳には、APIが用意されています。
でも、有料です。
それに従量課金なのです。
このAPIは、企業向けなのでしょうね。
我々のような一般人は、Webやアプリでチマチマしておけと言うことです。
そんな意地悪をされると、抵抗したくなってしまいます。
Webで公開されている以上、スクレイピングできないモノはありません。
だから、スクレイピングしてAPIみたいなモノを勝手に作りました。
簡単に言うと、俺流APIです。
本記事の内容
- DeepL翻訳のスクレイピング戦略
- 翻訳したい文章の入力
- JavaScriptによる動的コンテンツの読み込み
- 翻訳された文章の取得
- DeepL翻訳のスクレイピングするサンプルコード
それでは、上記に沿って解説していきます。
DeepL翻訳のスクレイピング戦略
DeepL翻訳のスクレイピングは、少し毛色の違うスクレイピングになります。
過去にAmazonやTwitterをスクレイピングしてきました。
記事にも書いていますが、Twitterは過去最高レベルの難易度でした。
でも、SeleniumとPythonの組み合わせでスクレイピングに成功しました。
おそらく、Twitterはすぐに仕様(デザイン変更)を変更するとは思いますが。
Twitterと比べると、DeepL翻訳のスクレイピング難易度はかなり落ちます。
しかし、少々発想を変える必要があります。
その部分への対応を中心に戦略を考えます。
まず、翻訳したい文章を入力する必要があります。
翻訳ツール画面の左側のエリアに文章を入力する必要があるということです。
そして、次は翻訳された文章の取得ですね。
左側のエリアに文字が設定されると、自動的に右側のエリアに翻訳された文字が表示されます。
随時左側のエリアに文字をJavaScriptで監視しているのでしょう。
だから、「翻訳」ボタンのようなモノが存在していません。
以上が翻訳ツールの仕様です。
大まかな方向性(戦略)は以下。
- 翻訳ツール画面に翻訳したい文章を渡す
- 動的コンテンツを読み込む
- 翻訳された文章が表示されるまで待つ
これらをクリアすれば、DeepL翻訳がスクレイピング可能です。
それでは、以下でそれらを解説していきます。
翻訳したい文章の入力
「翻訳ツール画面に翻訳したい文章を渡す」
これに対応するためには、クエリを工夫します。
翻訳ツール画面のURLは以下です。
https://www.deepl.com/ja/translator
この画面で左側に「 この文章を翻訳します 」を入力してみてください。
そうすると、アドレスバーが自動的に以下に変更されます。
https://www.deepl.com/ja/translator#ja/en/この文章を翻訳します
これはJavaScriptで動的に変更しています。
このURL(#以降)は次のことを意味しています。
ja | 翻訳前の文章の言語 |
en | 翻訳後の文章の言語 |
この文章を翻訳します | 翻訳対象の文章 |
なお、右側には以下の結果が表示されています。
I will translate this sentence.
Pythonのコードは、以下のようにしてURLを作成しています。
# url作成 url = 'https://www.deepl.com/translator#' + from_lang +'/' + to_lang + '/' + from_text
JavaScriptによる動的コンテンツの読み込み
「動的コンテンツを読み込む」
これに対しては、Seleniumを使います。
Seleniumに関しては、次の記事で解説しています。
Seleniumは、ブラウザをPythonなどのプログラムから操作できるための仕組みです。
また、Selenium自体でもスクレイピングは可能です。
ただ、今回はSeleniumを用いたスクレイピングは行いません。
Seleniumは、アクセスしたページ(全体)の情報を取得するまでをその役割とします。
スクレイピングは、プロに任せます。
BeautifulSoupで行います。
翻訳された文章の取得
「翻訳された文章が表示されるまで待つ」
これが、DeepL翻訳のスクレイピングで最も難しい箇所になります。
この要素の中に翻訳された文章が設定されます。
<button class="lmt__translations_as_text__text_btn"></button>
「この文章を翻訳します」を翻訳した場合、以下のようになります。
<button class="lmt__translations_as_text__text_btn">I will translate this sentence.</button>
これ自体は、BeautifulSoupを使えば簡単にスクレイピングできます。
じゃあ、何が難しいのか?
タイミングです。
buttonタグの間にテキストが入るタイミングがわからないのです。
そのため、テキストが入るまで確認し続けるという対応をしています。
もっとスマートにしたかったのですが・・・
for i in range(try_max_count): # 指定時間待つ time.sleep(sleep_time) html = driver.page_source to_text = get_text_from_page_source(html) try_count = i + 1 if to_text: wait_time = sleep_time * try_count print(str(wait_time) + "秒") # アクセス修了 break
翻訳時間は、どれだけ長くても10秒ぐらいでしょう。
なお、ここでのループ処理はサイトへのアクセスではありません。
あくまで、開いているブラウザ上での操作(テキストの存在チェック)がループしているだけです。
よって、何回ループしようがサイトには迷惑はかかりません。
スクレイピングする者にとっては、ここは大事な部分です。
DeepL翻訳のスクレイピングするサンプルコード
最後に、俺流APIのコードを載せておきます。
APIと言ってもAPIのようには、洗練されていません。
個人的に使うことを想定していますので。
あと、DeepL翻訳側がデザイン・仕様を変更したら、その時点で動かなくなるかもしれません。
2020年08月03日時点
from selenium import webdriver from selenium.webdriver.chrome.options import Options from bs4 import BeautifulSoup import time import urllib.parse sleep_time = 1 try_max_count = 30 chrome_driver = 'chromedriver.exeのパス' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36' } def get_translated_text(from_lang, to_lang, from_text): # urlencode from_text = urllib.parse.quote(from_text) # url作成 url = 'https://www.deepl.com/translator#' + from_lang +'/' + to_lang + '/' + from_text # ヘッドレスモードでブラウザを起動 options = Options() options.add_argument('--headless') # ブラウザーを起動 driver = webdriver.Chrome(chrome_driver, options=options) driver.get(url) driver.implicitly_wait(10) # 見つからないときは、10秒まで待つ for i in range(try_max_count): # 指定時間待つ time.sleep(sleep_time) html = driver.page_source to_text = get_text_from_page_source(html) try_count = i + 1 if to_text: wait_time = sleep_time * try_count print(str(wait_time) + "秒") # アクセス修了 break # ブラウザ停止 driver.quit() return to_text def get_text_from_page_source(html): soup = BeautifulSoup(html, features='lxml') target_elem = soup.find(class_="lmt__translations_as_text__text_btn") text = target_elem.text return text def get_from_text(): f = open('./data/translate.txt') data = f.read() return data if __name__ == '__main__': from_lang = 'ja' to_lang = 'en' #from_text = '提供された翻訳の正確性やサービスの利用可能性について、一切の責任を負いません。' from_text = get_from_text() # 翻訳 to_text = get_translated_text(from_lang, to_lang, from_text) print(to_text)