2
4

More than 3 years have passed since last update.

AWS Lambda(python)で Selenium を動かしてハマった点まとめ

Last updated at Posted at 2021-01-04

はじめに

Python を用いてスクレイピングをするにあたり、認証周りで躓き手っ取り早く解決するために Selenium を用いて実装したものの、Lambda で実行しようとしたときに躓いたので、メモとして残します(書きっぷりが雑になっているかもしれません…)
※ この記事は SAM を使わずに実装してます:bow:

作業環境

  • Windows 10
  • python 3.7 が望ましいけど、3.8 でも大抵はどうにでもなった
    • (使い方にもよるので、バージョン管理で切り替えられるようになっているとよい)

ハマりポイントその1

Q. Selenium を使うにあたって、headless-chromium と chromedriver を使えばいいの?
A. この2つを圧縮して、レイヤーに登録する

詳細

AWS Lambda で使用できるヘッドレスブラウザとして以下が提供されています
この、chrome と chromedriver のバージョンを合わせて1つのファイルとして圧縮します
https://github.com/adieuadieu/serverless-chrome

参考記事
https://qiita.com/mishimay/items/afd7f247f101fbe25f30

レイヤーの登録方法

image.png
1. 「レイヤーの作成」を押下する
image.png
2. 自分がわかる名前や説明をつけて、zip ファイルをアップロードする(chrome と chromedriver をまとめて圧縮すると容易に 10MB は超えるので、S3 にアップした後登録する必要が生じる)
image.png
3. Lambda の「レイヤーの追加」を押下して、追加したレイヤーを選択する

補足説明

レイヤーに登録すると「/opt/xxxx」配下にファイルが配置されることになる
例えば、chrome ディレクトリを作り、その配下に「serverless-chrome、chromedriver」のファイルを配置して圧縮したものをレイヤーに登録した場合は以下のような定義になる

    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options

    options = Options()
    options.binary_location = '/opt/chrome/headless-chromium'
    options.add_argument("--headless")
    options.add_argument("--no-sandbox")
    options.add_argument("--single-process")
    options.add_argument("--disable-gpu")
    options.add_argument("--window-size=1280x1024")
    options.add_argument("--disable-application-cache")
    options.add_argument("--disable-infobars")
    options.add_argument("--hide-scrollbars")
    options.add_argument("--enable-logging")
    options.add_argument("--log-level=0")
    options.add_argument("--ignore-certificate-errors")

    driver = webdriver.Chrome(
        options=options, executable_path='/opt/chrome/chromedriver')

ハマりポイントその2

Q. Lambda 上で Selenium が動かない
A. python 3.8 だと Amazon Linux2 になっているのか一部ライブラリがないため動かない

実行時にステータスコード 127 エラーが発生する(ザっと調べているとライブラリが不足しているかららしい)
何かしら対応策はあるかもしれないが、手っ取りばやく対応するには python3.7 の環境で実行するようにすればよい

ハマりポイントその3

Selenium で全部実装するとクッソ遅い

現象

メモリ 512MB で70ページ、約2100件(1ページ辺り30件)のテーブルをパースして dynamoDB に登録する処理を実施するのに12分掛かった

原因

Selenium で element をガリごり操作するのはとてもコストが掛かった

対策

例えばページを読み込んだ後、パース以降の処理を BeautifulSoup に任せる
※ lxml は xPath が使えて便利な反面 C言語を用いているため環境依存する。そのため、Amazon Linux2 環境でデプロイするなど、手間が増えてしまうことが実装中にわかったため BeautifulSoup を用いた

例)

driver.get('https://example.com')
html = BeautifulSoup(driver.page_source, 'html.parser')
table = html.select_one('table')
rows = table .findAll('tr')
for row in rows:
    cells = row.findAll('td')
# todo 
driver.quit()

結果として、同条件下で 12分 => 2分と処理速度の改善が見られた

実装中に理解した小ネタ

lambda の python を実行する際、「/opt/python/」配下にあるライブラリを読み込むようになっているらしい
そのため、「pip install -r ./requirements.txt -t .」等でlibを吐き出して zip 圧縮したものをレイヤーに登録しておくことで、実行するソースファイルのみをアップロード出来るようになり Lambda の WEB の画面からソースの編集が出来るようになった

さいごに

Lambda で Selenium って動かせると思っていなくて、ローカル PC の WSL に cron 仕込もうかって思っていたけれど、そんなことをしなくても良いことを知った

レイヤーすごい:laughing:
次はこれらを template.yml やレイヤーの yml ファイルを用意して、sam を用いてデプロイ出来るようになりたいなと思いました:sweat:

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4