Webサイトのデータをまとめて取得したい場面は意外と多い。競合分析、社内ドキュメントの移行、ナレッジベースの構築。BeautifulSoupやScrapyで地道にパーサーを書くのが王道だが、JavaScript描画のSPAが増えた今、従来のHTTPリクエスト+パースだけでは歯が立たないケースが出てきた。
Firecrawlはこの問題を正面から解決するツールだ。ブラウザレンダリング後のHTMLを取得し、Markdownに変換して返してくれる。LLMに食わせるデータの前処理がほぼ不要になる点が、他のスクレイピングツールとの最大の違いになる。
セットアップ: 5分で動く環境を作る
まずPython SDKをインストールする。
pip install firecrawl-py
APIキーはFirecrawlのダッシュボードで取得できる。無料プランでも月500クレジット使える。1ページのスクレイプで1クレジット消費するので、500ページ分だ。
from firecrawl import FirecrawlApp
app = FirecrawlApp(api_key='fc-xxxxxxxxxxxxxxxx')
環境変数で管理する場合は FIRECRAWL_API_KEY を設定しておけば、引数なしで初期化できる。
export FIRECRAWL_API_KEY=fc-xxxxxxxxxxxxxxxx
# 環境変数から自動で読み込む
app = FirecrawlApp()
単一ページの取得: scrape
まず1ページだけ取得してみる。scrape_urlメソッドにURLを渡すだけでいい。
result = app.scrape_url(
'https://example.com/pricing',
params={'formats': ['markdown', 'html']}
)
print(result['markdown'][:500])
返り値はこんな構造になる。
{
'markdown': '# Pricing\n\nOur plans start at...',
'html': '<h1>Pricing</h1><p>Our plans start at...</p>',
'metadata': {
'title': 'Pricing - Example',
'description': 'Our pricing plans...',
'language': 'en',
'sourceURL': 'https://example.com/pricing',
'statusCode': 200
}
}
formatsパラメータで取得形式を指定できる。markdownだけで十分なケースがほとんどだが、DOM構造が必要ならhtmlも併せて取る。
SPAやログイン後ページの対処
JavaScriptで描画されるページも、デフォルトでブラウザレンダリングされるので特別な設定は不要。ただし、ログインが必要なページはheadersでCookieを渡す必要がある。
result = app.scrape_url(
'https://app.example.com/dashboard',
params={
'formats': ['markdown'],
'headers': {
'Cookie': 'session_id=abc123def456'
}
}
)
サイト全体のクロール: crawl
本題のサイト全体取得。crawl_urlを使う。
crawl_result = app.crawl_url(
'https://docs.example.com',
params={
'limit': 100,
'scrapeOptions': {
'formats': ['markdown']
}
},
poll_interval=5
)
print(f"取得ページ数: {len(crawl_result['data'])}")
for page in crawl_result['data'][:3]:
print(f" - {page['metadata']['sourceURL']}")
出力例:
取得ページ数: 87
- https://docs.example.com/
- https://docs.example.com/getting-started
- https://docs.example.com/api-reference
クロールの挙動を制御するパラメータ
crawl_result = app.crawl_url(
'https://example.com',
params={
'limit': 200,
'maxDepth': 3,
'includePaths': ['/blog/*', '/docs/*'],
'excludePaths': ['/admin/*', '/tag/*'],
'allowBackwardLinks': False,
'scrapeOptions': {
'formats': ['markdown'],
'onlyMainContent': True
}
}
)
onlyMainContent: Trueは地味だが重要。これを入れないと、全ページにヘッダー・フッター・サイドバーが重複して含まれる。LLMに渡すデータが無駄に膨らむ原因になる。
非同期クロール: 大規模サイト向け
100ページを超えるサイトでは、同期的に待つとタイムアウトのリスクがある。非同期APIを使うほうが安全だ。
crawl_job = app.async_crawl_url(
'https://large-site.example.com',
params={'limit': 500}
)
job_id = crawl_job['id']
print(f"ジョブID: {job_id}")
import time
while True:
status = app.check_crawl_status(job_id)
completed = status.get('completed', 0)
total = status.get('total', 0)
print(f"進捗: {completed}/{total}")
if status['status'] == 'completed':
break
time.sleep(10)
pages = status['data']
print(f"取得完了: {len(pages)}ページ")
LLMで構造化データを抽出する: extract
Firecrawl v1で追加されたExtract機能を使うと、ページからLLMで構造化データを直接抽出できる。Pydanticのスキーマを定義して渡す。
from pydantic import BaseModel
from typing import List, Optional
class Product(BaseModel):
name: str
price: Optional[str]
description: str
features: List[str]
result = app.scrape_url(
'https://example.com/product/widget-pro',
params={
'formats': ['extract'],
'extract': {
'schema': Product.model_json_schema()
}
}
)
product = result['extract']
print(f"商品名: {product['name']}")
print(f"価格: {product['price']}")
print(f"特徴: {', '.join(product['features'])}")
出力例:
商品名: Widget Pro
価格: $49/month
特徴: リアルタイム同期, APIアクセス, カスタムダッシュボード
スキーマを渡さずにプロンプトだけで指示することもできる。
result = app.scrape_url(
'https://example.com/about',
params={
'formats': ['extract'],
'extract': {
'prompt': '会社の設立年、従業員数、所在地を抽出してください'
}
}
)
実際にやってみて気づいたこと
クレジット消費に注意
無料プランの500クレジットは、テスト段階で使い切りやすい。limitパラメータを設定せずにクロールすると、リンクをたどれるだけたどってしまう。最初はlimit: 10で動作確認し、徐々に増やすのが無難だ。
robots.txtは尊重される
Firecrawlはデフォルトでrobots.txtに従う。クロール対象サイトのrobots.txtでDisallowされているパスは取得できない。自社サイトのデータ移行で使う場合は、一時的にrobots.txtを調整する必要があるかもしれない。
レート制限
無料プランでは1分あたり10リクエストの制限がある。大量のページを取得する場合は、crawl_urlで一括取得するほうが、scrape_urlをループで回すより効率的だ。クロール機能は内部でレート制限を管理してくれる。
セルフホスト
APIキーの管理やデータの外部送信が気になる場合は、セルフホストもできる。
git clone https://github.com/mendableai/firecrawl.git
cd firecrawl
docker compose up -d
セルフホスト版はAPIキー不要で、レート制限もない。ただし、ブラウザレンダリング用のChromiumが必要になるため、メモリは最低4GB確保しておく。
料金体系(2026年3月時点)
| プラン | 月額 | クレジット/月 | レート制限 |
|---|---|---|---|
| Free | $0 | 500 | 10req/min |
| Hobby | $16 | 3,000 | 20req/min |
| Standard | $83 | 100,000 | 100req/min |
| Growth | 要問合せ | カスタム | カスタム |
個人プロジェクトや小規模な用途ならHobbyで十分。月3,000ページあれば、中規模サイトを数回クロールできる。
Scrapy・Playwrightとの使い分け
| 要件 | 推奨ツール |
|---|---|
| 細かいパーサーのカスタマイズが必要 | Scrapy |
| ブラウザ操作(ログイン、クリック等)が必要 | Playwright |
| サイト全体をMarkdownで一括取得 | Firecrawl |
| LLMに渡す構造化データが欲しい | Firecrawl(Extract) |
| 無料で大量ページを取得したい | Scrapy(セルフ管理) |
Firecrawlの強みは「とにかく早くきれいなデータが欲しい」場面にある。パーサーを書かなくていいのは、プロトタイプやPoCのスピードを上げる上で大きい。本番のパイプラインに組み込むなら、コストとレート制限を考慮して判断するのがいい。
まとめ
Firecrawlは「Webスクレイピングの面倒な部分を全部やってくれるAPI」と考えるとわかりやすい。JSレンダリング、Markdown変換、構造化抽出の3つが1つのAPIで完結する。
手を動かすなら、まず無料プランでscrape_urlを試すところから始めるのがいい。1ページの取得結果を見れば、自分の用途に合うかどうかすぐ判断できる。




