🌈

Ruby + Selenium + Chrome + Dockerでスクレイピング

2023/11/22に公開

概要

Ruby + Selenium + Chrome + Dockerでスクレイピングする方法を模索していたところ下記のような記事にたどり着いた。
https://zenn.dev/ydammatsu/articles/49f1d8b68a920c
しかし、バージョン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の配置先は以下になっている。
https://googlechromelabs.github.io/chrome-for-testing/
ちなみに114以前は以下で公開されている。
https://chromedriver.chromium.org/downloads/version-selection
また、安定版やベータ版のバージョン番号を取得するAPIも以下で公開されている。
https://github.com/GoogleChromeLabs/chrome-for-testing#json-api-endpoints
ChromeとChromeDriverのバージョンを一致させないとSeleniumが正常に動作しないため、

  1. 安定版のバージョン番号をAPIから取得。
  2. 該当のバージョンのChromeをダウンロード。
  3. 該当のバージョンのChromeDriverをダウンロード。

という流れ環境を構築していく。

実際のDockerfile

Dockerfile
# ARMを使用するとエラーが出るのでAMDを使用
FROM --platform=linux/amd64 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"]

雑解説

Dockerfile
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のバージョンによっては必要なパッケージが変わる可能性があるので要注意。

次に

Dockerfile
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行目の

Dockerfile
RUN CHROME_VERSION=`curl -sS https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_STABLE` \

で変数CHROME_VERSIONに安定版のバージョンを格納する。
その次の2~6行目の

Dockerfile
    && 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行目の

Dokcerfile
    && 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のディレクトリの役割などを全く理解できていないので勉強になった。

参考

https://chromedriver.chromium.org/downloads/version-selection
https://googlechromelabs.github.io/chrome-for-testing/
https://github.com/GoogleChromeLabs/chrome-for-testing#json-api-endpoints
https://zenn.dev/ydammatsu/articles/49f1d8b68a920c
https://exworl.com/python-1/
https://qiita.com/sgash708/items/5040d16a231394016b19

GitHubで編集を提案

Discussion