Headless-Chrome on AWS Lambda

以下の記事を参考にAWS Lambda上でHeadless-Chromeを動かしてみました。

注) Serverlessは事前にインストールしておく必要があります。

AWS Lambda上でのWebクローリング実行に少し近づいてきました。

ファイル構成

適当なディレクトリ以下に二つのディレクトリ(lambda、selenium-layer)を作成していきます。

mkdir crowler(任意)
cd crowler

$ tree -L 2
.
├── lambda
│   ├── handler.py
│   └── serverless.yml
├── selenium-layer
│   ├── chromedriver
│   ├── selenium
│   └── serverless.yml

selenium-layer

selenim(pythonモジュール)とchromedriver(chromedriver, headless-chrome)をLayerとして登録します。

参照した記事は、chromedriverディレクトリ以下の構成が少しわかりにくかったです。

chromedriver

$ cd selenium-layer
$ mkdir chromedriver
$ cd chromedriver

# headless-chromiumダウンロード
$ 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

# chromedriverダウンロード
$ curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip
$ unzip chromedriver.zip
$ rm chromedriver.zip

$ tree
.
├── chromedriver(実行モジュール)
└── headless-chromium(実行モジュール)

selemium

pythonモジュールを追加します。

$ cd selenium-layer
$ mkdir selenium
$ cd selenium
$ pip install -t selenium/python/lib/python3.6/site-packages selenium
$ tree -L 3
.
└── python
    └── lib
        └── python3.6

serverless.yml

chromedriverとseleniumをLayer定義します。

$ cat 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

deployします。awscliのインストールおよび設定は事前に済ませておく必要があります。

$ serverless deploy

AWSコンソールで登録内容を確認することができます。

lambda

登録したselenium-layerを使う関数をLambdaに登録します。

handler.py

Lambda登録したモジュールは/opt以下に配置されます。

$ cat handler.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://qiita.com/')
    body = f"Blog title is: {driver.title}"

    driver.close();
    driver.quit();

    response = {
        "statusCode": 200,
        "body": body
    }

    return response

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}

deploy

$ serverless deploy

実行

$ seleverless invoke -f hello
{
    "statusCode": 200,
    "body": "Blog title is: Qiita"
}

実行した時に以下のエラーが発生しましたが、しばらく時間をおいたら正常に動作しました。deployには少し時間がかかるのかも。

  Serverless Error ---------------------------------------

  The role defined for the function cannot be assumed by Lambda.