この記事は Serverless2 Advent Calendar 2018 - Qiita の20日目です。
- 今年開催された re:Invent2018でAWS Lambda Layersが発表されました。
- このアップデートによってC拡張のライブラリや容量の大きいライブラリの利用がより便利になりました。
- その中でも特に自分が最初に「使ってみたい!」と思ったHeadless Chrome on Seleniumの使い方を解説します。
- 自分が普段使っているServerless Frameworkは既にAWS Lambda Layersに対応しており、これを使ったやり方になります。
最終的なフォルダ構成&Versions
ここから作業していきますが、先に最終的なフォルダ構成を書いておきます。
tree -L 2 ├── lambda # Layerを使うアプリケーションのディレクトリ │ ├── handler.py │ └── serverless.yml └── selenium-layer # Layerのディレクトリ ├── chromedriver │ ├── chromedriver │ └── headless-chromium ├── selenium │ └── python └── serverless.yml
また利用するスタックのVersionはこちらです。
Layersの作成
まずLayerを作成します。 最初にLayer作成用のディレクトリを作成して、そこで作業しましょう。
cd ${project_dir} mkdir selenium-layer cd selenium-layer
必要なファイル群をローカルに準備
それでは、必要なファイル群を準備していきましょう
Selenium
Seleniumはpipでインストールします。パスの python/
以下はLayerで使うための決まったパスになります。
pip install -t selenium/python/lib/python3.6/site-packages selenium
Seleniumはそうではないですが、numpyなどのC拡張ライブラリをインストールする場合はDocker Imageのlambci/docker-lambdaを使う必要があります。下のような感じになると思います。
docker run --rm -v $(pwd):/var/task -w /var/task lambci/lambda:build-python3.6 pip install -t numpy/python/lib/python3.6/site-packages numpy
Headless Chrome/Chrome Driver
次にHeadless ChromeとChrome Driverをインストールします。 まず作業場所を移動します。
cd ${project_dir}/selenium-layer mkdir headless-chrome cd headless-chrome
Headless Chrome
Headless ChromeはAWS Lambda用に切り出されたserverless-chromeを使います。
curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-41/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip unzip headless-chromium.zip rm headless-chromium.zip
これでOKです。
Chrome Driver
Chrome Driverは公式のDriverを使います。
Downloads - ChromeDriver - WebDriver for Chrome
curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip unzip chromedriver.zip rm chromedriver.zip
これでOKです。
AWS LambdaにLayerを作成
必要なファイルが準備できたので、AWS Lambdaにデプロイしていきたいと思います。 serverless.ymlを下記のように作成します。
cd ${project_dir}/selenium-layer vim serverless.yml
service: selenium-layer provider: name: aws runtime: python3.6 stage: dev region: ap-northeast-1 layers: selenium: path: selenium description: selenium layer CompatibleRuntimes: - python3.6 chromedriver: path: chromedriver description: chrome driver layer CompatibleRuntimes: - python3.6 resources: Outputs: SeleniumLayerExport: Value: Ref: SeleniumLambdaLayer Export: Name: SeleniumLambdaLayer ChromedriverLayerExport: Value: Ref: ChromedriverLambdaLayer Export: Name: ChromedriverLambdaLayer
その後はdeployするだけです。
sls deploy
AWS Consoleを開くとLayerが出来ていることがわかります。
またresources以下で下記のように設定していることでCloudFormationのStackをExportすることができ、他のserverless frameworkのサービスからも簡単に参照できるようになります。
Ref
で参照している SeleniumLambdaLayer
は serverless frameworkが自動で作っている名前で {Layer名}LambdaLayer
という名前で作られるようです。
resources: Outputs: SeleniumLayerExport: Value: Ref: SeleniumLambdaLayer Export: Name: SeleniumLambdaLayer ChromedriverLayerExport: Value: Ref: ChromedriverLambdaLayer Export: Name: ChromedriverLambdaLayer
※参考: https://serverless.com/framework/docs/providers/aws/guide/variables#reference-cloudformation-outputs
Layerを利用するサービスの作成
Layerを作成できたので、Layerを使うサービスを作成します。
cd ${project_dir} mkdir lambda cd lambda
準備
serverless.ymlを作成します。
vim serverless.yml
service: crawler-with-selenium provider: name: aws runtime: python3.6 stage: dev region: ap-northeast-1 timeout: 900 environment: SELENIUM_LAYER_SERVICE: selenium-layer functions: hello: handler: handler.hello layers: - ${cf:${self:provider.environment.SELENIUM_LAYER_SERVICE}-${opt:stage, self:provider.stage}.SeleniumLayerExport} - ${cf:${self:provider.environment.SELENIUM_LAYER_SERVICE}-${opt:stage, self:provider.stage}.ChromedriverLayerExport}
次にhandler.pyを作成します。このBlogにアクセスしてタイトルを取ってくるだけのシンプルなスクリプトです。
vim hander.py
from selenium import webdriver from selenium.webdriver.chrome.options import Options def hello(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://blog.ikedaosushi.com/') body = f"Blog title is: {driver.title}" driver.close(); driver.quit(); response = { "statusCode": 200, "body": body } return response
デプロイ&実行
あとはデプロイして実行するだけです。 デプロイします。
sls deploy
デプロイが成功するとAWS ConsoleからLayerが正しく参照できていることが確認できます。
最後に実行します。
sls invoke -f hello # { # "statusCode": 200, # "body": "Blog title is: フリーランチ食べたい" # }
無事、実行することができました。
終わりに
- Serverless FrameworkからAWS Lambda Layersを使ってHeadless Chrome on Seleniumを動かす方法を解説しました
- 今までSeleniumを使う案件ではLambdaの利用を躊躇してしまっていたのですが、AWS Lambda Layersを使うことでガンガン使っていけそうですね
- 個人的には今年のre:inventで一番うれしいアップデートでした
- これからもServerlessを楽しんでいきましょう!
参考記事
- Running Selenium and Headless Chrome on AWS Lambda Layers
- 基本的にこの記事を参考に書いているのですが、ところどころ間違いがあり、この通りやっても動かないのでこの記事では修正しています。また設定に関しても補足しています。
- Serverless Frameworkで AWS Lambda Layers を試してみる - Taste of Tech Topics