AWS

LambdaでスクレイピングするならDockerイメージを使おう【Python】

AWS Lambdaからスクレイピングしてみたい方は、こんな悩みを抱えていませんか?

トラハック
トラハック
Pythonで書いたスクレイピングコードをAWS Lambdaで実行したいけど、どうすればいいの?

この記事では、以下について解説します。

この記事を読めば分かること
  • AWS Lambdaでのスクレイピング用Pythonスクリプト実行環境構築手順(Dockerを使います)
  • AWS Lambdaでのテスト実行方法
  • 任意ワードのGoogle検索結果上位10のURLを取得するスクレイピングコード(Python)

現在私は、SEOライティングのリサーチ自動化プログラムを開発中です。言語はPythonで、SeleniumとHeadless Chromeを使ってスクレイピングします。

サーバー管理が面倒なのでAWS Lambdaを使ってサーバーレス環境から実行させます。このプログラムを作った経験と知見を記事にまとめました。

「開発プロセスの中で私がハマった点」「web検索結果上位の記事にはまとまりきっていないと感じた情報」を、初心者でも分かりやすいよう解説します。

この記事ではAWS Lambdaの実行環境をDockerで用意するので、そもそもDockerを使ったことがない方は、まずこちらの記事を読んでください

LambdaでスクレイピングするならDockerイメージを使おう【Python】
【Python】AWS Lambdaでスクレイピング【Docker概要編】AWS Lambdaでスクレイピングしたい方へ AWS LambdaでスクレイピングPythonスクリプトをイベントド...

この記事内の手順はこちらのQiitaのエントリーを参考にさせていただきました…!
シンプルにまとまっていて大変感謝です。
その中でスキップされている手順や説明を捕捉しています。
AWSやPythonに触れ始めたばかりの方のためになればと思います。

AWS LambdaでPythonのスクレイピングコードを動かす環境構築手順(Dockerを使います)

AWS LambdaでPythonのスクレイピングコードを動かす環境構築手順(Dockerを使います)

まずはDockerイメージの作成手順について解説します。

Dockerを使う理由はスクレイピングに必要なライブラリがAWS Lambdaに存在しないから

残念ながら、SeleniumやBeautifulSoup4といったPythonで有名なスクレイピング用ライブラリは、AWS Lambdaのデフォルトの実行環境に存在していません

AWS Lambda は次のランタイムバージョンをサポートします。
(中略)
・Python – Python 3.6 および Python 2.7

引用元:AWS ドキュメント » AWS Lambda » 開発者ガイド » Lambda 実行環境と利用できるライブラリ

上記の通り、基本的には標準ライブラリのみ利用可能です。

トラハック
トラハック
Pythonでスクレイピングするには外部ライブラリのインポートが必須なのに、どうすればいいの?

そこでDockerを使います。外部ライブラリを含むDockerイメージを作成して、AWS S3バケットにアップロードし、AWS Lambdaの実行環境として利用します。

DockerでSeleniumとServerless-Chromiumをパッケージングする手順

Dockerを使ってAWS Lambda上でのスクレイピング実行環境を作成します。スクレイピングにはSelenium + Headless Chrome(AWS Lambdaで実行するのでServerless-Chromium)を使います。

今回私が作成したコードは以下の通りです。Pythonで書いたスクレイピング用コードで、任意ワードのGoogle検索結果上位10のURLを取得します。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options

def lambda_handler(event,context):
    # Headless Chromeを使うための設定を追加
    options = Options()
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    options.add_argument("--disable-application-cache")
    options.add_argument("--disable-infobars")
    options.add_argument("--no-sandbox")
    options.add_argument("--hide-scrollbars")
    options.add_argument("--enable-logging")
    options.add_argument("--log-level=0")
    options.add_argument("--v=99")
    options.add_argument("--single-process")
    options.add_argument("--ignore-certificate-errors")
    # Headless Chromeを起動
    options.binary_location = "./bin/headless-chromium"
    driver = webdriver.Chrome(executable_path="./bin/chromedriver", chrome_options=options)

    # 検索ワードを取得
    keyword = ''
    for key in event:
        if keyword == '':
            keyword += event[key]
        else:
            keyword += ' ' + event[key]

    # Chromeの検索結果ページにアクセス
    driver.get('https://www.google.co.jp/search?num=10&q='+ ' '.join(keyword))

    links = []
    for counter in range(1,11):
        link = driver.find_element_by_xpath("//*[@id='rso']/div/div/div["+str(counter)+"]/div/div/div/a")
        links.append(link.get_attribute("href"))

    # ブラウザを閉じる
    driver.close()
    # Google Chrome Canaryを終了する
    driver.quit()

    return links

事前準備

まずはワーク用ディレクトリを作成します。Dockerはビルドする際に、カレントディレクトリ内のファイルを全てパッケージングするからです。

以下のコードをターミナルから実行してください。

mkdir google_search_links
cd google_search_links

以降の手順でインストールする各種モジュールは互換性の関係上、最新版ではなく以下の組み合わせとなります元ネタはコチラ

  • severless-chrome v.0.0-37
  • chromedriver v.2.37
  • selenium 2.53.6 (for Python)

Lambda上で動くserverless-chromiumのダウンロード

AWS Lambda上で動くserverless-chromiumのモジュールをダウンロードします。

mkdir -p bin/
curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-37/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip
unzip headless-chromium.zip -d bin/
rm headless-chromium.zip

chromedriverのダウンロード

curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip
unzip chromedriver.zip -d bin/
rm chromedriver.zip

Seleniumのダウンロード(Dockerfileの作成)

