Ruby + Selenium + Chrome + Dockerでスクレイピング
概要
Ruby + Selenium + Chrome + Dockerでスクレイピングする方法を模索していたところ下記のような記事にたどり着いた。
しかし、バージョン115以降のChromeDriverは配置先が別サーバーに移行したようで、上記の記事の手法は使用できなくなっていた。そこで新サーバーに対応したスクレイピング環境を構築する手法を調査した。追記(2024-02-20)
https://googlechromelabs.github.io/chrome-for-testing/ を確認すると、ChromeとChromeDriverの保管先が変更された様子。
Dockerfile中のhttps://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing
となっている箇所を、適宜https://storage.googleapis.com/chrome-for-testing-public
に変更する必要あり。
調査
バージョン115以降のChromeDriverの配置先は以下になっている。
ちなみに114以前は以下で公開されている。 また、安定版やベータ版のバージョン番号を取得するAPIも以下で公開されている。 ChromeとChromeDriverのバージョンを一致させないとSeleniumが正常に動作しないため、- 安定版のバージョン番号をAPIから取得。
- 該当のバージョンのChromeをダウンロード。
- 該当のバージョンのChromeDriverをダウンロード。
という流れ環境を構築していく。
実際のDockerfile
# ARMを使用するとエラーが出るのでAMDを使用
FROM ruby:3.2.2
# 変数の設定
ARG APP_ROOT="/app"
ARG CHROME_PACKAGES="libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2"
ARG CHROME_WEBDRIVER_PACKAGES="libnss3-dev"
# 必要なライブラリのインストール
RUN apt update -qq \
&& apt install -y ${CHROME_PACKAGES} \
&& apt install -y ${CHROME_WEBDRIVER_PACKAGES}
# Chrome & Chrome Driverのインストール
RUN CHROME_VERSION=`curl -sS https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_STABLE` \
&& curl -sS -o /tmp/chrome-linux64.zip https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/$CHROME_VERSION/linux64/chrome-linux64.zip \
&& unzip -d /tmp /tmp/chrome-linux64.zip \
&& mkdir -p /usr/local/lib/chrome \
&& mv /tmp/chrome-linux64/* /usr/local/lib/chrome \
&& ln -s /usr/local/lib/chrome/chrome /usr/local/bin/chrome \
&& curl -sS -o /tmp/chromedriver-linux64.zip https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/$CHROME_VERSION/linux64/chromedriver-linux64.zip \
&& unzip -d /tmp /tmp/chromedriver-linux64.zip \
&& mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin
# Seleniumのスクショが文字化けしないように日本語フォントをインストール
RUN curl -sS -o /tmp/NotoSansCJKjp-hinted.zip https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \
&& unzip -d /tmp/NotoSansCJKjp-hinted /tmp/NotoSansCJKjp-hinted.zip \
&& mkdir -p /usr/share/fonts/noto \
&& cp /tmp/NotoSansCJKjp-hinted/*.otf /usr/share/fonts/noto/ \
&& chmod 644 /usr/share/fonts/noto/*.otf \
&& fc-cache -fv
# ファイルを全コピー
WORKDIR $APP_ROOT
COPY . ${APP_ROOT}/
# Gemのインストール
RUN bundle install -j4 \
&& bundle clean --force
# お掃除
RUN rm -rf /tmp/*
# サーバー起動コマンド
CMD ["rails", "server", "-b", "0.0.0.0"]
雑解説
ARG CHROME_PACKAGES="libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2"
ARG CHROME_WEBDRIVER_PACKAGES="libnss3-dev"
でChromeやChromeDriverが依存しているパッケージをインストールするための準備をしている。
これらは地道に調べた。ChromeやChromeDriverのバージョンによっては必要なパッケージが変わる可能性があるので要注意。
次に
RUN CHROME_VERSION=`curl -sS https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_STABLE` \
&& curl -sS -o /tmp/chrome-linux64.zip https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/$CHROME_VERSION/linux64/chrome-linux64.zip \
&& unzip -d /tmp /tmp/chrome-linux64.zip \
&& mkdir -p /usr/local/lib/chrome \
&& mv /tmp/chrome-linux64/* /usr/local/lib/chrome \
&& ln -s /usr/local/lib/chrome/chrome /usr/local/bin/chrome \
&& curl -sS -o /tmp/chromedriver-linux64.zip https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/$CHROME_VERSION/linux64/chromedriver-linux64.zip \
&& unzip -d /tmp /tmp/chromedriver-linux64.zip \
&& mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin
というコマンドの意味をざっくり解説する。
まず1行目の
RUN CHROME_VERSION=`curl -sS https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_STABLE` \
で変数CHROME_VERSIONに安定版のバージョンを格納する。
その次の2~6行目の
&& curl -sS -o /tmp/chrome-linux64.zip https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/$CHROME_VERSION/linux64/chrome-linux64.zip \
&& unzip -d /tmp /tmp/chrome-linux64.zip \
&& mkdir -p /usr/local/lib/chrome \
&& mv /tmp/chrome-linux64/* /usr/local/lib/chrome \
&& ln -s /usr/local/lib/chrome/chrome /usr/local/bin/chrome \
ではChromeをインストール、7~9行目の
&& curl -sS -o /tmp/chromedriver-linux64.zip https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/$CHROME_VERSION/linux64/chromedriver-linux64.zip \
&& unzip -d /tmp /tmp/chromedriver-linux64.zip \
&& mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin
ではChromeDriverをインストールしている。
ChromeDriverはzipファイルを解凍すると1つの実行ファイルになるので、/usr/local/bin
にそのまま移動してやれば使えるようになるが、Chromeは複数のファイルから構成されているので、それらのファイルを1つのディレクトリにまとめて/usr/local/lib
に保存してやり、シンボリックリンクだけを/user/local/bin
に作成するのがベタなやり方らしい。
Linuxのディレクトリの役割などを全く理解できていないので勉強になった。
参考
Discussion