Scrapyライブラリ 詳細
Scrapyは、Pythonで書かれたウェブクローリングおよびウェブスクレイピングのための高速で強力なフレームワークです。単なるHTMLパーサーやリクエストライブラリとは異なり、リクエストのスケジューリング、レスポンスの処理、アイテムのパイプライン処理、ロギング、エラーハンドリングなど、ウェブスクレイピングプロジェクト全体を構造化し、効率的に実行するための包括的な機能を提供します。
小規模なスクレイピングから、数百万ページに及ぶ大規模なクローリングまで対応できるように設計されており、非常に堅牢で拡張性が高いのが特徴です。
1. Scrapyのインストール
ScrapyはPythonの標準ライブラリではないため、pipを使用してインストールする必要があります。
Bash
pip install scrapy
Scrapyは依存関係としてTwistedという非同期ネットワークフレームワークを使用しているため、Windows環境ではビルドツールが必要になる場合があります。その場合は、pip install wheelの後にpip install Twistedを試すか、非公式のバイナリパッケージを利用することもあります。
2. Scrapyのアーキテクチャと主要コンポーネント
Scrapyはモジュール化されたアーキテクチャを採用しており、各コンポーネントが特定の役割を担っています。
- Engine (エンジン):
Scrapyの心臓部。すべてのコンポーネント間のデータフローを制御し、イベント駆動で処理を進めます。 - Scheduler (スケジューラー): エンジンから受け取ったリクエストをキューに入れて管理し、次にクロールするURLを決定します。重複リクエストのフィルタリングも行います。
- Downloader (ダウンローダー): スケジューラーからリクエストを受け取り、Webサイトから実際のコンテンツ(HTMLなど)をダウンロードします。
- Spiders (スパイダー): ユーザーが記述するクラス。Webサイトの巡回ロジックと、ダウンロードされたHTMLからデータを抽出するロジックを定義します。
- Item Pipelines (アイテムパイプライン): スパイダーが抽出したアイテム(データ)を処理するためのコンポーネント。データのバリデーション、クレンジング、データベースへの保存などを行います。
- Middlewares (ミドルウェア):
- Downloader Middleware (ダウンローダーミドルウェア): リクエストがダウンローダーに到達する前、またはレスポンスがダウンローダーから返される途中に、リクエストやレスポンスをフックして処理を変更します(例: User-Agentの変更、プロキシの追加、リトライ処理)。
- Spider Middleware (スパイダーミドルウェア): 入力されるレスポンスをスパイダーに送る前、またはスパイダーから出力されるアイテムやリクエストをエンジンに送る途中に、処理をフックします。
これらのコンポーネントが非同期に連携することで、高いパフォーマンスと効率的なスクレイピングを実現します。
3. Scrapyプロジェクトの作成とスパイダーの定義
3-1. プロジェクトの作成
まず、コマンドラインで新しいScrapyプロジェクトを作成します。
Bash
scrapy startproject myproject
これにより、以下のようなディレクトリ構造が生成されます。
myproject/
├── scrapy.cfg # プロジェクト設定ファイル
└── myproject/
├── __init__.py
├── items.py # 抽出するデータの構造定義
├── middlewares.py # ミドルウェア定義
├── pipelines.py # アイテムパイプライン定義
├── settings.py # プロジェクト設定
└── spiders/ # スパイダーを格納するディレクトリ
└── __init__.py
3-2. Item(アイテム)の定義
items.pyファイルで、抽出したいデータの構造を定義します。これはPythonのdictに似ていますが、より構造化されています。
Python
# myproject/items.py
import scrapy
class MyprojectItem(scrapy.Item):
# 抽出したいデータのフィールドを定義
title = scrapy.Field()
author = scrapy.Field()
url = scrapy.Field()
3-3. Spider(スパイダー)の定義
spidersディレクトリ内に新しいPythonファイルを作成し、スパイダーを定義します。スパイダーはscrapy.Spiderを継承します。
Python
# myproject/spiders/myspider.py
import scrapy
from myproject.items import MyprojectItem # 定義したItemをインポート
class MySpider(scrapy.Spider):
name = 'my_spider' # スパイダーの名前(プロジェクト内で一意)
start_urls = ['http://quotes.toscrape.com/'] # クロールを開始するURLのリスト
# クロールしたページからデータを抽出するメソッド
def parse(self, response):
# CSSセレクタまたはXPathを使用してデータを抽出
quotes = response.css('div.quote') # クラスが'quote'のdiv要素をすべて取得
for quote in quotes:
item = MyprojectItem()
item['title'] = quote.css('span.text::text').get() # テキストを取得
item['author'] = quote.css('small.author::text').get()
item['url'] = response.url # ページのURLをそのまま取得
yield item # 抽出したアイテムをパイプラインに送る
# 次のページへのリンクをたどる (ページネーション)
next_page = response.css('li.next a::attr(href)').get() # 次のページのhref属性値を取得
if next_page is not None:
# yield response.follow(next_page, callback=self.parse)
# ↑ 上記は相対URLでも動作する便利なメソッド
yield response.follow(next_page, callback=self.parse) # 次のページをクロールし、同じparseメソッドで処理
3-4. スパイダーの実行
プロジェクトのルートディレクトリで以下のコマンドを実行します。
Bash
scrapy crawl my_spider -o output.json # -o でJSONファイルに保存
my_spiderはスパイダーのname属性で指定した名前です。
4. データの抽出(セレクタ)
Scrapyは、HTML/XMLからデータを抽出するためにCSSセレクタとXPathという2つの強力なセレクタメカニズムを提供します。
- CSSセレクタ (
response.css()): CSSで要素を指定するのと同じ記法。シンプルで直感的。div.quote:class="quote"のdiv要素#main-content:id="main-content"の要素a::attr(href):aタグのhref属性値span.text::text:class="text"のspanタグのテキストノード
- XPath (
response.xpath()): XMLドキュメント内のノードを選択するための言語。CSSセレクタよりも強力で、より複雑な階層関係や属性に基づいた選択が可能。//div[@class="quote"]:class="quote"のすべてのdiv要素//a/@href: すべてのaタグのhref属性値//span[@class="text"]/text():class="text"のspanタグのテキストノード
いずれのメソッドも、Selectorオブジェクトのリストを返します。
selector.get(): 最初のセレクタにマッチする単一の結果(文字列)を取得。selector.getall(): すべてのセレクタにマッチする結果をリスト(文字列)で取得。
5. Item Pipelines (アイテムパイプライン)
スパイダーがyield itemで返したデータは、アイテムパイプラインを通過します。 pipelines.pyファイルでクラスを定義し、process_itemメソッドを実装します。
Python
# myproject/pipelines.py
class MyprojectPipeline:
def process_item(self, item, spider):
# 例: タイトルフィールドの空白を削除
if item.get('title'):
item['title'] = item['title'].strip()
# 例: データベースに保存
# self.db_connection.execute("INSERT ...", item)
return item # 次のパイプライン、または最終的な出力にアイテムを渡す
パイプラインを有効にするには、settings.pyでITEM_PIPELINESに登録します。
Python
# myproject/settings.py
ITEM_PIPELINES = {
'myproject.pipelines.MyprojectPipeline': 300, # 数値は実行順序(小さいほど早く実行)
}
6. Settings (設定)
settings.pyファイルは、Scrapyプロジェクト全体の挙動を制御します。主要な設定項目をいくつか挙げます。
USER_AGENT: デフォルトのUser-Agent。スクレイピング時にWebサイトのサーバーに人間からのアクセスであることを示すために設定します(例:'Mozilla/5.0 ... Chrome/...')。ROBOTSTXT_OBEY:robots.txtのルールに従うかどうか。デフォルトはTrue(推奨)。CONCURRENT_REQUESTS: 最大同時リクエスト数。サーバーへの負荷を考慮して調整します。DOWNLOAD_DELAY: リクエスト間の最小遅延時間(秒)。スクレイピング対象のサーバーへの負荷軽減と、IPブロック回避のために重要です。COOKIES_ENABLED: クッキーを有効にするかどうか。ログインが必要なサイトではTrue。ITEM_PIPELINES: 使用するアイテムパイプラインとその実行順序。DOWNLOADER_MIDDLEWARES: 使用するダウンローダーミドルウェアとその実行順序。AUTOTHROTTLE_ENABLED: 自動スロットリング(サーバーへの負荷に応じてリクエスト速度を自動調整)を有効にするかどうか。推奨設定。
7. Middlewares (ミドルウェア)
ミドルウェアは、Scrapyの強力な拡張ポイントです。リクエスト/レスポンス処理の途中でカスタムロジックを挿入できます。
- Downloader Middleware:
- User-Agentのランダム変更
- プロキシの自動切り替え
- HTTPリダイレクトのハンドリング
- リクエストのリトライ処理
- クローラーのIPアドレスを変更するためのTor統合
- Spider Middleware:
- スパイダーに渡すレスポンスを前処理
- スパイダーからエンジンに送るリクエストやアイテムを後処理
ミドルウェアもsettings.pyで有効化・設定します。
Python
# myproject/settings.py
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.MyprojectDownloaderMiddleware': 543,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, # デフォルトを無効化
'scrapy.downloadermiddlewares.retry.RetryMiddleware': None, # デフォルトを無効化
'scrapy_fake_useragent.middleware.RandomUserAgentMiddleware': 400, # 外部ライブラリ
}
8. Scrapy Shell
Scrapyには、対話的なシェル (scrapy shell) が付属しており、スパイダーを開発する際に非常に便利です。特定のURLにアクセスし、そのレスポンスに対してCSSセレクタやXPathを試しながらデータを抽出するコードをテストできます。
Bash
scrapy shell "http://quotes.toscrape.com/page/1/"
シェル内では、response オブジェクトが自動的に利用可能です。
Python
# シェル内で
response.css('title::text').get()
response.xpath('//h1/a/text()').get()
9. まとめ
Scrapyは、ウェブスクレイピングとクローリングのための単なるライブラリではなく、完全なフレームワークです。
- 非同期処理: 高速な並行処理を実現。
- 構造化: アイテム、パイプライン、ミドルウェアによりプロジェクトを整理。
- 拡張性: 各コンポーネントを自由にカスタマイズ・拡張可能。
- 堅牢性: リクエストスケジューリング、リトライ、重複フィルタリングなどにより安定した動作。
- 開発者ツール:
ScrapyShellなど、開発を助けるツールが豊富。
小規模なデータ収集から大規模なWebコンテンツ分析まで、Pythonでウェブデータを扱うプロフェッショナルなタスクにおいて、Scrapyは強力な選択肢となります。ただし、その多機能さゆえに学習曲線はRequestsやBeautifulSoup単体よりも急ですが、一度習得すれば、複雑なスクレイピングプロジェクトを効率的に構築・運用できるようになります。
ウェブスクレイピングを行う際は、必ず対象サイトの利用規約を確認し、robots.txtに従い、サーバーに過度な負荷をかけないよう倫理的な行動を心がけてください。
