1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

M1macのdockerコンテナでseleniumを動作させる方法

Posted at

はじめに

M1 MacのDockerコンテナ内でSeleniumを動かす方法を紹介します。Seleniumはブラウザの自動操作を行うツールで、Pythonなどのプログラミング言語でも実行できます。ただし、Seleniumを実行するにはライブラリの他に、ブラウザや対応するドライバが必要です。

今回の実行環境であるM1 Macは、CPUのアーキテクチャがIntel系(x64)とは異なるため、Seleniumを動作させるには一手間かかります。それでは早速実装していきましょう。

実行環境

  • 機種:MacBook Air 2020年モデル(M1)
  • OS:Sonoma 14.5
  • dockerバージョン:27.1.2
  • seleniumバージョン:4.23.1
  • Chromeバージョン:128.0.6613.84

実装

フォルダ構成

.
├── Dockerfile
└── app
    ├── __init__.py
    ├── app.py
    └── requirements.txt

Dockerfile

seleniumは他のPythonライブラリとは違い、ブラウザやブラウザのドライバが必要になります。コンテナイメージを作成する際に、それらのツールをライブラリと一緒にインストールします。今回はブラウザにChromeを選択しました。


FROM --platform=linux/amd64 python:3.11-slim

# wget, curl, unzipをインストール
RUN apt-get update && \
    apt-get install -y wget curl unzip && \
    apt-get -y clean && \
    rm -rf /var/lib/apt/lists/*

# Chromeをインストール
RUN wget "https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" && \
    apt-get update && \
    dpkg -i ./google-chrome-stable_current_amd64.deb || apt-get install -f -y && \
    rm ./google-chrome-stable_current_amd64.deb && apt-get -y clean && \
    which google-chrome-stable

# ChromeDriverをインストール
# 参考 https://qiita.com/casareal_user/items/f932c32517e0d6118809

FROM --platform=linux/amd64 python:3.11-slim

# wget, curl, unzipをインストール
RUN apt-get update && \
    apt-get install -y wget curl unzip && \
    apt-get -y clean && \
    rm -rf /var/lib/apt/lists/*

# Chromeをインストール
RUN wget "https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" && \
    apt-get update && \
    dpkg -i ./google-chrome-stable_current_amd64.deb || apt-get install -f -y && \
    rm ./google-chrome-stable_current_amd64.deb && apt-get -y clean && \
    which google-chrome-stable

# ChromeDriverをインストール
RUN apt-get update && apt-get install -y unzip graphviz && \
    CHROME_VERSION=$(google-chrome-stable --version | cut -d" " -f3) && \
    echo "Chrome_Version: ${CHROME_VERSION}" && \
    echo "$(google-chrome-stable --version)" && \
    wget "https://storage.googleapis.com/chrome-for-testing-public/128.0.6613.84/linux64/chromedriver-linux64.zip" &&\
    unzip chromedriver-linux64.zip -d /tmp/ && \
    rm chromedriver-linux64.zip && \
    chown root:root /tmp/chromedriver-linux64/chromedriver && \
    chmod 755 /tmp/chromedriver-linux64/chromedriver && \
    mv /tmp/chromedriver-linux64/chromedriver /usr/bin/chromedriver && \
    chromedriver --version || apt-get install -f -y

# 作業ディレクトリを設定
WORKDIR /app

VOLUME /app

# 依存関係をコピー
COPY ./app/requirements.txt .

# 依存関係をインストール
RUN pip install --no-cache-dir -r requirements.txt

# パスを通す
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/chrome

# アプリケーションのソースコードをコピー
COPY ./app .

# コンテナ起動時に実行するコマンドを指定
CMD ["python", "app.py"]

今回重要になってくるのが以下の部分です。

FROM --platform=linux/amd64 python:3.11-slim

Chromeはamd64系のドライバしか提供されていません。プラットフォームを選択せずに動作させると、M1 Macと同じarm系の環境でコンテナイメージが作成されてしまい、ブラウザやドライバがインストールできなくなります。明示的にプラットフォームを選択することで、コンテナイメージの環境をamd64にします。

app.py

Example Domainを表示してスクリーンショットを作成する処理です。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options


def main():

    try:
        # データの取得・成型
        chromedriver_bin = "/usr/bin/chromedriver"
        service = Service(executable_path=chromedriver_bin)

        # Chromeオプションを設定
        options = Options()
        options.add_argument("--headless")
        options.add_argument("--no-sandbox")
        options.add_argument("--disable-dev-shm-usage")
        options.add_argument("--disable-gpu")
        options.add_argument("--window-size=1920x1080")

        driver = webdriver.Chrome(service=service, options=options)

        driver.get("https://example.com/")
        
        page_content = driver.page_source

        print(page_content)

        driver.quit()

    except Exception as e:
        print(e)
        raise e 

    return 

if __name__ == "__main__":
    main()

特に重要となってくるのが、Optionで指定している部分になります。

        options = Options()
        options.add_argument("--headless")
        options.add_argument("--no-sandbox")
        options.add_argument("--disable-dev-shm-usage")
        options.add_argument("--disable-gpu")
        options.add_argument("--window-size=1920x1080")

コンテナ内で実行するときはGUIが利用できないため、ブラウザの画面を表示しないで処理するヘッドレスモードで実行する必要があります。

requirements.txt

Selenium以外も実行していたので、必須パッケージより若干多くなっています。

attrs==24.2.0
beautifulsoup4==4.12.3
blinker==1.7.0
botocore==1.34.88
bs4==0.0.2
certifi==2024.7.4
charset-normalizer==3.3.2
click==8.1.7
h11==0.14.0
idna==3.8
itsdangerous==2.2.0
Jinja2==3.1.3
jmespath==1.0.1
MarkupSafe==2.1.5
outcome==1.3.0.post0
PySocks==1.7.1
python-dateutil==2.9.0.post0
requests==2.32.3
s3transfer==0.10.1
selenium==4.23.1
six==1.16.0
sniffio==1.3.1
sortedcontainers==2.4.0
soupsieve==2.6
trio==0.26.2
trio-websocket==0.11.1
typing_extensions==4.12.2
urllib3==2.2.1
websocket-client==1.8.0
Werkzeug==3.0.2
wsproto==1.2.0

実行テスト

docker build -t selenium-sample .
docker run -it selenium-sample 

私の場合、実行したときに以下のような警告が出ました。
コンテナのプラットフォームと実行環境のプラットフォームが異なるときに出るのだと思います。

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

コンテナのボリュームを確認すると、以下のスクリーンショットが保存されていました。

screenshot.png

終わりに

M1 MacのDockerコンテナでSeleniumを動作させる方法をまとめました。Seleniumはブラウザを自動実行してくれるので便利ですが、依存関係が複雑だったり、実行環境に依存する部分が大きいです。今回、コンテナイメージにまとめてどこでも実行できるようになったので、移植性が大きく向上し、満足しています。

後日談

後から調べたら、公式からSeleniumのコンテナイメージが公開されていることに気づきました。

自分で作るときは、すでに存在しないか調べてから作るようにしましょう。車輪の再開発になってしまいます。(1敗) ただ、車輪の再開発も自分の技術力向上につながるので、悪いことではないと思っています。

参考文献

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?