25 min readPython
【Pythonコード付】LambdaとSeleniumでスクリーンショット自動化
LambdaとSeleniumを活用して何か自動化したい!しかしサンプルコードがなくてわからない。。そんな方々のため今回は、Pythonコードを利用してスクリーンショット撮影を自動化いたします。最後までご一読ください。
執筆者 - おすすめの記事2選
用意するもの
- AWSアカウントの作成が済んでいる。
使用する各種バージョン情報
名称 | 変更点 |
---|---|
Lambda | Python3.7 |
Selenium | 3.141.0 |
Chromedriver | 81.0.4044.69 |
アーキテクチャ
今回は、AWSサービスの1つLambdaを活用してSelenium操作を行います。
Lambdaを操作する環境としてPython3.7を採用し、Lambda内で扱えるファイル量に限りがあるので重いファイルに関しては、Layerを活用してファイル構成を行いました。
Layerを適用することで、
- 重いファイルにも対応できる。(最大250 MBまで)
- 別のLambda関数にもLayer化したファイルを充てることが可能
のメリットがあります。今回は、Selenium, Chromedriver, .fontsに関してLayer扱いすることにしました。
.fontsフォルダは、スクリーンショットした際に文字化けを防ぐために利用します。
スクリーンショットを撮影した結果は、S3で管理します。
実装手順
実装順序としては、
で行います。内容量が多いぶん大変ですが、丁寧に解説致しますので、最後までご確認ください。
zipファイルの作成
zipファイルの作成の章では、LambdaやLayerで利用するファイルの準備を行います。早速ですが手を動かしてみましょう。
- こちらのページに訪問ください。
- 緑の「Code」と書かれているボタンをクリックして、 「Download ZIP」をクリックください。
- ダウンロードしたZipファイルをドラック&ドロップを使って、デスクトップへファイル移動して下さい。
- Zipファイルを展開するために、デスクトップに置いた先ほどのファイルをダブルクリックして下さい。
- screenshot-masterフォルダ内に含まれる、selenium, headlessフォルダ, .fonts.zipファイルをデスクトップへ配置ください。
- headless/python/binフォルダ内に含まれる、chromedriver.zip, headless-chromium.zipをダブルクリックして展開ください。
- chromedriver.zip, headless-chromium.zipをゴミ箱に捨てます。
- ターミナルを起動する。
$ cd desktop/selenium
: seleniumフォルダへ移動する。$ zip -r selenium.zip ./*
: Layerへseleniumを配置するため、selenium.zipファイル名としてzip化する。- seleniumフォルダに生成されたselenium.zipファイルを、デスクトップへ配置する。
$ cd ..
: 一つ上の親ディレクトリへ戻る。$ zip -r headless.zip ./headless
: LayerへChromedriverを配置するため、headless.zipファイル名としてzip化する。$ cd screenshot-master
: screenshot-masterフォルダへ移動する。$ zip -r deploy.zip lambda_function.py automate.py
: Lambda関数へアップロードするため、deploy.zipファイル名としてzip化する。- screenshot-masterフォルダ内に含まれるdeploy.zipファイルをデスクトップへ配置する。
Lambda関数を作成 & デプロイ
Lambda関数を作成 & デプロイの章では、先ほど作成したdeploy.zipファイルをLambda関数へ作成 & デプロイする工程になります。
まず、AWSへログインします。
上の検索窓口に「Lambda」と入力してLambdaサービスを選択する。
「関数」を選択する。
「関数の作成」を選択する。
関数の詳細を入力する。
- 関数の作成(どのようにLambda関数を作成するのか?予め構成要素を作っておいて実装したりすることができる。) : 一から作成
- 関数名 : screenshot
- ランタイム(どのプログラミング言語を利用して、Lambdaを動かすか?) : Python 3.7
- 実行ロール(作成するLambdaを実行する権限の設定) : 基本的な Lambda アクセス権限で新しいロールを作成
- その他 : 空白
「関数の作成」を選択する。
続いてアップロード元 → .zipファイルを選択する。
アップロードを選択して、デスクトップへ配置したdeploy.zipファイルを保存する。
Layerのデプロイと紐付け
Layerのデプロイと紐付けの章では、先ほど作成したselenium.zip, headless.zipファイル, .fonts.zipファイルをLayerにデプロイする工程になります。
上の検索窓口に「Lambda」と入力してLambdaサービスを選択する。
「レイヤー」を選択する。
「レイヤーの作成」を選択する。
headless.zipをデプロイするため、詳細入力する。
- 名前 : headless
- 説明 - オプション : headlessに関するファイル群
- .zipファイルをアップロード : デスクトップへ配置したheadless.zipファイルを選択。
- 互換性のあるランタイム - オプション : Python3.7
最後に「作成」を選択する。※少し時間がかかります。
同様の手順でselenium.zip, .fonts.zipに関してもLayerを作成します。
selenium.zipをデプロイするための詳細設定。
- 名前 : selenium
- 説明 - オプション : seleniumに関するファイル群
- .zipファイルをアップロード : デスクトップへ配置したselenium.zipファイルを選択。
- 互換性のあるランタイム - オプション : Python3.7
.fonts.zipをデプロイするための詳細設定。
※Macの場合、Finderを開いてcommand + shift + .
を実行すると、.から始まる隠しファイルを探し出せます。(参考)
- 名前 : fonts
- 説明 - オプション : fontsに関するファイル群
- .zipファイルをアップロード : デスクトップへ配置した.fonts.zipファイルを選択。
- 互換性のあるランタイム - オプション : Python3.7
次にLambda関数でLayerを活用するための紐付け作業を行います。
上の検索窓口に「Lambda」と入力してLambdaサービスを選択する。
「関数」を選択して「screenshot」を選ぶ。
「レイヤーの追加」を選択する。
「カスタムレイヤー」をクリックして、カスタムレイヤーを「headless」, バージョン「1」を選択して追加。
同様に「selenium」「fonts」に関してもカスタムレイヤーを利用して、紐付け作業を行う。
S3内にバケットの作成
S3内にバケットの作成の章では、Seleniumを活用してスクリーンショットされた画像を保管できる場所を作ります。
上の検索窓口に「S3」と入力してS3サービスを選択する。
「バケット」をクリックして、「バケットを作成」を選択する。
バケットの詳細設定を行う。
- バケット名 : imglist
- AWS リージョン(バケットをどこの地域に設置するのか?) : アジアパシフィック(東京) ap-northeast-1
- パブリックアクセスをすべてブロックにチェックする。(チェックを加えることでアクセス制限を行う。)
- バケットのバージョニング : 無効にする
- デフォルトの暗号化 : 無効にする
最後に「バケットを作成」を選択。
Lambdaの詳細設定
Lambdaの詳細設定の章では、Seleniumを動かすために必要な詳細設定を行います。
上の検索窓口に「Lambda」と入力してLambdaサービスを選択する。
「関数」を選択して「screenshot」を選ぶ。
設定 → 一般設定をクリックして編集を選択
Lambdaに関する詳細設定を行います。
- メモリ(MB) : 10000 (Lambdaを実行するために必要なメモリの大きさ。Chromedriverを動かすために、大きなメモリを割り当てる必要があるため、10000とする。)
- タイムアウト : 5分0秒 (Lambdaの実行を持続する時間。仮想的にブラウザを立ち上げたりする十分な時間が必要なため、5分0秒とする。)
- 実行ロール : そのまま
最後に「保存」します。
IAMの設定
IAMの設定の章では、LambdaからS3へスクリーンショットを転送するために必要な権限を設定します。
上の検索窓口に「IAM」と入力してIAMサービスを選択する。
「ロール」をクリックして「screenshot-role-xxx」を選択
「ポリシーをアタッチします」をクリックします。続いて「ポリシーのフィルタ」箇所へ「S3」と入力して「AmazonS3FullAccess」を選択。
最後に「ポリシーのアタッチ」を選びます。
テストしてみる
長い道のりでしたが、以上で準備が完了です。テストを通じてスクリーンショットが撮れているのか、確認しましょう。
上の検索窓口に「Lambda」と入力してLambdaサービスを選択する。
「関数」を選択して「screenshot」を選ぶ。
「テスト」タブを選んで、「テスト」ボタンをクリック。
実行結果が表示されますので、問題なくテストが実行されるかご確認ください。
スクリーンショットを確認する
先ほどはテストを実行する方法をお伝えしました。テストが成功していれば、S3内にスクリーンショットが生成されています。確認しましょう。
上の検索窓口に「S3」と入力してS3サービスを選択する。
バケットをクリックしてimglistのバケットを選択。
screenshot.pngをクリックし「オブジェクトアクション」から「ダウンロード」を選択して、ダウンロードされたスクリーンショットを確認します。
このような画像がダウンロードされれば成功です。お疲れ様でした。
よくわかるコード解説
実装はできたけれども、コードについて理解できていないと思います。まずは、lambda_function.pyファイルに関して説明します。
os.environ['HOME'] = '/opt/' : HOMEの環境変数の値を'/opt/'へ変更する。これはスクリーンショットが文字化けを起こさないように設定します。Layer関数でデプロイされたファイル(.fonts.zip)は/opt/以下に配置されます。/opt/.fontsにフォント情報を設置し、HOMEの環境変数の値を'/opt/'へ変更することで、Lambda関数実行前に.fonts以下を自動読み込みし、文字化け防止を行います。
1# 環境変数HOMEを変更する。
2# もともとLambda自体、Linuxベースで動いている。 : https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html
3# 故に環境変数の扱いもLinuxを元にしていて、HOMEの環境変数は、「あなたのホームディレクトリのパス」を表す。
4# ホームディレクトリとは? : https://wa3.i-3-i.info/word11160.html
5# HOMEを/opt/に設定することでlambda_handler関数が実行される前に、/opt/以下のファイルを自動読みこみする。
6# /opt/以下に、.fontsを設置することで、ファイルの自動読み込みを行い、文字化け現象を防ぐ。
7# LambdaのLayerでアップロードしたコードは自動的に/opt/以下に配置される。
8os.environ['HOME'] = '/opt/'
次にautomate.pyです。
options.binary_location = "/opt/headless/python/bin/headless-chromium" : Layerに設置したファイル(selenium.zip, headless.zip)は、/opt/配下へ自動配置されます。パス調整を行う際は、/opt/から始めるとうまくいきます。
1class Selenium:
2 def __init__(self):
3 # LambdaのLayerを活用している。
4 # Layerとは、Lambda内に含まれるサービス名で、重いファイルや共通で利用するファイルを配置する場所。
5 # Lambdaとの紐付けを行うことで、紐づいたLambda関数ならば再利用可能。
6 # Lambda関数実行時には、/opt/以下にファイルが配置される。
7 options.binary_location = "/opt/headless/python/bin/headless-chromium"
今日のまとめ
- LambdaとSeleniumを活用して自動化できる。
- 重いファイルや再利用可能なコードは、Layer配下で管理する。
- 権限管理は、IAMにて行う。
こんなことにもチャレンジしてみよう
参考文献
- AWSとは?
- Lambdaとは?
- Seleniumとは?
- Chromedriverとは?
- Lambdaで扱えるファイル量について
- Lambdaで使えるLayerとは?
- S3とは?
- S3でよく聞くバケットについて
- IAMとは?
- 親ディレクトリとは?
- デプロイとは?
- タイムアウトとは?
- メモリとは?
- headless chromeをLambda Layerで動かした話
- Lambdaの新機能Layerの使い方
- AWS Lambda + @serverless-chrome/lambda + Puppeteer 環境で任意のフォントを使えるようにする