Webサイトから大量のデータを効率よく収集したい場面は、価格調査・市場分析・学術研究などさまざまです。Scrapy(読み方:スクレイピー)は、そうしたデータ収集を自動化するためのPython製オープンソースフレームワークで、GitHubスター数は約59,700、フォーク数は約11,200と、Python界で最も利用されているクローリング基盤の一つです(出典: GitHub - scrapy/scrapy)。
2026年1月時点の最新安定版は 2.14.1 で、Python 3.10〜3.13に対応しています(出典: PyPI - Scrapy)。ライセンスはBSD-3-Clauseで、商用利用にも制限がありません。
Scrapyの基本コンセプト ── 単なるライブラリではなくフレームワーク
BeautifulSoupやlxmlが「HTMLを解析するライブラリ」であるのに対し、Scrapyはクローリングとスクレイピングの両方を統合的に管理するアプリケーションフレームワークです。リクエスト送信・レスポンス受信・データ抽出・保存処理・エラーハンドリング・リトライ制御をまとめて面倒を見てくれるため、開発者はデータ抽出ロジックに集中できます。
主な設計思想は次の3点です。
- 非同期I/O: 内部でTwisted(イベント駆動ネットワークエンジン)を使い、複数リクエストを同時並行で処理します。requestsライブラリで順次アクセスするよりも圧倒的に高速です。
- プラグイン拡張性: Middleware・Pipeline・Extensionの仕組みで、リクエスト/レスポンスの加工やデータ保存先の切り替えを自由にカスタマイズできます。
- 規約による生産性: プロジェクトテンプレートとコマンドラインツールにより、Spider定義・設定・実行の流れが統一されています。
Scrapyのアーキテクチャ ── 5つの構成要素を把握する
Scrapyの内部データフローは、以下の5つのコンポーネントが連携して動作します。
| コンポーネント | 役割 | 開発者が触る頻度 |
|---|---|---|
| Engine | 全コンポーネント間のデータフローを制御する司令塔 | 通常は触らない |
| Scheduler | Engineから受け取ったリクエストをキューに格納し、順序制御する | 設定で調整 |
| Downloader | HTTPリクエストを実行し、レスポンスをEngineに返す | Middlewareで拡張 |
| Spider | レスポンスを解析し、Item(抽出データ)や追加リクエストを生成する | 主に開発 |
| Item Pipeline | Spiderが生成したItemを受け取り、バリデーション・変換・保存を行う | 必要に応じて実装 |
処理の流れを簡潔にまとめると、次のようになります。
- SpiderがURLを定義 → Engineがリクエスト生成
- Schedulerがキューイング → DownloaderがHTTPアクセス
- レスポンスをSpiderに渡す → Spiderがデータ抽出
- 抽出したItemをPipelineが加工・保存
- 追加のURLがあれば1に戻る
この一連の流れの中でDownloader MiddlewareやSpider Middlewareが介在し、ヘッダー付与・プロキシ設定・レスポンスフィルタリングなどを差し込めます。
Scrapyのインストール手順
pip(推奨)
pip install scrapy
仮想環境(venv)を利用する場合は事前に作成しておきます。
python -m venv scrapy-env
source scrapy-env/bin/activate # macOS / Linux
scrapy-env\Scripts\activate # Windows
pip install scrapy
conda
Anacondaを利用している場合はconda-forgeチャネルからインストールできます。
conda install -c conda-forge scrapy
インストール確認
scrapy version
# Scrapy 2.14.1
バージョン番号が表示されれば成功です。依存ライブラリ(Twisted、lxml、cssselect等)も自動的にインストールされます。
プロジェクト作成からSpider実行までの流れ
1. プロジェクトの作成
scrapy startproject myproject
cd myproject
以下のディレクトリ構成が生成されます。
myproject/
scrapy.cfg
myproject/
__init__.py
items.py # データ構造の定義
middlewares.py # ミドルウェア
pipelines.py # データ保存処理
settings.py # 各種設定
spiders/ # Spider格納ディレクトリ
__init__.py
2. Spiderの生成
genspider コマンドで雛形を作成します。
scrapy genspider sample_spider example.com
spiders/sample_spider.py が生成されます。
3. Spiderの実装例
Books to Scrape(スクレイピング練習用サイト)からデータを取得する例です。
import scrapy
class BooksSpider(scrapy.Spider):
name = "books"
start_urls = ["https://books.toscrape.com/catalogue/category/books/fantasy_19/index.html"]
def parse(self, response):
for book in response.css("article.product_pod"):
yield {
"title": book.css("h3 a::attr(title)").get(),
"price": book.css(".price_color::text").get(),
"availability": book.css(".availability::text").getall()[-1].strip(),
}
# 次ページへのリンクをたどる
next_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, callback=self.parse)
4. 実行とデータ出力
scrapy crawl books -o books.json
-o オプションで出力形式を指定できます。対応フォーマットはJSON、JSON Lines、CSV、XMLです。
scrapy crawl books -o books.csv # CSV出力
scrapy crawl books -o books.jsonl # JSON Lines出力
settings.pyで押さえるべき設定項目
実運用では、対象サイトへの負荷を配慮した設定が重要です。
# リクエスト間隔(秒)
DOWNLOAD_DELAY = 1
# 同時並行リクエスト数
CONCURRENT_REQUESTS = 8
# 同一ドメインへの同時リクエスト上限
CONCURRENT_REQUESTS_PER_DOMAIN = 4
# robots.txtの遵守
ROBOTSTXT_OBEY = True
# User-Agentの設定
USER_AGENT = "myproject (+http://www.example.com)"
# レスポンスキャッシュ(開発時に便利)
HTTPCACHE_ENABLED = True
HTTPCACHE_EXPIRATION_SECS = 3600
DOWNLOAD_DELAY を設定すると、Scrapyは指定秒数の間隔を空けてリクエストを送信します。AUTOTHROTTLE_ENABLED = True を併用すると、サーバーのレスポンス時間に応じて自動的にリクエスト間隔を調整してくれます。
Item Pipelineによるデータ加工と保存
SpiderがyieldしたデータはItem Pipelineを通過します。バリデーション、重複排除、データベースへの書き込みなどを実装できます。
# pipelines.py
class PriceValidationPipeline:
def process_item(self, item, spider):
price_str = item.get("price", "")
if price_str.startswith("£"):
item["price"] = float(price_str.replace("£", ""))
return item
class DuplicateFilterPipeline:
def __init__(self):
self.seen_titles = set()
def process_item(self, item, spider):
title = item.get("title")
if title in self.seen_titles:
raise scrapy.exceptions.DropItem(f"Duplicate: {title}")
self.seen_titles.add(title)
return item
settings.py でPipelineを有効化します。
ITEM_PIPELINES = {
"myproject.pipelines.DuplicateFilterPipeline": 100,
"myproject.pipelines.PriceValidationPipeline": 200,
}
数値が小さいほど先に実行されます。
XPathとCSSセレクタ ── データ抽出の2つのアプローチ
Scrapyでは、XPathとCSSセレクタの両方でDOM要素を指定できます。
| 操作 | CSSセレクタ | XPath |
|---|---|---|
| クラス指定 | response.css(".price_color::text") | response.xpath('//span[@class="price_color"]/text()') |
| 属性取得 | response.css("a::attr(href)") | response.xpath('//a/@href') |
| テキスト取得 | response.css("h3::text") | response.xpath('//h3/text()') |
| 単一取得 | .get() | .get() |
| 全件取得 | .getall() | .getall() |
CSSセレクタはシンプルな指定に向いており、XPathはテキスト内容による絞り込みや兄弟要素の参照など複雑な条件に強いです。実務では両者を使い分けることが多いです。
scrapy shell コマンドを使えば、対話的にセレクタを試せます。
scrapy shell "https://books.toscrape.com"
>>> response.css("article.product_pod h3 a::attr(title)").getall()
Scrapy・BeautifulSoup・Seleniumの使い分け
Python のスクレイピングでよく比較される3つのツールは、それぞれ得意分野が異なります。
| 観点 | Scrapy | BeautifulSoup | Selenium |
|---|---|---|---|
| 種別 | クローリングフレームワーク | HTML解析ライブラリ | ブラウザ自動化ツール |
| 非同期処理 | 標準搭載(Twisted) | なし(別途asyncioが必要) | なし |
| JavaScript実行 | 単体では不可(プラグインで対応) | 不可 | ブラウザエンジンで実行 |
| 処理速度 | 高速 | 中程度(リクエストは別途) | 低速(ブラウザ起動コスト) |
| 学習コスト | やや高い | 低い | 中程度 |
| 大規模収集 | 得意(並行処理・リトライ内蔵) | 自前実装が必要 | 不向き |
| 適用場面 | 複数ページを横断する大量データ収集 | 単一ページの解析・小規模案件 | ログインが必要なサイト・SPA |
選び方の目安として、数ページ程度のシンプルな取得ならBeautifulSoup + requests、大規模なクロールや定期実行ならScrapy、JavaScriptレンダリングが必須のSPAサイトならSeleniumが適しています。
Scrapy-Playwrightで動的サイトに対応する
Scrapy単体ではJavaScriptで描画されるコンテンツを取得できません。この制約を解消するのが scrapy-playwright プラグインです。Microsoft製ブラウザ自動化ライブラリPlaywrightとScrapyを統合し、ヘッドレスブラウザ経由でページを取得できます。
導入手順
pip install scrapy-playwright
playwright install chromium
settings.pyへの追記
DOWNLOAD_HANDLERS = {
"http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
"https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
}
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
Spiderでの利用例
import scrapy
class DynamicSpider(scrapy.Spider):
name = "dynamic"
start_urls = ["https://example.com/spa-page"]
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(
url,
meta={"playwright": True, "playwright_include_page": True},
)
async def parse(self, response):
page = response.meta["playwright_page"]
await page.wait_for_selector(".loaded-content")
# ページ内容が読み込まれた状態でresponseを取得
content = await page.content()
await page.close()
sel = scrapy.Selector(text=content)
for item in sel.css(".loaded-content .item"):
yield {
"name": item.css("::text").get(),
}
Seleniumと比較したscrapy-playwrightの利点は、Scrapyのスケジューラ・リトライ・Pipeline等の仕組みをそのまま活用しながらJavaScript描画に対応できる点です。従来のSelenium連携(scrapy-selenium)よりも高速かつ安定して動作します。
Scrapy Shellを活用したデバッグ手法
開発中のSpiderのセレクタをすばやく検証するには、Scrapy Shellが便利です。
scrapy shell "https://books.toscrape.com"
対話環境が起動し、response オブジェクトを使ってCSSセレクタやXPathをリアルタイムに試行できます。
>>> response.css("title::text").get()
'All products | Books to Scrape - Sandbox'
>>> len(response.css("article.product_pod"))
20
>>> response.xpath('//article[@class="product_pod"]//h3/a/@title').getall()[:3]
['A Light in the Attic', 'Tipping the Velvet', 'Soumission']
本番のSpiderに組み込む前にShellで動作確認する習慣をつけると、デバッグ時間を大幅に短縮できます。
robots.txtとスクレイピングの倫理的配慮
Scrapyはデフォルトで ROBOTSTXT_OBEY = True が設定されており、対象サイトのrobots.txtを参照してアクセス制御に従います。
収集作業を行う際は、以下の原則を守ることが重要です。
- robots.txtの遵守:
Disallowで指定されたパスにはアクセスしない - リクエスト間隔の設定:
DOWNLOAD_DELAYやAUTOTHROTTLEを適切に設定し、サーバーに過度な負荷をかけない - 利用規約の確認: 対象サイトの利用規約でスクレイピングが禁止されていないか事前に確認する
- 個人情報の取り扱い: 収集したデータに個人情報が含まれる場合は、個人情報保護法やGDPRなどの法規制を遵守する
USER_AGENT に連絡先情報を含めておくと、サイト管理者から問い合わせがあった際に迅速に対応できます。
Zyte(旧Scrapinghub)とScrapy Cloudの関係
Scrapyの開発を主導している企業がZyte(旧Scrapinghub)です。Zyteは以下のクラウドサービスを提供しています。
- Scrapy Cloud: Scrapyプロジェクトをクラウド上でデプロイ・実行・スケジューリングする実行基盤
- Zyte API: プロキシ管理・CAPTCHA突破・JavaScriptレンダリングを統合したAPI
- Zyte Data: 特定業界向けの構造化データ提供サービス
ローカル環境でScrapyを運用する場合は無料ですが、定期実行やスケール対応が必要な場合はScrapy Cloudが選択肢になります。CLIツール shub を使ってデプロイできます。
pip install shub
shub deploy
実務で役立つTips
複数ページの巡回(ページネーション対応)
def parse(self, response):
# データ抽出処理
for item in response.css(".item"):
yield {"name": item.css("::text").get()}
# 次ページへ遷移
next_url = response.css("a.next::attr(href)").get()
if next_url:
yield response.follow(next_url, callback=self.parse)
Spider実行時の引数渡し
scrapy crawl books -a category=fantasy -a max_pages=5
Spider側で __init__ メソッドで受け取ります。
class BooksSpider(scrapy.Spider):
name = "books"
def __init__(self, category=None, max_pages=10, *args, **kwargs):
super().__init__(*args, **kwargs)
self.category = category
self.max_pages = int(max_pages)
ログレベルの調整
scrapy crawl books --loglevel WARNING
開発中はDEBUG、本番運用ではWARNINGまたはERRORに設定すると出力が整理されます。
よくある質問
Scrapyの読み方は?
スクレイピーと読みます。「Scraping」から派生した名称です。
BeautifulSoupとScrapyはどちらを先に学ぶべき?
HTML解析の基礎を理解するにはBeautifulSoupが適しています。requestsと組み合わせた小規模スクレイピングに慣れた後、複数ページにまたがる本格的なクロールが必要になった段階でScrapyへ移行するとスムーズです。
Scrapyでログインが必要なサイトをクロールできる?
FormRequest を使ってログインフォームにPOSTリクエストを送信し、セッションCookieを維持したまま後続ページをクロールできます。
def start_requests(self):
yield scrapy.FormRequest(
"https://example.com/login",
formdata={"user": "myuser", "pass": "mypass"},
callback=self.after_login,
)
対象サイトにアクセスを拒否された場合は?
まずrobots.txtを確認し、アクセスが許可されているか確認します。許可されているにもかかわらずブロックされる場合は、DOWNLOAD_DELAY の引き上げ、USER_AGENT の変更、AUTOTHROTTLE_ENABLED = True の設定を試してください。それでも解決しない場合は、対象サイトの利用規約を再確認し、スクレイピングが許可されていない可能性を検討します。
まとめ
ScrapyはPythonでWebデータ収集を行う際の有力な選択肢です。非同期処理による高速性、Middleware/Pipelineによる拡張性、そしてプロジェクト構成の統一性が特長で、小規模な収集から大規模なクローリングシステムまで対応できます。2026年1月リリースのバージョン2.14.1では Python 3.10〜3.13をサポートしており、活発にメンテナンスが続けられています。JavaScriptレンダリングが必要な場合はscrapy-playwrightプラグインで補完でき、クラウド実行が必要な場合はZyteのScrapy Cloudが利用可能です。