no-image

Google翻訳で翻訳された文章をとってくる【python, PhantomJS】

pythonでサイトにとばずにgoogle翻訳させる

前回の計画【webスクレイピング計画【実行したらグーグル翻訳に飛ばして、訳を受け取って表示する。】】ではbs4とrequestsとpyperclipを使ってgoogle翻訳をとってこようと計画をねっていました。しかしながら、bs4,requestsだけではクリック操作が模倣できないのです。しかしクリック操作は必要ないことに私は気づきました。

しかもまだあります。このPhantomJSを使わなくてもできるのではないかということに気づきました。ただ今回はPhantomJSを使ったやり方が成功したのでお届けしたいと思います。

Google翻訳の特徴を理解する。

google翻訳の特徴を理解すれば、納得できる部分があります。仕組みまではわかりませんが、スクリプトを書く時の手助けになります。次に特徴をあげていきます。

  • 左の欄に英文を入力するとそれがそのままURLになる。
  • 日本語翻訳はクリックしなくても自動的に行われる
  • 翻訳されたものはクラス名を指定しても取得できない(なぜかは不明)
  • span要素の50番目あたりに翻訳のwebエレメントがある。

PhantomJSはseleniumがサポートしている。

まずPhantomJSとはなんですか?ときかれると僕もこたえることができません。しかしざっくり説明したとすると、ヘッドレスブラウザといってブラウザの画面が表示されないので作業の邪魔にならないという利点があります。pythonではseleniumモジュールと組み合わせることでPhantomJSを使うことができます。PhantomJSを使うメリットデメリットをあげます。(素人目線なので参考になるかどうかはわかりません。)

PhantomJSを使うメリット

PhantomJSなどのヘッドレスブラウザをつかうと、ブラウザが立ち上がらないので作業の邪魔にならない。

PhantomJSを使うデメリット

  • 何がおきているのか目でみえない。
  • 以外と動作がもっさりしている
  • 見えないので精神的に恐い

PhantomJSはデメリットのほうが多い結果となりましたが、ブラウザが立ち上がらないというのはやはり強いですね。今回紹介する方法はあくまでもPhantomJS単体ではなくpythonのseleniumモジュールでPhantomJSを使うやり方です。自分も素人なのでどういう仕組みで動いているのか奥深くのことはわかりません。

Google翻訳からPhantomJSを使って翻訳したものをとってくるコード

import pyperclip
from selenium import webdriver

driver = webdriver.PhantomJS()
driver.get("https://translate.google.co.jp/?hl=ja#en/ja/" + pyperclip.paste())
spanlist = driver.find_elements_by_tag_name("span")
for i in range(50, 60):
 print(spanlist[i].text)
driver.quit()

おもしろいのは5行目でpyperclip.paste()を使っているところです。こうすることによって英文をコピーしてこのプログラムを実行すれば、すぐに結果を得ることができます。もしくはsysモジュールを使って、コマンドライン引数でプログラムを実行してもおもしろいかもしれません。

問題は6,7行目です。

6行目はelements_by_tag_name(‘span’)としています。これでspan要素がリストにできます。7行目がいやらしいです。range(50, 60)としているのはその辺に翻訳されたエレメントがあるからです。少々野暮な書き方ですが、これでとれるのでこのままにしておきます。

最後にPhantomJSは意外に動作が遅いです。都度Google翻訳を開いて貼り付けても良いかもしれません。

追記: requests、bs4ではうまく要素を取得できませんでした。

import pyperclip, requests, bs4, pprint

res = requests.get('https://translate.google.co.jp/?hl=ja#en/ja/' + pyperclip.paste())
res.raise_for_status() 
soup = bs4.BeautifulSoup(res.text)
elems = soup.select('span')
for i in range(len(elems)):
 print(elems[i].getText())

やっていることは最初のコードと同じですが、span要素をうまく拾ってくることができませんでした(原因はわかりません。)またclassやidを指定しても、getText()でとってくることができませんでした。