この記事では
AWS Lambdaから、selenium×chromeでブラウザ操作したい時に、
Layer の作り方でハマったので投稿します。
やりたいこと
AWS Lambdaでselenium×chromeを動かしたい。
環境
windows 10 Pro
python 3.7
chromdriver 2.37
headless-chromium 64.0.3282.167
記載しないこと
-AWS lambda の関数作成、呼出方法
-selenium webdriverによるブラウザ操作ができるpythonプログラムの作り方。
つまづいたところ
1.AWS Lambda Layersを作る単位
2.AWS Lambda Layersへの搭載方法と呼び出し方
##1.AWS Lambda Layersを作る単位
まず、AWS Lambda Layers とはlamda から共通的に使える共通関数のようなものです。
下記のようにLambda本体から参照される形で呼び出すことができます。
機能の1部を切り出すことで、lambda本体の軽くすることができます。
軽くすることで、例えば下記のような、モジュール一式の容量が大きすぎるためにコードが表示できないデメリットを回避することができます。
今回は、python からselenium でchromeDriverで実装したかったので、
以下2点のLayer を作ります。
1.seleniumのライブラリを格納するLayer
2.chromeDriverを格納するLayer
以下に作り方を記載します。
###1.seleniumのライブラリを格納するLayer
####1.搭載するライブラリ一式の準備
任意のフォルダで下記コマンドを実行します。
既にpip install selenium をしていると思いますが、
搭載するライブラリを準備する作業なので、実行モジュールとは別の場所で行います。
pip install -t ./python/lib/python3.7/site-packages selenium
####2.以下の構成ができあがります。(windows環境で実施しています。)
####3.zip 圧縮
python フォルダからzip圧縮します。
####4.AWS Lambda Layers の作成
lambdaのコンソール画面から、Layers を新規作成します。
作成時に、3のzipファイルを指定して作成します。
####5.Lambda関数へのLayer追加
Lambda関数から4で作ったLayers を参照設定します。
Layer の設定画面からカスタムレイヤーを選択すると、選択肢に表示されるようになります。
####6.import で呼び出し
lambdaからimport で呼び出します。
from selenium import webdriver
もし、上記構成を間違った場合、下記エラーとなります。
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': No module named 'selenium'
###2.chromeDriverを格納するLayer
####1.driverの準備
公式配布されているdriver (2点)を準備します。
chromdriver 配布元:https://chromedriver.storage.googleapis.com/index.html?path=2.37/
headless-chromium 配布元:https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-37/stable-headless-chromium-amazonlinux-2017-03.zip
####2.zip 圧縮
上記2点を同じフォルダに配置し、linux環境でzip 圧縮します。
もし、windows環境でzip圧縮した場合、lamdaを実行しても下記のエラーとなります。
linux 環境でも、各ファイルのパーミッションが777でないと、下記エラーとなります。
[ERROR] WebDriverException: Message: 'chromedriver' executable may have wrong permissions. Please see https://sites.google.com/a/chromium.org/chromedriver/home
windowsPCの方で、linux 環境でzip圧縮するには、下記方法があります。どちらでもいけました。
1.WSL環境でのzip ※パーミッション777にしておく
2.Docker desktopで適当な環境を作る
(たまたま使っていた、こちらのphp環境を利用しました。 https://hub.docker.com/_/php )
####3.Lambda関数へのLayer追加
Lambda関数から4で作ったLayers を参照設定します。
※先ほどと同じ手順となります。
####4.lambdaから呼出
lambdaから 以下パスを指定して呼びます。
AWS Lambda layersの仕様で、/opt に配置されるため、下記のように指定します。
driver = webdriver.Chrome(executable_path ="/opt/chromedriver", chrome_options=options)
もし、optが無いなどパスを誤った場合、エラーとなります。
[ERROR] WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home
###もう一つ注意点
lamda もseleniumも処理が遅いので、lamdaのtimeout値を長めに設定してやります。
デフォルトは、3秒ですので、ほぼtimeoutし、下記のエラーとなります。
Task timed out after XX.XX seconds
実装
lamdaのコードは、最終的に下記となります。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def lambda_handler(event, context):
LINE_NOTIFY_URL = "https://notify-api.line.me/api/notify"
options = Options()
options.binary_location = '/opt/headless-chromium'
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--single-process')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(executable_path ='/opt/chromedriver', chrome_options=options)
driver.get("https://xxxxxxxxxxx")
まとめ
他の記事を見ていると、serverless.ymlやcloudFormationを使ったものが多かったのですが、
私はそのあたりの知識が弱かったため、上記方法をとりました。
初めてサーバレスでseleniumを組み込む方の参考になれば幸いです。