Scrapy
は、Python
で使える強力なウェブスクレイピングフレームワークであり、大規模なデータ収集に特化しています。大規模なクローラーを構築するには、効率的なデータ収集、リトライ、並列処理、データ保存の仕組みが不可欠です。この記事では、Scrapyを使って大規模なウェブクローラーを構築する方法をステップごとに紹介します。
Scrapyとは?
Scrapy
は、Python
ベースのウェブスクレイピングフレームワークで、ウェブサイトから効率的にデータを収集するためのツールです。Scrapyの最大の特徴は、並列処理とスケジューリングのサポートによる高速なクローリングです。さらに、スクレイピングしたデータをJSON、CSV、データベースなどに簡単に保存でき、エラー処理や再試行も自動化されています。
Scrapyの主な機能
- 並列処理による高速クローリング
- リトライ機能でエラーや失敗時に再試行
- シンプルな設定で、データパイプラインやミドルウェアをカスタマイズ可能
- JSONやCSV、データベースへの簡単なデータ保存
- ロボット排除規約(robots.txt)に準拠したクローリング
Scrapyのインストール
Scrapyをインストールするには、次のコマンドをターミナルで実行します。
pip install scrapy
インストールが完了したら、Scrapyプロジェクトを作成します。
プロジェクトの作成
次に、Scrapyプロジェクトを作成します。
scrapy startproject mycrawler
これで、新しいScrapyプロジェクトがmycrawler
というディレクトリに作成されます。次に、クローラー(スパイダー)の実装に進みます。
Scrapyスパイダーの作成
スパイダーは、Scrapyでウェブページをクロールし、データを収集するためのメインコンポーネントです。まず、spiders
フォルダに新しいスパイダーを作成します。
スパイダーの基本的な実装
以下は、例としてあるニュースサイトをクロールしてタイトルとリンクを取得するスパイダーのコードです。
import scrapy
class NewsSpider(scrapy.Spider):
name = 'news_spider'
start_urls = ['https://example-news-site.com/']
def parse(self, response):
# 各ニュース記事のタイトルとリンクを抽出
for article in response.css('div.article'):
yield {
'title': article.css('h2.title::text').get(),
'link': article.css('a::attr(href)').get(),
}
# 次のページがあれば、再度リクエストを送信
next_page = response.css('a.next-page::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
コードの説明
start_urls
:スパイダーが最初にアクセスするURLのリスト。parse()
:レスポンスを解析し、データを抽出するメソッド。ここでは、記事のタイトルとリンクを取得しています。yield
:収集したデータや次のリクエストを返す際に使用します。yield
は並列処理をサポートしているため、効率的なクローリングが可能です。 このスパイダーは、ページ内の記事をスクレイピングし、次のページがあれば再帰的にクローリングを続けます。
並列処理の設定
Scrapyはデフォルトで並列処理をサポートしていますが、クローリングの効率をさらに高めるためには、いくつかの設定を調整することが重要です。settings.py
ファイルで、並列リクエスト数やダウンロード遅延などの設定を行います。
並列処理の設定例
# settings.py内
# 並列リクエスト数の設定(デフォルト: 16)
CONCURRENT_REQUESTS = 32
# 同一ドメインへの最大リクエスト数
CONCURRENT_REQUESTS_PER_DOMAIN = 16
# ダウンロードの遅延(0.5秒)
DOWNLOAD_DELAY = 0.5
# リトライ回数
RETRY_TIMES = 3
# クローリング速度を適度に抑える設定
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 1 # 初期遅延時間
AUTOTHROTTLE_MAX_DELAY = 60 # 最大遅延時間
- CONCURRENT_REQUESTS:同時に処理するリクエストの数。これを増やすとクローリング速度が向上します。
- DOWNLOAD_DELAY:サーバー負荷を軽減するためのリクエスト間の遅延時間。適度な値を設定することで、サイトに負担をかけずに効率的にクローリングできます。
- AUTOTHROTTLE_ENABLED:自動でクローリング速度を調整する機能。サーバーの負荷に応じて速度を調整します。
エラー処理とリトライ
大規模なクローリングでは、リクエストの失敗やサーバーエラーが発生する可能性があります。Scrapyはこれに対処するため、リトライ機能が標準で提供されています。RETRY_TIMES
やRETRY_HTTP_CODES
の設定で、エラー発生時のリトライ回数や対象のHTTPステータスコードを指定できます。
リトライ設定の例
# リトライ回数の設定
RETRY_TIMES = 5
# リトライ対象となるHTTPステータスコード
RETRY_HTTP_CODES = [500, 502, 503, 504, 408]
これにより、サーバーの一時的な障害に対してリクエストを再送し、クローリングが途切れないようにできます。
データの保存
Scrapyは、クローリングしたデータをさまざまなフォーマットで保存できます。JSON、CSV、XMLなどの形式に簡単にエクスポート可能です。
JSON形式でデータを保存する例
scrapy crawl news_spider -o output.json
このコマンド
を実行すると、収集したデータがoutput.json
に保存されます。データフォーマットはCSVやXMLにも変更可能です。
データパイプラインを使ったデータベース保存
大規模なクローリングでは、収集データをデータベースに直接保存することが一般的です。pipelines.py
にデータパイプラインを実装し、データをMySQLやMongoDBなどのデータベースに保存します。
import pymongo
class MongoPipeline:
def open_spider(self, spider):
# MongoDBに接続
self.client = pymongo.MongoClient('localhost', 27017)
self.db = self.client['scrapy_db']
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
# データをMongoDBに保存
self.db['news'].insert_one(dict(item))
return item
settings.py
でこのパイプラインを有効化します。
ITEM_PIPELINES = {
'mycrawler.pipelines.MongoPipeline': 300,
}
スケジューリングと自動化
Scrapyは定期的に実行するためのスケジューリング機能をサポートしていませんが、Linuxのcron
やWindowsのタスクスケジューラを使って定期的にクローリングを自動化することが可能です。
Linuxでのcron
によるスケジューリング
以下のようにcron
を設定して、1時間ごとにクローラーを実行できます。
0 * * * * cd /path/to/project && scrapy crawl news_spider
まとめ
Scrapy
は、大規模なウェブクローラーを構築するための強力なフレームワークです。並列処理やリトライ機能を標準でサポートしているため、効率的なクローリングが可能です。また、データの保存やスケジューリングも簡単に行えるため、大量のデータを自動で収集・保存できるシステムを構築できます。
今回紹介した設定や機能を活用し、自分のプロジェクトに最適な大規模クローラーを構築してみてください。