技術(tech)

Pythonで作成したLambdaのメソッドをローカル上で動作確認する

Pythonで作成したLambdaをローカルでデバックできるように、ローカルで動かすための手順を紹介します。pythonlambdalocalというモジュールを使用します。

以下の記事の続きとなっていますので、まずは以下の記事を参考にAWSのLambda上で動作させてみるのをおすすめいたします。

Lambdaからseleniumを動かすための環境構築手順、設定を分かりやすく紹介LambdaでSeleniumを動かす手順をエラーを解決しながら詳細に紹介。必要なレイヤーの設定、メモリ割り当ての調整など、環境構築のポイントを解説。デバッグ方法も紹介。...

 

前提

筆者のローカル環境は以下の通りです。

  • pyenv: stable 2.3.31
  • python: 3.7.3
  • pip 23.2.1
  • selenium 4.1.0

 

python 3.7.3の準備で躓く場合には以下も参考にどうぞ。

python 3.7.3のインストールでエラー「error: implicit declaration of function 'sendfile' is invalid in C99」macOS Big Sur 11.7.4でPython 3.7.3のインストール時にerror: implicit declaration of function 'sendfile' is invalid in C99エラーに遭遇。問題解決のため、特定のコマンドを使用し無事にインストールできた。詳細手順は記事内に記載。...

 

 

先に本記事の最終形の共有

最終的なディレクトリ構成は以下のようになります。

~/D/g/selenium_test ❯❯❯ tree .                                                                                                                                  main ✭ ✖ ✱
.
├── app
│   └── lambda_function.py
├── chromedriver
├── headless-chromium
└── test
    └── event.json

 

今回使用するソースコード(lambda_function.py)はこちら。

#coding: UTF-8
import os
import time
import pytz
from selenium import webdriver
from selenium.webdriver.chrome.options import Options  # オプションを使うために必要
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

CHROMEDRIVER_PATH = os.environ["CHROMEDRIVER_PATH"]
HEADLESS_CHROMIUM_PATH = os.environ["HEADLESS_CHROMIUM_PATH"]

def lambda_handler(event, context):
  options = webdriver.ChromeOptions()
  options.add_argument("--disable-gpu")
  options.add_argument("--hide-scrollbars")
  options.add_argument("--ignore-certificate-errors")
  options.add_argument("--window-size=880x996")
  options.add_argument("--no-sandbox")
  options.add_argument("--homedir=/tmp")

  if "env" in event and event["env"] == "local":
    print("This is local env.")
  else:
    options.add_experimental_option("w3c", True)
    options.add_argument("--headless")
    options.add_argument("--single-process")  # if enable this option, it doesn't work in local
    options.binary_location = HEADLESS_CHROMIUM_PATH

  driver = webdriver.Chrome(
    executable_path=CHROMEDRIVER_PATH,
    options=options
  )

  driver.get("https://www.google.com/")
  driver.quit()

 

event.jsonファイルは以下の通り。実行環境がローカルであることを示します。

{
  "env": "local"
}

 

以下のコマンドを実行した際に、ローカル環境でLambdaが起動します。

python-lambda-local -t 100 -f lambda_handler app/lambda_function.py test/event.json

 

ローカルでLambdaを動かすまでの手順

ローカル環境上にもchromedriverをダウンロードしましょう。
(すでに実施済みの方は不要です)

headless-chromiumは今回使わないですが、一応ダウンロードしておきます。

curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip

curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-37/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip

unzip -o chromedriver.zip -d .
unzip -o headless-chromium.zip -d .

python-lambda-localをインストールします。

~/D/g/selenium_test ❯❯❯ pip install python-lambda-local

 

./test/event.jsonファイルを作成します。lambda_handler関数のeventに渡る引数となります。

{
  "env": "local"
}

 

次に、lambda_handler.pyを準備します。

#coding: UTF-8
import os
import time
import pytz
from selenium import webdriver
from selenium.webdriver.chrome.options import Options  # オプションを使うために必要
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

CHROMEDRIVER_PATH = os.environ["CHROMEDRIVER_PATH"]
HEADLESS_CHROMIUM_PATH = os.environ["HEADLESS_CHROMIUM_PATH"]

def lambda_handler(event, context):
  options = webdriver.ChromeOptions()
  options.add_argument("--disable-gpu")
  options.add_argument("--hide-scrollbars")
  options.add_argument("--ignore-certificate-errors")
  options.add_argument("--window-size=880x996")
  options.add_argument("--no-sandbox")
  options.add_argument("--homedir=/tmp")

  if "env" in event and event["env"] == "local":
    print("This is local env.")
  else:
    options.add_experimental_option("w3c", True)
    options.add_argument("--headless")
    options.add_argument("--single-process")  # if enable this option, it doesn't work in local
    options.binary_location = HEADLESS_CHROMIUM_PATH

  driver = webdriver.Chrome(
    executable_path=CHROMEDRIVER_PATH,
    options=options
  )

  driver.get("https://www.google.com/")
  driver.quit()

 

if文の中で、localの場合には不要なオプションを追加しないようにしています。
(これらのオプションが含まれるとローカルでseleniumが起動しないです)

あとはプログラムの中で使用する環境変数を設定しましょう。

先程ダウンロードした2つのファイルを指定します。

export HEADLESS_CHROMIUM_PATH=[ファイルの格納先パス]/headless-chromium

export CHROMEDRIVER_PATH=[ファイルの格納先パス]/chromedriver

 

ローカルからLambdaを実行します。

-tオプションでタイムアウト時間を渡しています。

~/D/g/selenium_test ❯❯❯ python-lambda-local -t 100 -f lambda_handler app/lambda_function.py test/event.json                                                         main ✭ ✖ ✱
[root - INFO - 2023-10-25 00:09:35,835] Event: {'env': 'local'}
[root - INFO - 2023-10-25 00:09:35,836] START RequestId: 9e7527bd-09e9-4c19-af65-21611df6b9b9 Version: 
This is local env.
[root - INFO - 2023-10-25 00:09:41,684] END RequestId: 9e7527bd-09e9-4c19-af65-21611df6b9b9
[root - INFO - 2023-10-25 00:09:41,687] REPORT RequestId: 9e7527bd-09e9-4c19-af65-21611df6b9b9  Duration: 5077.01 ms
[root - INFO - 2023-10-25 00:09:41,687] RESULT:
None

 

ローカルでもLambdaが動くことを確認できました。

これでわざわざAWS上でLambdaを実行しなくても手元で動作確認できるようになりますね。

残りは、GitHubリポジトリで本ソースコードを管理して、masterに変更を加えた際にLambdaにもソースコードが反映されるようになればより使いやすくなりますね。
(その話は別途記事にしましょう)

 

ここまでご覧いただき、ありがとうございました。