はじめに
Python を用いてスクレイピングをするにあたり、認証周りで躓き手っ取り早く解決するために Selenium を用いて実装したものの、Lambda で実行しようとしたときに躓いたので、メモとして残します(書きっぷりが雑になっているかもしれません…)
※ この記事は SAM を使わずに実装してます
作業環境
- 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
レイヤーの登録方法
- 「レイヤーの作成」を押下する
- 自分がわかる名前や説明をつけて、zip ファイルをアップロードする(chrome と chromedriver をまとめて圧縮すると容易に 10MB は超えるので、S3 にアップした後登録する必要が生じる)
- 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 仕込もうかって思っていたけれど、そんなことをしなくても良いことを知った
レイヤーすごい
次はこれらを template.yml やレイヤーの yml ファイルを用意して、sam を用いてデプロイ出来るようになりたいなと思いました