サイトアイコン

toLog

Lambda(Python)でSeleniumが動かないのでバージョンを調整して解決した件

  • 更新日:
  • 投稿日:
サムネイル

この記事は最終更新日から3年以上が経過しています。

はじめに

Lambda(Python)でスクレイピングしたくて Selenium とか ChromeDriver でゴニョゴニョしようとしたのですが、案の定エラーに詰まって動きませんでした。

Lambda 上で headless-chrome を使うために導入した serverless-chrome と Python とのバージョン齟齬、Selenium と ChromeDriver のバージョン齟齬など、今回は Python、Selenium、ChromeDriver、serverless-chrome の各バージョンを揃える必要がありました。

serverless-chrome の Issue に上記の解決法が載っているで、今回はこの Issue を参考に AWS SAM や Lambda Layer を使って簡単なスクレイピングをしてみました。

Serverless Chrome?

Serverless Chrome には、AWS Lambda でヘッドレス Chrome の実行を開始するために必要なものがすべて含まれています(Azure 機能と GCP 機能は間もなく)。

このプロジェクトの目的は、サーバーレス関数の呼び出し中にヘッドレス Chrome を使用するための足場を提供することです。サーバーレス Chrome は、Chrome バイナリの構築とバンドルを処理し、サーバーレス機能の実行時に Chrome が実行されていることを確認します。

さらに、このプロジェクトは、一般的なパターンのいくつかのサンプルサービスも提供します(例:ページのスクリーンショットを撮る、PDF に印刷する、一部を削るなど)。

adieuadieu/serverless-chrome の README の翻訳より

バージョン調整(2020/04/14 時点)

Issue を参考に動作確認を行ったバージョン関係です。

注意することは Python 3.8 では動作しないことでした。

サンプル

とりまディレクトリ構造

あくまでもサンプルです。

sam init してゴニョゴニョした後に完成するディレクトリ構造です。

不要なものは消しています。

1$ tree .
2.
3├── layer
4│   └── bin
5│       ├── chromedriver
6│       └── headless-chromium
7├── sample
8│   ├── __init__.py
9│   ├── app.py
10│   └── requirements.txt
11└── template.yaml

chromedriver 等の実行ファイルをダウンロード

1# LambdaLayer用のディレクトリ作成
2$ mkdir -p layer/bin
3
4# ダウンロード Chrome Driver 2.43
5$ wget https://chromedriver.storage.googleapis.com/2.43/chromedriver_linux64.zip -P layer/bin
6$ unzip layer/bin/chromedriver_linux64.zip
7
8# ダウンロード Serverless Chrome v1.0.0-55
9$ wget https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-55/stable-headless-chromium-amazonlinux-2017-03.zip -P layer/bin
10$ unzip layer/bin/stable-headless-chromium-amazonlinux-2017-03.zip

サンプル template.yaml

注意したいのは Python のランタイムが 3.6 であることです。

layer は、コンテナ上で /opt/ 直下に配置されます。

layer/bin/*** であれば /opt/bin/*** に置かれます。

1AWSTemplateFormatVersion: "2010-09-09"
2Transform: AWS::Serverless-2016-10-31
3
4Globals:
5  Function:
6    Timeout: 30
7
8Resources:
9  ServerlessFunction:
10    Type: AWS::Serverless::Function
11    Properties:
12      FunctionName: sample-selenium-function
13      CodeUri: sample/
14      Handler: app.lambda_handler
15      Runtime: python3.6
16      Layers:
17        - !Ref ServerlessLayer
18
19  ServerlessLayer:
20    Type: AWS::Serverless::LayerVersion
21    Properties:
22      LayerName: sample-selenium-layer
23      ContentUri: layer/

requirements.txt に Selenium ライブラリを追加

Lambda Layer をせっかく使っているので layer/python/ 等に固めるが良いのかなとも思っていますが、今回は requirements.txt で単純にライブラリ管理しています。

1cat << EOF >> sample/requirements.txt
2selenium
3EOF

サンプル app.py(Lambda)

Yahoo ニュースを対象に class から要素を print する簡単なサンプルになります。 詳しい操作方法はこちらの API ドキュメントを参考にしてもらえればです。

1import json
2from selenium import webdriver
3
4CHROME_DRIVER_PATH = "/opt/bin/chromedriver"
5HEADLESS_CHROMIUM_PATH = "/opt/bin/headless-chromium"
6
7TARGET_URL = "https://news.yahoo.co.jp/"
8
9def lambda_handler(event, context):
10
11    options = webdriver.ChromeOptions()
12    options.binary_location = HEADLESS_CHROMIUM_PATH
13    options.add_argument('--headless')
14    options.add_argument('--no-sandbox')
15    options.add_argument('--single-process')
16
17    chrome_driver = webdriver.Chrome(
18        executable_path = CHROME_DRIVER_PATH,
19        chrome_options = options)
20
21    chrome_driver.get(TARGET_URL)
22
23    print(chrome_driver.find_element_by_class_name('topics_title').text)
24
25    chrome_driver.close()
26    chrome_driver.quit()
27
28    return {
29        "statusCode": 200,
30        "body": json.dumps({
31            "message": "success",
32        }),
33    }

出力結果

1$ sam build
2$ sam local invoke
3>> トピックス

おわりに

全体的にバージョン低めなので慎重に運用する必要がありそうだなと思っていますが、比較的簡単にスクレイピングできてしまう Lambda はやっぱりすごいですね。

ひよっこですが、簡単なサービスをどんどん Lambda で組んでみたいです。

参考文献


プロフィール画像

canji

とにかく私的にサービスを作りたい発作を起こしている。お腹はペコペコ。

  • toLog Tools icon
  • dots icon