Chrome Driverとバイナリーのバージョンを一致させるためのDockerfileの書き方
Seleniumでスクレイピングするには、Chrome Driveとバイナリーの両方が必要になりますが、両者のバージョンの一貫性をDockerfile内で保つことにややハマったので自分なりの解決方法を書きます。
目次
はじめに
- Seleniumでスクレイピングするには、Chrome Driverとバイナリー(本体)が必要
- 両者のバージョンは基本的に一致している必要がある
- Driverはバージョンにあわせて公開してある
- Google Chromeのバイナリーは最新バージョンしか公開していない
- 両者のバージョン同期は、落としたバイナリーを見れば可能だが、それを自動的にDockerfile内でやる方法はないだろうか? というのがこの記事の目的
結論
Chrome DriverのDLを最新のバージョンになるように工夫する。具体的には以下の通り
# Install Chrome binary
RUN curl -O https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
apt-get install -yq --no-install-recommends ./google-chrome-stable_current_amd64.deb && \
apt-get clean && rm google-chrome-stable_current_amd64.deb
# Install Chrome Driver (Get Latest Version)
RUN curl -O https://chromedriver.storage.googleapis.com/$(curl -s https://chromedriver.storage.googleapis.com/LATEST_RELEASE)/chromedriver_linux64.zip && \
unzip chromedriver_linux64.zip && \
mv chromedriver /usr/local/bin/ && \
rm chromedriver_linux64.zip
Chrome Dirverの最新バージョンを取得するAPI
Chrome Driverの最新バージョンは以下のURLで取得でき、文字列として返ってきます。
https://chromedriver.storage.googleapis.com/LATEST_RELEASE
例えば、CURLで叩いてみると、
> curl https://chromedriver.storage.googleapis.com/LATEST_RELEASE
114.0.5735.90
このようになるので、wgetの中で展開すれば最新版が落ちてくるという仕組み。ただし、Google Chromeのバージョンアップと、Chrome Driverのバージョンアップは必ずしも連動はしていないので、ズレることがあるというのが問題点。
Google Chromeではなく、Chromiumのバイナリを使うという方法もあるが、ここでは割愛。
サンプルコード
以下のようなディレクトリ構成にする
+ src
- app.py
+ docker-compose.yaml
+ Dockerfile
+ requirements.txt
Dockerfile
FROM ubuntu:22.04
RUN apt-get update
ENV TZ=Asia/Tokyo
ENV LANG=en_US.UTF-8
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get install -yq --no-install-recommends python3-pip \
python3-dev \
curl \
unzip \
tzdata && apt-get upgrade -y && apt-get clean
RUN ln -s /usr/bin/python3 /usr/bin/python
# Install Chrome binary
RUN curl -O https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
apt-get install -yq --no-install-recommends ./google-chrome-stable_current_amd64.deb && \
apt-get clean && rm google-chrome-stable_current_amd64.deb
# Install Chrome Driver (Get Latest Version)
RUN curl -O https://chromedriver.storage.googleapis.com/$(curl -s https://chromedriver.storage.googleapis.com/LATEST_RELEASE)/chromedriver_linux64.zip && \
unzip chromedriver_linux64.zip && \
mv chromedriver /usr/local/bin/ && \
rm chromedriver_linux64.zip
COPY requirements.txt .
RUN pip install -U pip &&\
pip install --no-cache-dir -r requirements.txt
※最小限の構成で、Docker上でSeleniumを動かすための環境しか作っていない
requirements.txt
selenium
docker-compose.yaml
services:
selenium:
build: .
image: chrome_web_driver_sample
volumes:
- ./src:/src
container_name: web-driver-container
stdin_open: true
tty: true
ローカルのソースディレクトリをマウントしているほか、擬似端末を入れています。
app.py
from selenium import webdriver
from selenium.webdriver.common.by import By
def extract_yahoo_topic():
options = webdriver.chrome.options.Options()
options.add_argument('--no-sandbox')
options.add_argument("--headless")
with webdriver.Chrome(options=options) as driver:
driver.get("https://www.yahoo.co.jp/")
element = driver.find_element(By.CSS_SELECTOR, "section#tabpanelTopics1")
print(element.text)
if __name__ == "__main__":
extract_yahoo_topic()
試しにYahoo Japanのトップトピックを抜いてprintしています。
実行・結果
ビルドと実行はいつもの通りで、
# ビルド
docker-compose build
# 実行
docker-compose up
別ウィンドウ(WSL)からコンテナをアタッチしてPythonコードを実行させます。
~$ docker attach web-driver-container
root@1cb160436669:/# cd src
root@1cb160436669:/src# python app.py
主要 ニュース
7/17(月) 0:19更新
東北 少しの雨でも土砂災害に警戒
NEW
16
マイナ対応「評価せず」68% 朝日
NEW
スーパーで実弾を一時紛失 兵庫県
NEW
539
海で子ども救助に向かい 父親死亡
NEW
1003
人気バッグ由来 バーキンさん死去
四球確信し一塁へ 判定にSBあ然
2297
小田凱人17歳 ウィンブルドン初V
488
民放 バラエティー量産が終えん?
1542
つかの間の涼
7/16(日) 18:45
神戸新聞NEXT
もっと見る
トピックス一覧
コンテナ消したいときはdocker-compose downで。
結論
とりあえずこれで使えるから良さそう(バージョンをハードコーディングするのもどうかなと思ったので)
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
北海道の駅巡りコーナー