はじめに
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
コンテナのボリュームを確認すると、以下のスクリーンショットが保存されていました。
終わりに
M1 MacのDockerコンテナでSeleniumを動作させる方法をまとめました。Seleniumはブラウザを自動実行してくれるので便利ですが、依存関係が複雑だったり、実行環境に依存する部分が大きいです。今回、コンテナイメージにまとめてどこでも実行できるようになったので、移植性が大きく向上し、満足しています。
後日談
後から調べたら、公式からSeleniumのコンテナイメージが公開されていることに気づきました。
自分で作るときは、すでに存在しないか調べてから作るようにしましょう。車輪の再開発になってしまいます。(1敗) ただ、車輪の再開発も自分の技術力向上につながるので、悪いことではないと思っています。
参考文献