LoginSignup
11

More than 3 years have passed since last update.

Scrapyをaws Lambdaで動かす

Last updated at Posted at 2020-11-30

Python製のクローラーフレームワークであるScrapyを使うと、簡単にクローラーを作成することができます。
実際のクローラーの開発・運用ではクローラーを定期的に動かす必要が多いです。
Scrapy単体は定期実行の機能を提供していないため、何かしらの外部の仕組みを活用して定期実行をする必要が出てきます。
例えば、Scrapyの開発元であるScrapingHub社が提供しているPaaSであるScrapy Cloudを使うと定期実行を行うことができます。
このクラウドはScrapyに特化したものであり、ヘッドレスブラウザやIPアドレス偽装などの便利機能とのインテグレーションも容易です。
しかし、この記事ではaws Lambda(以下Lambda)の上でScrapyを動作させてみます。
Lambdaで動かすことで、他のawsサービスとのインテグレーションがやりやすくなります。

PythonコードからScrapyを呼ぶ方法

通常はScrapyを呼び出すために、shellから scrapy run <spiderの名前> 実行します。
しかし、LambdaのエントリーポイントはPython関数であるため、何らかの方法でPythonからScrapyを呼び出す必要があります。
標準ライブラリのsubprocessを使いshellを呼びだすこともできますが、ここではより直接的な方法でScrapyを呼び出してみます。
以下の公式ドキュメントを参考にして、PythonからScrapyを呼び出します。

crawl.py
import os
import csv
from multiprocessing import Process, Queue

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

from .spiders.hoge import HogeSpider

def crawl(file_name):
    # settings.pyに書いていた設定をここに書く
    settings = get_project_settings()
    settings.set('FEEDS', { file_name: {"format": "csv"}})

    process = CrawlerProcess(settings)
    process.crawl(HogeSpider)
    process.start()

    # csvをslackに通知したり、S3に保存したりする

def run():
    file_name = '/tmp/hoge.csv'
    process = Process(target=do_crawl, args=(file_name,))
    process.start()
    process.join()

if __name__ == '__main__':
    run()

crawl関数がScrapyを呼び出す処理の本体です。
ただPythonから呼び出すだけならばこれで十分ですが、LambdaがPythonプロセスを再利用した場合はこのままだとエラーになります。
これはScrapyが内部的に使っている非同期処理ライブラリのtwistによるものです。
そのため、run関数内部でプロセスを生成しそれを使い捨てることで、毎実行ごとに独立したプロセス空間でScrapyを動作させています。

Lambdaから呼び出す

ここまで出来ればあとは簡単です。
Lambdaから呼び出されるハンドラーを作成します。

hander.py
from crawl import run

def start(event, context):
    run()

    response = {
        "statusCode": 200,
        "body": "Success"
    }
    return response

デプロイ

最後に、この設定をLambdaにデプロイします。
デプロイにはServerless Frameworkを利用します。
以下のYAMLファイルを用意し、 serverless deply コマンドを実行すれば定期的にLambdaの上でScrapyが動きます。

serverless.yml
service: hoge-crawler

provider:
  name: aws
  runtime: python3.8
  region: ap-northeast-1

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true

functions:
  start:
    handler: handler.start
    timeout: 600 # 10 min
    events:
      - schedule: cron(0 15 * * ? *) # every day at 00:00 JST

注意点

awsの利用規約

awsのAcceptable Use Policyには以下のように書かれています。

Monitoring or Crawling. Monitoring or crawling of a System that impairs or disrupts the System being monitored or crawled.

そのため、クローリング対象のシステムを妨害するレベルでの大量アクセスをした場合はawsのアカウントが停止される恐れがあります。
Lambda上でクローラーを運用する時は特に適切なダウンロード間隔が設定されているかどうかをしっかりと確認しましょう。

Lambdaの実行時間制限

Lambda関数の実行時間には最大15分の制限があるため、この方法は大規模なサイトをクローリングするのには向いていません。
その場合はEC2にScrapyをインストールしてcronで定期実行したり、ECS Scheduled Taskの機能で定期実行をしたりを考える必要があります。

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
11