こしあん
2023-07-17

Chrome Driverとバイナリーのバージョンを一致させるためのDockerfileの書き方


2k{icon} {views}


Seleniumでスクレイピングするには、Chrome Driveとバイナリーの両方が必要になりますが、両者のバージョンの一貫性をDockerfile内で保つことにややハマったので自分なりの解決方法を書きます。

はじめに

  • Seleniumでスクレイピングするには、Chrome Driverとバイナリー(本体)が必要
  • 両者のバージョンは基本的に一致している必要がある
  • 両者のバージョン同期は、落としたバイナリーを見れば可能だが、それを自動的に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の中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です