AWS Lambda で Selenium を利用したブラウザ自動化 (Python3.12版)

AWS Lambda で Selenium を実行

AWS Lambda は Amazon Web Servises が提供する FaaS のサービスであり、必要なときだけサーバ処理を実行できるサービスです。そのため、定期的にブラウザを自動化する Selenium を実行しているユーザも多かったでしょう。

しかし、現在 AWS Lambda で実行できる Selenium は Python 3.7 のみに限られており、Python 3.8 以降では動作させることができませんでした。また、公式より AWS Lambda の Python 3.7 は 2024 年 1 月 25 日以降、関数を更新できなくなるとの注意喚起があります。

代替手段

では AWS Lambda で Selenium を実行するにはどうすれば良いでしょうか。これまで通り Python 3.8 以降で Selenium が実行できるのを待つしかないのでしょうか。おそらく、この望みは薄いと思われます。

今回 AWS 内のサービスに限って言うと、Amazon ECR のイメージを利用した AWS Lambda が最も適した方法だと考えられます。 Amazon ECR とは Docker コンテナレジストリであり、 Docker のイメージを Amazon ECR リポジトリに配置することができます。今まで AWS Lambda しか利用したことがなければ、Docker や Amazon ECR など新しい用語が出てきて億劫になるかもしれません。下記の手順を一読して、できそうかどうか最初に確認してみてください。

前準備

1. Docker Desktop のインストール

今回は Docker を利用してイメージを作成します。下記よりご自身の環境に合った Docker Desktop をインストールしてください。
https://www.docker.com/products/docker-desktop/

Docker が正しくインストールできたかどうかは、コマンドプロンプトやターミナルなどから以下のコマンドを実行して確認できます。

> docker -v
Docker version 24.0.6, build ed223bc

Docker のバージョンが表示されていれば問題ないです。

2. AWS CLI のインストール

Docker で作成したイメージを ECR に配置するためには AWS CLI が必要です。下記よりご自身の環境に合った AWS CLI をインストールしてください。
https://aws.amazon.com/jp/cli/

AWS CLI が正しくインストールできたかどうかは、コマンドプロンプトやターミナルなどから以下のコマンドを実行して確認できます。

> aws --version
aws-cli/2.14.5 Python/3.11.6 Windows/10 exe/AMD64 prompt/off

Windows であればこのように表示されていれば問題ないです。

3. AWS CLI の初期化

AWS CLI を利用して ECR にイメージを配置するには、ご自身のアカウントのアクセスキーが必要です。

まだ発行していない方は、下記の「アクセスキーの管理 (コンソール)」を参考に「アクセスキー ID」と「シークレットアクセスキー」を取得してください。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_access-keys.html

AWS CLI の初期化は、コマンドプロンプトやターミナルなどから以下のコマンドを実行します。

> aws configure
AWS Access Key ID [None]: xxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxxxx
Default region name [None]: ap-northeast-1
Default output format [None]: json

以上で初期化は完了です。

4. Amazon ECR リポジトリの準備

Docker イメージを Amazon ECR へプッシュするには、事前にAWS コンソールよりリポジトリを作成する必要があります。
AWS へログインし、 Amazon ECR を開きます。次に、左にある「Repositories」をクリックしリポジトリ画面を開きます。次に画面右にある「リポジトリを作成」ボタンをクリックします。

リポジトリ名として「my_selenium」と入力し、「リポジトリを作成」ボタンをクリックします。

リポジトリ一覧画面に戻ると、「my_selenium」と表示されていればOKです。これで前準備は完了です。ここで表示されている URI は後で使うのでメモしておいてください。

Docker イメージの準備

Docker イメージを作成するには 2 つのファイルを用意します。任意のフォルダに下記のファイルを用意してください。

1. Dockerfile

Docker イメージを構築するためのファイルになります。今回は Selenium を利用しますので、この Dockerfile 内に Selenium をインストールするほか、 chromedriver なども含みます。

今回は下記の Dockerfile を参考にさせて頂きました。
https://github.com/umihico/docker-selenium-lambda

FROM public.ecr.aws/lambda/python@sha256:fb31ca51357519a48a90f01a76e9d550778ecfcbe8d92dd832ec49b6672e387c as build
RUN dnf install -y unzip && \
    curl -Lo "/tmp/chromedriver-linux64.zip" "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/119.0.6045.105/linux64/chromedriver-linux64.zip" && \
    curl -Lo "/tmp/chrome-linux64.zip" "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/119.0.6045.105/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:fb31ca51357519a48a90f01a76e9d550778ecfcbe8d92dd832ec49b6672e387c
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.15.2
COPY --from=build /opt/chrome-linux64 /opt/chrome
COPY --from=build /opt/chromedriver-linux64 /opt/
COPY main.py ./
CMD [ "main.handler" ]

2. main.py

実際に Selenium で実行させたい処理を記述します。 handler メソッド内に Selenium で自動化したい処理を記述してください。

from tempfile import mkdtemp

from selenium import webdriver
from selenium.webdriver.common.by import By


