背景
スクレイピングを定期的に実行する場合、Lambdaなどのクラウド上で実行したいと考えています。今回、lambda環境上への環境構築に大変苦労したので、最終的にうまく言った方法をまとめたいと思います。
目的
Lambda上でSeleniumによるスクレイピングをするための方法をまとめる。
結論
ChromeとChromeWebDriverを含めたDocker Imageを作成し、デプロイすることでスクレイピングできる。
前提条件
Python 3.13.0
Chrome 131.0.6778.204
Chrome Driver 131.0.6778.204
Selenium 4.27.1
方針
Lambda上にChrome, Chrome Driverを使用した環境をデプロイするためには、大きく分けて二つの方法があります。
- Lambda Layerとして定義する。
- Dockerでイメージ化する。
調べると2020年前後の1.の方法が結構出てきますが、自分の環境ではエラーが出てなかなかうまくいきませんでした。そのため、2.の方法をとることにしました。
やり方
基本のDockerFile
こちらのリポジトリがdockerでseleniumを利用するための環境構築コードが公開されており非常に使いやすいです。また、自動で最新版のChromeにアップデートされているようです。
FROM public.ecr.aws/lambda/python@sha256:f5b51b377b80bd303fe8055084e2763336ea8920d12955b23ef8cb99dda56112 as build
RUN dnf install -y unzip && \
curl -Lo "/tmp/chromedriver-linux64.zip" "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.204/linux64/chromedriver-linux64.zip" && \
curl -Lo "/tmp/chrome-linux64.zip" "https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.204/linux64/chrome-linux64.zip" && \
unzip /tmp/chromedriver-linux64.zip -d /opt/ && \
unzip /tmp/chrome-linux64.zip -d /opt/
FROM public.ecr.aws/lambda/python@sha256:f5b51b377b80bd303fe8055084e2763336ea8920d12955b23ef8cb99dda56112
RUN dnf install -y atk cups-libs gtk3 libXcomposite alsa-lib \
libXcursor libXdamage libXext libXi libXrandr libXScrnSaver \
libXtst pango at-spi2-atk libXt xorg-x11-server-Xvfb \
xorg-x11-xauth dbus-glib dbus-glib-devel nss mesa-libgbm
RUN pip install selenium==4.27.1
COPY --from=build /opt/chrome-linux64 /opt/chrome
COPY --from=build /opt/chromedriver-linux64 /opt/
COPY main.py ./
CMD [ "main.handler" ]
DockerFileは、Chromeのバージョンによりcurlコマンドのコマンドが変わります。最新版は下のリンクが参考になります。
https://github.com/umihico/docker-selenium-lambda/blob/main/Dockerfile
独自パッケージなどの追加
独自のパッケージを追加する場合には、DockerFileに追記することでDockerイメージに組み込むことができます。
# ライブラリのインストール(例)
COPY requirements.txt ./
RUN pip install -r requirements.txt -t .
# ファイルのコピー(例)
COPY _libs/ ./_libs/
呼び出し部分
DockerFilleでlambda関数の入りをmain.handler
と指定しているため、main.py>def handler関数を実装します。
from selenium import webdriver
from tempfile import mkdtemp
from selenium.webdriver.common.by import By
def handler(event=None, context=None):
options = webdriver.ChromeOptions()
options.binary_location = '/opt/chrome/chrome' # ダウンロードしたChromeのファイル指定
service = webdriver.ChromeService("/opt/chromedriver") # ダウンロードしたChromeDriverのファイル指定
# Chromeの起動オプション
# 一覧ページ→https://peter.sh/experiments/chromium-command-line-switches/
options.add_argument("--headless=new") # ヘッドレスモードで起動する。
options.add_argument('--no-sandbox')
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1280x1696")
options.add_argument("--single-process")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-dev-tools")
options.add_argument("--no-zygote")
options.add_argument(f"--user-data-dir={mkdtemp()}")
options.add_argument(f"--data-path={mkdtemp()}")
options.add_argument(f"--disk-cache-dir={mkdtemp()}")
options.add_argument("--remote-debugging-port=9222")
chrome = webdriver.Chrome(options=options, service=service)
chrome.get("https://example.com/")
return chrome.find_element(by=By.XPATH, value="//html").text