Seleniumなどの外部ライブラリは、Dockerfileとrequirements.txtを利用してDockerイメージにパッケージングします。

ローカルでライブラリをpipした場合、ローカル環境(例えばMacOS)で実行可能なファイルがダウンロードされますが、Lambdaで実行するにはAmazon Linux 2用のファイルをダウンロードする必要があります

そのため、Dockerを使っています。

Dockerfileの書き方

FROM lambci/lambda:build-python3.6

ENV AWS_DEFAULT_REGION ap-northeast-1
ENV APP_DIR /var/task

ADD . .

CMD pip install -r requirements.txt -t $APP_DIR && \
  zip -9 deploy_package.zip fetch_links.py && \
  zip -r9 deploy_package.zip *

AWS Lamndaで実行可能な環境にPythonが組み込まれているlambda/lambciを利用してDockerイメージを作成します。

ENVコマンドで、デフォルトリージョンはap-northeast-1(アジアパシフィック(東京))を指定しておけば良いです。

CMDコマンド以降の“zip -9 deploy_package.zip fetch_links.py && \”の行で指定するpythonファイルはあなたが作成したファイル名に適宜変更してください。

requirements.txtはベタ書きで外部ライブラリの名前を書いておけば良いです。

Selenium

ここまで終えると、ディレクトリ構成は以下のようになっているはずです。

work
├ bin
│  ├ chromedriver
│  └ headless-chromium
├ Dockerfile
├ fetch_links.py
└ requirements.txt

この構成となっていない場合、手順を見直して修正してください。

Dockerイメージの作成

いよいよDockerイメージを作成します。

docker build -t lambda_fetch_links .
$ docker run -v "${PWD}":/var/task lambda_fetch_links

docker build -t lambda_fetch_links .

”lambda_fetch_links”という名前のDockerイメージを、カレントディレクトリ内のファイルを全て含めてビルドします。

docker run -v “${PWD}”:/var/task lambda_fetch_links

ビルドしたDockerイメージをDockerfileの内容に従って実行します。

Dockerfileの”CMD”以降に記載したzipコマンドによって、AWS上にアップロードする”deploy_pacakge.zip”が作成されます

AWS Lambda上にDockerイメージをアップロード

それではDockerイメージをS3バケットにアップロードしましょう。

まずはAWSのコマンドラインインターフェイスをローカルにインストールしておきます。

pip install aws-cli

Lambda関数実行に関連する権限の事前準備を済ませておきます。

  1. AWS Lambdaから実行するためのIAMロールの作成
  2. APIキーの設定

詳細な手順は以下の記事にて解説しています。

DockerイメージをAWS Lambdaで使うIAM設定方法
DockerイメージをAWS Lambdaで使うIAM設定方法Dockerなどで用意した実行環境をAWS Lambdaで利用したい方へ この記事では、AWS CLIを使ってLambda用実行環...

また、事前にS3バケットを作成する必要があります。この手順は次の記事内で紹介しています。

手軽で最強のストレージサービスS3の概要と設定方法【優しく解説】
手軽で最強のストレージサービスS3の概要と設定方法【優しく解説】AWSのS3とは何か知りたい方へ この記事では、その疑問について回答します。 S3の特徴については以下の書籍の情報をシンプル...

準備ができたら、S3にDockerイメージをアップロードしてLambda関数を作成します。

aws s3 cp deploy_package.zip s3://YOUR_BUCKET_NAME
aws lambda create-function --region ap-northeast-1 --function-name lambda_headless_chrome_python --runtime python3.6 --role YOUR_ROLE_NAME --code S3Bucket=YOUR_BUCKET_NAME,S3Key=deploy_package.zip --handler fetch_links.lambda_handler --memory-size 512 --timeout 300
  • YOUR_BUCKET_NAME:あなたが作成したS3バケット名を指定
  • YOUR_ROLE_NAME:Lambdaの実行権限とS3の読み取り権限を持つIAMロールをarn形式で指定します。

実際にスクレイピングしてみよう!AWS Lambdaでのテスト実行方法

実際にスクレイピングしてみよう!AWS Lambdaでのテスト実行方法

アップロードが完了したので、AWSコンソールからLambdaにアクセスしてテストを実行して見ましょう。

テストイベントの作成

AWSコンソールの[サービス]一覧からLambdaを選択します。

select-lambda

関数の一覧から、先ほどアップロードした[fetch_links.py]を選択します。

select-function

テストイベントを作成するため[テスト]をクリックします。

create-test

テストイベントの内容を作成します。

  • 新しいテストイベントの作成:チェック
  • イベントテンプレート:Hello World
  • イベント名::任意のイベント名を入力
  • 送信内容:検索したいワードを記載
    JSON形式(Pythonでの辞書型)で記載します。
    以下画像の通り入力すると、アップロードしたスクレイピングコードは”Python”と”スクレイピング”というワードの検索結果上位10のURLを取得します。
content-of-test

テストイベントの実行

テストイベントを作成し終えたら、もう一度[テスト]をクリックします。

execute-test

しばらくするとテストの実行結果が返ってきました!

エラーが無ければ[実行結果:成功]となり、[▼詳細]から検索結果上位10のURLが取得できていることが確認できます

result-of-test

今回の記事は以上です。補足事項は別記事にて追記していきます。

トラハック
トラハック
これでAWS LambdaからPythonで書いたスクレイピングコードを実行できるね!
まとめ
  • PythonによるスクレイピングコードをAWS Lambdaから実行するならDockerで環境構築
  • 使うモジュールはSelenium + Serverless-Chromium
  • テストイベントはJSON形式(Pythonの辞書型)で記載