Webスクレイピング比較:Scrapy vs Crawlee vs Playwright-Python でスクレイピングを実装する
オープンソースラボ編集部 ・ 2026年6月14日
Webスクレイピング比較:Scrapy vs Crawlee vs Playwright-Python でスクレイピングを実装する
ECサイトの価格監視・競合分析・データ収集・SEO調査などWebスクレイピングはデータエンジニアリングの重要なスキルです。Scrapy(Python製・フル機能フレームワーク・Spider中心)・Crawlee(TypeScript製・Apify発・ブラウザ自動化統合)・Playwright-Python(Microsoft製・ヘッドレスブラウザ・動的サイト対応)の3つが2026年のOSSスクレイピングツール主要選択肢です。
OSSスクレイピングを使う理由
- データ収集自動化: ECサイトの価格変動・ニュース・不動産情報を定期収集してDB化
- 競合分析: 競合他社のWebサイトを定期クロールして製品情報・価格・コンテンツを追跡
- SEO調査: クロールで内部リンク・メタデータ・構造化データを一括取得して分析
- コスト削減: ScrapingBee($49/月〜)などのスクレイピングSaaSを使わずに自前で構築
主要ツールの概要
Scrapy
2008年公開、Python製のOSSです。GitHubスター52k+。Pythonのデファクトスタンダードなフル機能Webスクレイピングフレームワークで、Spider(クローラー)・Pipeline(データ処理)・Middleware(リクエスト/レスポンス処理)・Feed Exporters(CSV/JSON/DB出力)が統合されています。
# Scrapy: ECサイトの価格監視Spider
import scrapy
from dataclasses import dataclass
from typing import Generator
@dataclass
class ProductItem:
name: str
price: float
sku: str
in_stock: bool
url: str
class EcPriceSpider(scrapy.Spider):
name = 'ec_price_monitor'
allowed_domains = ['shop.example.com']
start_urls = ['https://shop.example.com/products']
custom_settings = {
'DOWNLOAD_DELAY': 1.5, # 1.5秒間隔でリクエスト(サーバーに優しく)
'RANDOMIZE_DOWNLOAD_DELAY': True,
'CONCURRENT_REQUESTS': 4,
'ROBOTSTXT_OBEY': True, # robots.txtを尊重
'USER_AGENT': 'Mozilla/5.0 (compatible; PriceBot/1.0)',
'ITEM_PIPELINES': {
'ec_spider.pipelines.PostgresPipeline': 300,
},
'HTTPCACHE_ENABLED': True, # 開発時はキャッシュを有効化
}
def parse(self, response: scrapy.http.Response) -> Generator:
'''商品一覧ページをパース→各商品詳細ページをFollowする'''
for product_link in response.css('a.product-card::attr(href)').getall():
yield response.follow(product_link, callback=self.parse_product)
# ページネーション処理
next_page = response.css('a.pagination__next::attr(href)').get()
if next_page:
yield response.follow(next_page, callback=self.parse)
def parse_product(self, response: scrapy.http.Response) -> dict:
'''商品詳細ページから価格・在庫情報を抽出'''
price_text = response.css('[itemprop="price"]::attr(content)').get() or '0'
yield {
'name': response.css('h1.product-title::text').get('').strip(),
'price': float(price_text),
'sku': response.css('[itemprop="sku"]::text').get(''),
'in_stock': bool(response.css('[itemprop="availability"][href*="InStock"]')),
'url': response.url,
'scraped_at': response.headers.get('Date', b'').decode(),
}
# pipelines.py: ScrapyのItemをPostgreSQLに保存するPipeline
import psycopg2
from itemadapter import ItemAdapter
class PostgresPipeline:
def open_spider(self, spider):
self.conn = psycopg2.connect('postgresql://scraper:pass@localhost/prices')
self.cursor = self.conn.cursor()
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS product_prices (
id SERIAL PRIMARY KEY,
name TEXT, price NUMERIC(10,2), sku TEXT,
in_stock BOOLEAN, url TEXT, scraped_at TIMESTAMP DEFAULT NOW()
)
''')
def process_item(self, item, spider):
self.cursor.execute(
'INSERT INTO product_prices (name, price, sku, in_stock, url) VALUES (%s, %s, %s, %s, %s)',
(item['name'], item['price'], item['sku'], item['in_stock'], item['url']),
)
self.conn.commit()
return item
def close_spider(self, spider):
self.cursor.close()
self.conn.close()
Crawlee
2022年公開(Apify)、TypeScript製のOSSです。GitHubスター16k+。Apify(商用スクレイピングプラットフォーム)が作ったOSSのWebスクレイピングライブラリで、Cheerio(高速HTML解析)・Playwright・Puppeteerをシームレスに切り替えながら使えます。自動セッション管理・プロキシローテーション・キューによるURL管理が統合されています。
// Crawlee: TypeScript/Node.jsでのスクレイピング(Playwright統合)
import { PlaywrightCrawler, Dataset } from 'crawlee';
const crawler = new PlaywrightCrawler({
maxRequestsPerCrawl: 100,
launchContext: {
launchOptions: {
headless: true, // trueで非表示、falseでブラウザ表示(デバッグ用)
},
},
// プロキシ設定(IPバン回避)
proxyConfiguration: {
proxyUrls: [
'http://proxy1:8080',
'http://proxy2:8080',
],
},
async requestHandler({ page, request, enqueueLinks }) {
// JavaScriptレンダリング後の動的コンテンツを取得
await page.waitForSelector('.product-list', { timeout: 10000 });
const products = await page.$$eval('.product-card', (cards) =>
cards.map((card) => ({
name: card.querySelector('.product-name')?.textContent?.trim() ?? '',
price: parseFloat(card.querySelector('.price')?.dataset.price ?? '0'),
url: (card.querySelector('a') as HTMLAnchorElement)?.href ?? '',
}))
);
await Dataset.pushData(products); // JSONLファイルに自動保存
// 次のページへのリンクをキューに追加
await enqueueLinks({
selector: 'a.pagination-next',
label: 'LIST',
});
},
failedRequestHandler({ request, error }) {
console.error(`失敗: ${request.url} - ${error.message}`);
},
});
await crawler.run(['https://shop.example.com/products']);
// 結果はデフォルトで./storage/datasets/default/に保存
Playwright-Python
2020年公開(Microsoft)、Python製のOSSです。GitHubスター70k+(本体)。Microsoftが開発したクロスブラウザ(Chromium・Firefox・WebKit)自動化ライブラリで、JavaScript実行・Ajax待機・フォーム操作・スクリーンショット・PDFエクスポートができます。動的SPAサイトのスクレイピングに最適です。
# Playwright-Python: SPA・JavaScriptレンダリングサイトをスクレイピング
import asyncio
from playwright.async_api import async_playwright, Page
import json
async def scrape_with_intercept(url: str) -> list:
'''XHR/Fetch APIをインターセプトして内部APIのJSONレスポンスを取得'''
api_responses = []
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
context = await browser.new_context(
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
viewport={'width': 1280, 'height': 720},
)
page = await context.new_page()
# APIレスポンスをインターセプト(Ajax通信を傍受)
async def handle_response(response):
if '/api/products' in response.url and response.status == 200:
try:
data = await response.json()
api_responses.append(data)
except Exception:
pass
page.on('response', handle_response)
await page.goto(url, wait_until='networkidle')
# 「もっと見る」ボタンを繰り返しクリックして全商品を取得
while True:
more_btn = await page.query_selector('button.load-more:not([disabled])')
if not more_btn:
break
await more_btn.click()
await page.wait_for_timeout(1500)
await browser.close()
return api_responses
async def scrape_table_data(url: str) -> list:
'''テーブルデータを含むページをスクレイピング(React/Vue SPA対応)'''
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page: Page = await browser.new_page()
await page.goto(url, wait_until='domcontentloaded')
await page.wait_for_selector('table.data-table', timeout=10000)
rows = await page.$$eval('table.data-table tbody tr', lambda rows: [
[cell.innerText.strip() for cell in row.querySelectorAll('td')]
for row in rows
])
await browser.close()
return rows
if __name__ == '__main__':
results = asyncio.run(scrape_with_intercept('https://spa.example.com/products'))
print(json.dumps(results, ensure_ascii=False, indent=2))
機能比較表
| 比較項目 | Scrapy | Crawlee | Playwright-Python |
|---|---|---|---|
| JavaScript対応 | △(Splash連携) | ✅ | ✅ |
| 速度(静的HTML) | ✅ 最速 | 中 | △ |
| TypeScript対応 | ❌ | ✅ | ❌ |
| セッション管理 | ✅ | ✅ | 手動実装 |
| GitHub Stars | 52k+ | 16k+ | 70k+ |
スクレイピングツールはDevOpsカテゴリ/categories/devopsのデータパイプライン(dbt/Airbyte)と組み合わせてスクレイピング→PostgreSQL→dbt変換→BI分析のELTパイプラインを構築します。LLMツールカテゴリ/categories/llm-toolsのRAGフレームワーク(LlamaIndex/LangChain)とPlaywrightを組み合わせてWebページをスクレイピングしてベクトルDBに格納するナレッジベース自動更新パイプラインを実現します。
FAQ
Q. ScrapyでJavaScriptレンダリングが必要なSPAサイトをスクレイピングするには?
A. Scrapy-Playwright(scrapy-playwright)プラグインでScrapyにPlaywrightを統合してJSレンダリング対応にします。インストール: pip install scrapy-playwright playwright && playwright install chromium。Settings設定: DOWNLOAD_HANDLERS = {'https': 'scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler', 'http': 'scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler'}・TWISTED_REACTOR = 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'。Spider実装: yield scrapy.Request(url, meta={'playwright': True, 'playwright_include_page': True, 'playwright_page_methods': [PageMethod('wait_for_selector', '.products'), PageMethod('click', 'button.load-more')]})→Playwrightが動的コンテンツをレンダリング→通常のScrapyのparse関数でCSSセレクターを使って解析。
Q. Playwright-Pythonでボット検知を回避するステルス設定はどうすればいいですか?
A. Playwright-stealth(playwright-extra+stealth plugin)でヘッドレスブラウザの特徴を隠蔽します。インストール: pip install playwright-stealth。設定: from playwright_stealth import stealth_async→async with async_playwright() as p: browser = await p.chromium.launch(); page = await browser.new_page(); await stealth_async(page)。追加設定: await page.set_extra_http_headers({'Accept-Language': 'ja-JP,ja;q=0.9', 'Accept-Encoding': 'gzip, deflate, br'})・await context.add_cookies([{'name': 'session', 'value': 'xxx', 'domain': '.example.com', 'path': '/'}])でCookieを事前設定。プロキシ: await p.chromium.launch(proxy={'server': 'http://proxy:8080', 'username': 'user', 'password': 'pass'})で住宅用プロキシ(Residential Proxy)を経由してIPバンを回避。CAPTCHAバイパス: 2captchaやCapSolver APIと連携してCAPTCHAを自動解決→Playwrightで入力フォームに解答を自動入力。
Q. CrawleeとScrapyのどちらを選ぶべきですか?
A. Python・静的HTML中心・大規模クロールならScrapy、TypeScript/Node.js・動的SPAサイト・Playwright統合・チーム開発ならCrawleeが向いています。Scrapy優位: ①52kスターの最大コミュニティ→Middleware・Extensionが豊富②非同期HTTPリクエスト(Twisted)で静的サイトの大量クロールが最速③PipelineとItem Processorで複雑なデータ変換・検証をPythonで実装④Scrapy CloudやScrapydでのデプロイが容易。Crawlee優位: ①TypeScript製で型安全なコード③Playwright/Puppeteer/Cheerioをシームレスに切り替え→動的JSサイトも静的サイトも同一フレームワーク③自動プロキシローテーション・セッション管理→IPバン回避が組み込み済み④RequestQueueで大量URLのキュー管理が簡単⑤Dataset・KeyValueStoreで収集データを整理・保存するストレージ抽象化。
Q. ScrapyとPlaywrightを使ったスクレイピングは法的に問題ないですか?
A. スクレイピングの合法性はサイトのToS・robots.txt・目的・手法・データの使い方によって異なります。基本原則: ①ROBOTSTXT_OBEY = Trueでrobots.txtを尊重(Scrapyのデフォルト設定)②DOWNLOAD_DELAY = 2で適切な間隔でリクエスト(サーバーに負荷をかけない)③ToS(利用規約)を読んでスクレイピング禁止条項がないか確認④個人情報(名前・メールアドレス)の収集・保存はGDPR/個人情報保護法に注意⑤著作権のあるコンテンツをそのまま再配布することは著作権侵害の可能性。合法的なユースケース: 公開価格情報の収集・学術研究・自社サイトの監視・SEO分析。避けるべきこと: ログイン認証をバイパス・CAPTCHA解析・Rate Limitの意図的回避・競合を不正に妨害するための大量リクエスト。
まとめ
| ユースケース | 推奨ツール |
|---|---|
| Python・静的HTML・大規模クロール | Scrapy |
| TypeScript・SPA・Playwright統合 | Crawlee |
| 動的JS・API傍受・ブラウザ自動化 | Playwright-Python |