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全コンポーネント間のデータフローを制御する司令塔通常は触らない
SchedulerEngineから受け取ったリクエストをキューに格納し、順序制御する設定で調整
DownloaderHTTPリクエストを実行し、レスポンスをEngineに返すMiddlewareで拡張
Spiderレスポンスを解析し、Item(抽出データ)や追加リクエストを生成する主に開発
Item PipelineSpiderが生成したItemを受け取り、バリデーション・変換・保存を行う必要に応じて実装

処理の流れを簡潔にまとめると、次のようになります。

  1. SpiderがURLを定義 → Engineがリクエスト生成
  2. Schedulerがキューイング → DownloaderがHTTPアクセス
  3. レスポンスをSpiderに渡す → Spiderがデータ抽出
  4. 抽出したItemをPipelineが加工・保存
  5. 追加の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つのツールは、それぞれ得意分野が異なります。

観点ScrapyBeautifulSoupSelenium
種別クローリングフレームワーク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_DELAYAUTOTHROTTLE を適切に設定し、サーバーに過度な負荷をかけない
  • 利用規約の確認: 対象サイトの利用規約でスクレイピングが禁止されていないか事前に確認する
  • 個人情報の取り扱い: 収集したデータに個人情報が含まれる場合は、個人情報保護法や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が利用可能です。