エンジニアの@biosugar0です。 皆さんは2020年のre:Inventで発表されたLambdaのコンテナサポートを使っていますか? この機能、個人的にはこれまでのZIPで固めてやる方法があまり好きではなかったのでとても嬉しい発表でした。
さて、今回はLambdaコンテナ内でplaywright-pythonを使う方法を紹介します。(playwright自体の使い方の説明はしません)
Playwrightは、マイクロソフトが開発しているブラウザ操作を自動化するためのライブラリおよびCLIツールです。このようなライブラリはpuppeteerやseleniumも有名ですね。 主にNode.jsライブラリとして開発されていますが、python用のplaywright-pythonもあり、今回はこちらを使います。
使用したbaseイメージは public.ecr.aws/lambda/python:3.8
です。
Lambdaで使用するためのコンテナイメージは何でもいいわけではなく、いくつかの条件があります。
一番簡単なのはAWSが用意しているベースイメージを利用することです。
今回もPython用の公式ベースイメージを使います。
条件によってPlaywrightを動かすのにちょっとハマったので、Lambda用のコンテナイメージでPlaywrightを動かす際の注意点などを紹介します。
これはpublic.ecr.aws/lambda/python:3.8
を使用したので難しくありませんでした。
あとはlambdaのライブラリを使用してeventとcontextを受け取る関数を作ればいいです。 Playwrightを使うときはこの関数内に処理を書く感じになります。
from playwright.sync_api import sync_playwright
def lambda_handler(event, context):
# なにかのplaywrightを使った処理
# ...
return {
"statusCode": 200,
"body": "",
}
仕様で、Lambdaで実行するプログラムを置くディレクトリ(公式ベースイメージのデフォルトは/var/task
)では書き込み操作が禁止されています。
書き込みしたい処理がある場合には、/tmp
ディレクトリを使います。
このディレクトリでは、512MBまでのファイルの書き込みができます。
自分はこれを知らなくてだいぶハマりました! Playwright の自動ブラウザ操作にはchromiumを使ったのですが、これを動かすためにはchromiumが存在するディレクトリが書き込み操作可能なディレクトリである必要があります。
chromiumのインストールにはDockerfile内で
bash
python3.8 -m playwright install chromium
のようにインストールしているのですが、デフォルトだと読み込み専用のディレクトリにインストールされてしまい起動しなくなるので、環境変数でインストール場所を変更し、
ENV PLAYWRIGHT_BROWSERS_PATH=/var/task/bin
Lambda関数の実行時にchromiumをインストールしたディレクトリを/tmp/bin
にコピーする処理をアプリケーション側のコードに書いて解決しました。
PLAYWRIGHT_BROWSERS_PATH
環境変数に指定したディレクトリをPlaywrightはブラウザが存在するディレクトリとして使用します。
os.environ['PLAYWRIGHT_BROWSERS_PATH'] = '/tmp/bin'
def move_bin(src_dir: str = "/var/task/bin", dest_dir: str = "/tmp/bin"):
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
copy_tree(src_dir, dest_dir)
Lambdaのベースイメージでは、デフォルトではPlaywrightを動かすための依存パッケージがインストールされていません。 なので、入れてあげる必要があります。
具体的には、Dockerfile内で以下のようにインストールしました。
RUN yum -y update && yum -y install libXScrnSaver gtk2 gtk3 alsa-lib.x86_64
もう少し最小構成があるかもしれませんが、これらのパッケージをインストールすれば動きます。
デフォルトの設定でchromiumをplaywrightから呼び出すとまだ動かないので、pythonコード内でいくつかオプションを渡す必要があります。 この際に参考にしたのは以下のnode.js用のライブラリです。 https://github.com/JupiterOne/playwright-aws-lambda/blob/master/src/chromium.ts
playwright-pythonでは、こうなります。
browser = playwright.chromium.launch(
headless=True, downloads_path="/tmp",
args=[
'--autoplay-policy=user-gesture-required',
'--disable-background-networking',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-breakpad',
'--disable-client-side-phishing-detection',
'--disable-component-update',
'--disable-default-apps',
'--disable-dev-shm-usage',
'--disable-domain-reliability',
'--disable-extensions',
'--disable-features=AudioServiceOutOfProcess',
'--disable-hang-monitor',
'--disable-ipc-flooding-protection',
'--disable-notifications',
'--disable-offer-store-unmasked-wallet-cards',
'--disable-popup-blocking',
'--disable-print-preview',
'--disable-prompt-on-repost',
'--disable-renderer-backgrounding',
'--disable-setuid-sandbox',
'--disable-speech-api',
'--disable-sync',
'--disk-cache-size=33554432',
'--hide-scrollbars',
'--ignore-gpu-blacklist',
'--metrics-recording-only',
'--mute-audio',
'--no-default-browser-check',
'--no-first-run',
'--no-pings',
'--no-sandbox',
'--no-zygote',
'--password-store=basic',
'--use-gl=swiftshader',
'--use-mock-keychain',
'--single-process'])
上記の注意点を考慮して書いたDockerfileは以下のようになりました。
FROM public.ecr.aws/lambda/python:3.8
ENV PLAYWRIGHT_BROWSERS_PATH=/var/task/bin
RUN yum -y update && yum -y install libXScrnSaver gtk2 gtk3 alsa-lib.x86_64
RUN mkdir /var/task/bin
COPY app.py requirements.txt ./
RUN python3.8 -m pip install --upgrade pip && python3.8 -m pip install -r requirements.txt && \
python3.8 -m playwright install chromium
# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]
これで、アプリケーション側で先述したPLAYWRIGHT_BROWSERS_PATH
の設定とそのディレクトリの /tmp
以下へのコピー、chromiumのオプション設定を行えばPlaywrightが動くようになります。
Lambdaコンテナイメージを使用してPlaywrightを動かすために必要なことを紹介しました。 Lambda with Containerを使ってスクレイピングや自動テストをしたい人の参考になれば幸いです。
ちなみに自分はほぼ毎日使う珈琲豆の注文をこれで自動化しています☕ Lambdaは定期実行もできて便利ですね!