AWS Lambdaを介してSeleniumを実行するAPIを作成してみます。(Windows10)
■PC環境
>Windows 10
>sam –version
SAM CLI, version 1.52.0
>npm –version
8.3.1
>node –version
v16.14.0
>nodeserverless –version
Framework Core: 3.19.0
Plugin: 6.2.2
SDK: 4.3.2
>aws –version
aws-cli/2.5.6 Python/3.9.11 Windows/10 exe/AMD64 prompt/off
>Python バージョン
Python 3.6.8
■Selenium Lambdaレイヤーを作成する
AWSLambdaを介してSeleniumを実行するAPIの作成を行いますが、その前にSelenium Lambdaレイヤーを作成します。作成のためにコマンドプロンプトを起動します。
>pip3.6 install -t selenium/python/lib/python3.6/site-packages selenium==3.8.0
起動後、上記のコマンドを入力し、Enterキーを押します。pipを経由してseleniumバージョン3.8.0をインストールします。「-t」オプションで、インストールされるディレクトリを「selenium/python/lib/python3.6/site-packages」に指定します。
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip. Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue. To avoid this problem you can invoke Python with '-m pip' instead of running pip directly. Collecting selenium==3.8.0 Using cached selenium-3.8.0-py2.py3-none-any.whl (941 kB) Installing collected packages: selenium Successfully installed selenium-3.8.0 WARNING: Target directory C:\Users\user_\selenium\python\lib\python3.6\site-packages\selenium already exists. Specify --upgrade to force replacement. WARNING: You are using pip version 21.1.2; however, version 21.3.1 is available. You should consider upgrading via the 'c:\program files\python36\python.exe -m pip install --upgrade pip' command.
Enterキーを押すと、インストールが開始されます。「Successfully installed」が表示されれば、正常にインストールが完了したことになります。今回はWARNING(警告)が表示されていますが、エラーではないので一旦、無視します。
作業ディレクトリ(カレントディレクトリ)内に「selenium」というディレクトリが作成されます。
コマンドプロンプトを起動します。
>cd selenium
起動後、上記のコマンドを入力し、Enterキーを押します。cdコマンドでseleniumディレクトリに移動します。
zip -r python.zip python/
移動後、上記のコマンドを入力し、Enterキーを押します。Enterキーを押すと、「’zip’ は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。」と出力される場合は、zip.exeのダウンロード(http://gnuwin32.sourceforge.net/packages/zip.htm)を行う必要がある。Binariesのzipファイルをダウンロードし任意のフォルダに解凍。解凍後、「システム環境変数の編集」から環境変数の編集を行います。zipコマンドを用いてファイルを圧縮しpython.zipというzipファイルにします。
Enterキーを押すと、「selenium」に「python.zip」というファイルが生成されます。
生成後「AWS マネジメントコンソール」にログインし、「Lambda」サービスから左メニューの「レイヤー」をクリックします。クリック後、「レイヤーの作成」ボタンをクリックします。
クリックすると「レイヤー設定」が表示されますので、今回は「名前」を「selenium」にし、「説明 – オプション」を「Selenium layer」と入力します。入力後「.zip ファイルをアップロード」に選択し、「アップロード」ボタンをクリックします。
クリックすると、「開く」ウインドウが表示されますので、先程圧縮したzipファイル(python.zip)を選択し、「開く」ボタンをクリックします。
クリックすると、「アップロード」ボタンの右側に選択したzipファイルが表示されます。この状態で次の設定に移ります。「互換性のあるアーキテクチャ – オプション」とありますが、今回これは使用しませんので、チェックはなしで、「互換性のあるランタイム – オプション」で「ランタイム」と表示された入力欄をクリックします。
クリックするとメニューが表示されますので「Python 3.6」を選択します。
選択後、「ライセンス – オプション」は使用しませんので、未入力で「作成」ボタンをクリックします。
クリックすると、「レイヤー ***** のバージョン * が正常に作成されました。」と表示されますので、これが表示されればレイヤーの作成は完了となります。
■Chromedriver Lambdaレイヤーを作成する
今後は、Chromedriver Lambdaレイヤーを作成します。作成のために、Chromeドライバーをダウンロードしますので、コマンドプロンプト上に戻ります。
>mkdir -p chromedriver
戻った後に、上記のコマンドを入力し、Enterキーを押します。「selenium」内に「chromedriver」というディレクトリを作成します。
>cd chromedriver
作成後、上記のコマンドを入力し、Enterキーを押します。cdコマンドでchromedriverディレクトリに移動します。
>curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip
作成後、上記のコマンドを入力し、Enterキーを押します。curlコマンドでchromedriverをダウンロードし、それをchromedriver.zipにします。
Enterキーを押すと、「%」が「100」となり、ダウンロードが完了します。
完了後、「chromedriver」内に「chromedriver.zip」が生成されました。
>unzip chromedriver.zip
生成後、コマンドプロンプトで上記のコマンドを入力し、Enterキーを押します。unzipコマンドで、zip形式で圧縮されたアーカイブを展開します。なお「’unzip.exe’は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」と出力される場合は、unzip.exeをダウンロード(http://gnuwin32.sourceforge.net/packages/unzip.htm)し、ファイルを解凍。解凍後、「システム環境変数の編集」から環境変数の編集を行う必要があります。
Archive: chromedriver.zip inflating: chromedriver
Enterキーを押すと、上記のように出力され、展開が完了します。展開後、chromedriver.zipは削除します。
>curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-41/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip
これでChromeドライバーのダウンロードは完了ですが、次にChromeバイナリをダウンロードする必要がありますので、コマンドプロンプトで上記のコマンドを入力し、Enterキーを押します。curlコマンドでChromeバイナリをダウンロードし、それをheadless-chromium.zipにします。
Enterキーを押すと、「%」が「100」となり、ダウンロードが完了します。
完了後、「chromedriver」内に「headless-chromium.zip」が生成されました。
>unzip headless-chromium.zip
生成後、コマンドプロンプトで上記のコマンドを入力し、Enterキーを押します。unzipコマンドで、zip形式で圧縮されたアーカイブを展開します。
Archive: headless-chromium.zip inflating: headless-chromium
Enterキーを押すと、上記のように出力され、展開が完了します。展開後、headless-chromium.zipは削除します。
>zip -r chromedriver.zip chromedriver headless-chromium
削除後、上記のコマンドを入力し、Enterキーを押します。zipコマンドを用いてchromedriverとheadless-chromiumを圧縮しchromedriver.zipというzipファイルにします。
Enterキーを押すと、「chromedriver」内に「chromedriver.zip」が生成されました。
生成後、Chromedriver Lambdaレイヤーを作成するために、「AWS マネジメントコンソール」にログインし、「Lambda」サービスから左メニューの「レイヤー」をクリックします。クリック後、「レイヤーの作成」ボタンをクリックします。
クリックすると、「レイヤー設定」が表示されますので、今回は「名前」を「chromedriver」とし、「説明 – オプション」を「chrome driver and binary layer」と入力します。入力後「.zip ファイルをアップロード」が選択された状態となっていますが、今回アップロードするchromedriver.zipが10 MBより大きいファイルとなるので、このような場合は、アップロードが遅くなる可能性があるので、「Amazon S3 からファイルをアップロードする」を選択します。
選択後、今回「Lambda」サービスを利用していますが、このサービスがどこの場所であるかを確認します。今回は「米国東部(バージニア北部)「us-east-1」」となっています。
確認後、「S3」サービスへ移動し、今回は「バケット」から「バケットを作成」ボタンをクリックし、新しいバケットを作成します。作成する際に、「AWS リージョン」を、「Lambda」サービスの「米国東部(バージニア北部)「us-east-1」」と同じに設定します。この設定を行わないと、ファイルがアップロードできません。「Error occurred while GetObject. S3 Error Code: PermanentRedirect. S3 Error Message: The bucket is in this region: us-west-2. Please use this region to retry the request」といったエラーが発生します。
S3バケットを作成後、「オブジェクト」から「アップロード」ボタンをクリックします。
クリックすると、「アップロード」が表示されますので、点線部分にファイルをドラッグアンドドロップするか、「ファイルを追加」ボタンで、「chromedriver」内に「chromedriver.zip」を追加します。
今回は「ファイルを追加」ボタンで、「chromedriver」内に「chromedriver.zip」を追加し、「アップロード」ボタンをクリックします。
クリックすると、アップロードが開始されます。
開始後、しばらくすると、アップロードが完了します。完了後、アップロード画面の右側の「閉じる」ボタンをクリックして、画面を閉じます。
閉じると、「オブジェクト」にアップロードしたファイルが追加されますので、このファイルの名前をクリックします。
クリックすると、「オブジェクトの概要」が表示されますので、「オブジェクト URL」をコピーします。
コピー後、「Lambda」の「レイヤー」の「レイヤー設定」に戻り、「Amazon S3 からファイルをアップロードする」を選択し、「Amazon S3 のリンク URL」の入力欄に、URLを貼り付けます。貼り付けた後に、「互換性のあるアーキテクチャ – オプション」は選択せずに、「互換性のあるランタイム – オプション」で入力欄の「ランタイム」をクリックし、「Python 3.6」を選択します。
選択後「ライセンス – オプション」は未入力のまま、「作成」ボタンをクリックします。
クリックすると、「レイヤー ***** のバージョン * が正常に作成されました。」と表示されます。これでChromedriver Lambdaレイヤーの完成となります。
■Lambda関数を作成する
完了後、Lambda関数を作成しますが、その前に「selenium」内に「lambda」ディレクトリを作成します。
作成後、「lambda」ディレクトリに「handler.py」というファイルを作成します。これはLambda関数がかかれたものになります。このファイルをコードエディタで開き、Lambda関数を作成します。今回、コードはこちらのものを参考にさせていただきました(https://dev.to/awscommunity-asean/creating-an-api-that-runs-selenium-via-aws-lambda-3ck3)。
■コード
from selenium import webdriver from selenium.webdriver.chrome.options import Options def main(event, context): 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('/opt/chromedriver',chrome_options=options) driver.get('https://laboratory.kazuuu.net/') body = f"Headless Chrome Initialized, Page title: {driver.title}" driver.close(); driver.quit(); response = { "statusCode": 200, "body":body } return response
今回はdriver.get()を用い、括弧内に引数,パラメータとして当サイト(https://laboratory.kazuuu.net/)のURLを渡します。これでURLを開き、driver.titleでWebサイトのタイトルを取得。取得後、body変数に格納し、さらにresponse変数にbody変数を格納。最後にreturnでresponse変数の情報を返すというものです。
コードを記述後、保存します。
保存後、「lambda」ディレクトリに「serverless.yaml」というファイルを作成します。このファイルにサーバーレスなアプリケーションを簡単に開発、デプロイするためのツールである「Serverless Framework」の設定を記述します。記述のために、コードエディタで開きます。
今回、コードはこちらのものを参考にさせていただきました(https://dev.to/awscommunity-asean/creating-an-api-that-runs-selenium-via-aws-lambda-3ck3)。
■コード(修正前)
service: selenium-lambda provider: name: aws runtime: python3.6 region: ap-southeast-2 timeout: 900 functions: main: memorySize: 1000 handler: handler.main events: - http: path: test method: get layers: - arn:aws:lambda:ap-southeast-2:{}:layer:chromedriver:2 - arn:aws:lambda:ap-southeast-2:{}:layer:selenium:2 resources: Resources: ApiGatewayRestApi: Properties: BinaryMediaTypes: - "*/*"
このコードを記述し、保存後、コマンドプロンプトを起動し、「lambda」ディレクトリ内に移動し、「sls deploy」コマンドを用いてデプロイを行っても、まず「Error:
Deployment bucket has been removed manually. Please recreate it or remove your service and attempt to deploy it again」というエラーが発生するので、コードを変更する。
■コード(修正後その1)
service: web-selenium-lambda-test provider: name: aws runtime: python3.6 region: ap-southeast-2 timeout: 900 functions: main: memorySize: 1000 handler: handler.main events: - http: path: test method: get layers: - arn:aws:lambda:ap-southeast-2:{}:layer:chromedriver:2 - arn:aws:lambda:ap-southeast-2:{}:layer:selenium:2 resources: Resources: ApiGatewayRestApi: Properties: BinaryMediaTypes: - "*/*"
「service: selenium-lambda」を「service: web-selenium-lambda-test」に変更し、保存する。保存後、デプロイする。デプロイするが、下記のエラーが発生する。
Error: CREATE_FAILED: MainLambdaFunction (AWS::Lambda::Function) Resource handler returned message: "1 validation error detected: Value '[arn:aws:lambda:ap-southeast-2:{}:layer:chromedriver:2, arn:aws:lambda:ap-southeast-2:{}:layer:selenium:2]' at 'layers' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 140, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: (arn:[a-zA-Z0-9-]+:lambda:[a-zA-Z0-9-]+:\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+), Member must not be null] (Service: Lambda, Status Code: 400, Request ID: a54e6e64-7feb-4694-9417-a5b8b346872f)" (RequestToken: 048675f6-cb82-1fea-047e-b3464ad19e14, HandlerErrorCode: InvalidRequest)
このエラーが発生したので、問題の箇所を修正する。
■コード(修正後その2)
service: web-selenium-lambda-test provider: name: aws runtime: python3.6 region: ap-southeast-2 timeout: 900 functions: main: memorySize: 1000 handler: handler.main events: - http: path: test method: get layers: - arn:aws:lambda:us-east-1:*******:layer:chromedriver:2 - arn:aws:lambda:us-east-1:*******:layer:selenium:2 resources: Resources: ApiGatewayRestApi: Properties: BinaryMediaTypes: - "*/*"
まず、providerの「region: ap-southeast-2」を「region: us-east-1 (米国東部(バージニア北部))」に変更します。今回、「Lambda」サービスはus-east-1 (米国東部(バージニア北部))を利用している。
※これは「chromedriver」のレイヤーで、参考として表示しています。
さらに「functions:」の「layers:」を下記のコードに変更する。このコードは、今回作成した「Lambda」の「レイヤー」の「selenium」、「chromedriver」をクリックすると、「バージョン」で「バージョン ARN」が表示されているので、こちらの情報をコピーして、コピーしたもので、上記にも記載していますが、下記のように変更します。
layers: - arn:aws:lambda:us-east-1:****:layer:chromedriver:2 - arn:aws:lambda:us-east-1:****:layer:selenium:2
変更後、保存します。保存後、、コマンドプロンプトを起動し、「lambda」ディレクトリ内に移動し、「sls deploy」コマンドを用いてデプロイを行います。
Warning: Invalid configuration encountered at 'resources.Resources.ApiGatewayRestApi': must have required property 'Type' Learn more about configuration validation here: http://slss.io/configuration-validation Deploying web-selenium-lambda-test to stage dev (us-east-1) Warning: Function main has timeout of 900 seconds, however, it's attached to API Gateway so it's automatically limited to 30 seconds. ✔ Service deployed to stack web-selenium-lambda-test-dev (138s) endpoint: GET - https://****.execute-api.us-east-1.amazonaws.com/dev/test functions: main: web-selenium-lambda-test-dev-main (551 B) 1 deprecation found: run 'serverless doctor' for more details Toggle on monitoring with the Serverless Dashboard: run "serverless"
デプロイを行うと、デプロイが完了し、上記のメッセージが出力されます。出力内容を確認すると「Warning(警告)」が出力されていますが、「エラー」ではないので、今回は一旦無視します。
「endpoint:」で「GET – https://****.execute-api.us-east-1.amazonaws.com/dev/test」」と出力されていますので、このURLをコピーします。コピー後、Webブラウザを起動し、アドレスバーに貼り付けて、アクセスします。
アクセスすると、AWSLambdaを介してSeleniumを実行し、指定したWebサイトのページタイトルを出力させることができました。
出力後、「AWS マネジメントコンソール」から「CloudFormation」を確認すると新しいスタックが追加されていることと、「S3」で新しいS3バケットが作成されていることが確認できました。
コメント