近々、AWS Lambdaを使って簡易的なクローラを作る予定があったので
Lambda上でNokogiriが使えるか 検証しました。
開発環境
ローカルの開発環境はMac、クローラはRubyで実装します。
ポイント
クローリングに必要となるGemである「Nokogiri」はネイティブライブラリを含むGemであるため、
Mac上でビルドしてAWSへデプロイすると「cannot load such file -- nokogiri
」が発生します。
これを回避するため、AWS SAMを用いて雛形作成した上で、
「sam build --use-container
」を実行しAmazonLinux2のDockerコンテナ上でビルドを行いました。
AWS SAM CLIでHello World
AWS SAM CLIを使ってRubyのLambdaハンドラの雛形を作成します。
アプリの名前が実際に作ろうとしているクローラの名前になっていますので、適宜置き換えてください。
$ sam init --runtime ruby2.5 --name sample_app
$ cd sample_app
$ sam build
$ sam local invoke HelloWorldFunction --event event.json
参考: https://aws.amazon.com/jp/about-aws/whats-new/2018/04/aws-sam-cli-releases-new-init-command/
Nokogiriのインストール
今回はLambda上でスクレイピングツールであるNokogiriを動かす必要があります。
このGemはネイティブライブラリが含まれるため、ローカル環境(今回はMac)でインストールするとLambda上でエラーとなります。
が、AWS SAM CLIは以下コマンドでネイティブライブラリも含めて良い感じにビルドしてくれるコマンドを提供してくれています。便利ですね。
source "https://rubygems.org"
gem "httparty"
gem "nokogiri" # 追記
gem "robotex" # 追記
追記先はルートのGemfileではありませんので注意してください。
cannot load such file -- nokogiri
が起こる原因となります。
Nokogiriを使うLambdaハンドラを実装
動作確認のためLambdaハンドラの処理も修正します。
require "bundler/setup"
Bundler.require
URL='https://www.google.com/'
def lambda_handler(event:, context:)
charset = nil
robotex = Robotex.new
robotex.allowed?(URL)
robotex.delay!(URL)
html = open(URL) do |f|
charset = f.charset
f.read
end
doc = Nokogiri::HTML.parse(html, nil, charset)
{
statusCode: 200,
body: {
page_title: doc.title,
}.to_json
}
end
ローカルの開発環境で動作確認
ビルドして実行してみましょう。
GoogleのTOPページのタイトルが取得できました。
$ sam build --use-container
$ sam local invoke HelloWorldFunction --event event_file.json
{"statusCode":200,"body":"{\"page_title\":\"Google\"}"}
デプロイ
AWS SAM CLIを使ってデプロイします。
$ sam package --output-template-file output.yaml --s3-bucket sample_app
$ sam deploy --template-file output.yaml --stack-name sample_app --capabilities CAPABILITY_NAMED_IAM
ただし、 sam package
に --template-file
オプションを指定すると、vendor配下がアップロードされない問題が発生しました。 --template-file
は設定しないようにしましょう。
AWSコンソールにログインして、Lambdaを実行すると無事成功しました。
参考