この記事は YAMAP エンジニア Advent Calendar 2020 の 23日目の記事となります。
ダイジェスト
Selenium をサーバで定期実行しようと思ったら、日本語化や長時間処理などでハマったので晒します。
興味のある方は続きをお読みいただければと思います。
※実施したときからかなりの時間が経過しており、記憶があいまいな部分は記載を省略しております。予めご了承ください。
動機
ヤボ用で、とあるWebページを定期的にスクレイピングしてゴニョゴニョしたいなと思い立ちまして、Selenium でサクッとやってサーバで定期実行したら良いだろうと軽い気持ちでやってみました。
まずはローカルで動かしてみる
今回はサンプルなので Yahoo! JAPAN のトップニュース見出しを取得してみます。
本来はあれしたり、これしたりと色々なことをやっています。
試しに赤丸部分を取得します
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("--disable-extensions")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(executable_path="./chromedriver", options=options)
driver.get("https://www.yahoo.co.jp/")
news = driver.find_element_by_xpath("//*[@id=\"tabpanelTopics1\"]/div/div[1]/ul/li[1]/article/a/div/div/h1/span").text
print(news)
driver.close()
> python3 sample.py
イベント 上限再び5千人に
取得できました。
Heroku上で実行する
詳しい説明は割愛しますが、ポイントは Selenium のオプション設定で headless を指定して executable_path を変更します。
options = Options()
options.add_argument("--disable-gpu")
options.add_argument("--disable-extensions")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--headless")
driver = webdriver.Chrome(executable_path="/app/.chromedriver/bin/chromedriver", options=options)
ハマリポイント1: スクショ取ってみたら日本語が文字化け
つい出来心で、スクリーンショットを取って外部ストレージに保存したりすると便利なんじゃないかと思ってやってみました。
すると、あろうことか日本語が文字化けしてしまいます。。
Heroku で動かす場合は .fonts フォルダに日本語フォントの tts ファイルを置いておかないといけないようです。
今回はIPAフォントを置いたら正常に表示されました。
ハマりポイント2: Webアプリケーションが30秒でタイムアウトしてしまう
Selenium でいろんなページを処理するようにしていたらタイムアウトエラーになってしまいました。
どうやら heroku は 30 秒を超えるとタイムアウトエラーになり、30秒という設定は変更できないようです。(基本的なことらしいですが知りませんでした。)
バックグラウンド処理での実装を検討して、 Heroku Redis と RQ で何とか実装できました。
こちらを参考にしました。
https://python-rq.org/patterns/
最後に
ここまで Heroku の無料の範囲内で実装できました。いろいろとハマりましたが、何とかやりたいことを実現できました。
また、自動で Selenium の定期実行ができるようになり、スクリーンショットの外部ストレージ保存もできたので、次は自作Webアプリケーションの定期テストを自動化してみようと思います