def handler(event, context):
    """
    Seleniumの処理
    Args:
        event: event
        context: context
    Return:
        str: HTML
    """
    options = webdriver.ChromeOptions()
    service = webdriver.ChromeService("/opt/chromedriver")

    options.binary_location = '/opt/chrome/chrome'
    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://www.google.co.jp/")

    return chrome.find_element(by=By.XPATH, value="//html").text

Docker イメージの作成

それでは Docker イメージを作成しましょう。ファイルを配置したフォルダに移動して以下のコマンドを実行します。

> docker build -t my_selenium .
[+] Building 102.6s (12/12) FINISHED                                                                       docker:default
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 1.13kB
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for public.ecr.aws/lambda/python@sha256:fb31ca51357519a48a90f01a76e9d550778ecfcbe8d9
 => [internal] load build context
 => => transferring context: 29B
 => [build 1/2] FROM public.ecr.aws/lambda/python@sha256:fb31ca51357519a48a90f01a76e9d550778ecfcbe8d92dd832ec49b6
 => CACHED [stage-1 2/6] RUN dnf install -y atk cups-libs gtk3 libXcomposite alsa-lib     libXcursor libXdamage l
 => CACHED [stage-1 3/6] RUN pip install selenium==4.15.2
 => CACHED [build 2/2] RUN dnf install -y unzip &&     curl -Lo "/tmp/chromedriver-linux64.zip" "https://edgedl.m
 => CACHED [stage-1 4/6] COPY --from=build /opt/chrome-linux64 /opt/chrome
 => CACHED [stage-1 5/6] COPY --from=build /opt/chromedriver-linux64 /opt/
 => CACHED [stage-1 6/6] COPY main.py ./
 => exporting to image
 => => exporting layers
 => => writing image sha256:a103295bc9002d1dab8811fe85a9acb2965a09188fa202c7cd5ee869f982c5af
 => => naming to docker.io/library/my_selenium

What's Next?
  View a summary of image vulnerabilities and recommendations → docker scout quickview

上記は正常にイメージが作成された様子です。
Docker Desktop の Images を確認すると、「my_selenium」が見つかります。

このイメージをリポジトリにプッシュできるように、イメージタグを付けます。次のコマンドを叩いてください。(URI は AWS ECR リポジトリ一覧に表示されていた URI に置き換えてください。)

> docker tag my_selenium:latest 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my_selenium:latest

エラーがでなければ大丈夫です。 Docker Desktop の Images を確認すると、イメージが増えていることが判ります。

Amazon ECR へプッシュ

それでは作成したイメージを Amazon ECR へプッシュしましょう。プッシュする前に認証トークンを取得し、レジストリに対して Docker クライアントを認証します。具体的には次のコマンドを実行します。(URI は Amazon ECR リポジトリ一覧に表示されていた URI に置き換えてください。)

> aws ecr get-login-password  | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
Login Succeeded

そしてイメージを Amazon ECR へプッシュします。次のコマンドを実行してください。(URI は Amazon ECR リポジトリ一覧に表示されていた URI に置き換えてください。)

> docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my_selenium:latest
The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my_selenium]
851512f85dfd: Pushed
1b692f4838d0: Pushed
b3ff196c4818: Pushed
d860993b0051: Pushed
2e876907c4f4: Pushed
f0a5a83b4296: Pushed
33a3533de21f: Pushed
15dd6c63f3a2: Pushed
1408f843530b: Pushed
c7ecf44e42ca: Pushed
63c478520da4: Pushed
latest: digest: sha256:9c2694584039fe19d22f0c3fa648acf3452716b89919fe73758ffa91760966c2 size: 2634

AWS コンソールのリポジトリ内のイメージを確認すると、イメージタグ「latest」としてイメージが追加されたことが判ります。

AWS Lambda の作成

それでは AWS コンソールの AWS Lambda を表示します。左メニューから「関数」を選択し、画面右にある「関数の作成」をクリックします。

今回は Docker イメージを作成したので、「コンテナイメージ」を選択します。関数名を入力し、「イメージを参照」ボタンをクリックしコンテナイメージ URI を選択します。最後に「関数の作成」ボタンを押すと作成が開始されます。

画面上部に「関数 my_selenium を正常に作成しました。」と表示されれば作成完了です。

関数は作成されましたが、このままではスムーズな実行が困難です。初期値である 128 MB のメモリでは処理に時間が掛かってしまうので、もっと大きな値にします。また Selenium を実行する上でタイムアウトが 3 秒は短すぎます。「設定」より「編集」をクリックし、メモリを「512 MB」、タイムアウトを「1 分 0 秒」のように適切に修正します。

設定が完了したらテストを実行してみましょう。私の環境では 10 秒程度で処理が正常に完了しました。

まとめ

今回は AWS Lambda で Selenium を実行する方法として、Amazon ECR のイメージを利用した方法を紹介しました。これであれば今後も AWS Lambda で Selenium を実行することができるので安心です。
またこの Amazon ECR を利用する方法は、ほかにも応用が効くので AWS Lambda の可能性が広がりますね。
ぜひ活用してみてください。