Firecrawlとは。料金と使い方、競合サイトを丸ごとデータ化する方法

競合30社のサービスページを全部集めてくれ、と頼まれたことがある。手作業なら、1社ずつ開いてコピーして、表に貼って、を数日かけて繰り返す仕事だ。Firecrawlを使ったら、その日の午後には終わっていた。
Webサイトのデータをまとめて欲しくなる場面は、経営の現場に意外と多い。競合の価格やサービス内容の一覧化。旧サイトから新サイトへの記事移行。自社の問い合わせ対応をAIに任せるための、社内マニュアルのデータ化。どれも「人間が1ページずつ開いてコピーする」とキリがない。Firecrawlは、この「1ページずつ」を丸ごと肩代わりするツールだ。
私はAIエージェント組織を自分の業務で毎日動かしている。その中でWebからデータを集める作業は日常的に発生する。この記事は、実際にFirecrawlを触った記録をもとに、何ができて、いくらかかって、自社に入れる価値があるかを判断できるところまで書く。コードも載せるので、手を動かす人はそのまま試せる。
Firecrawlとは。Webサイトを丸ごとデータ化するツール
一言でいうと、任意のWebサイトを開いて、中身をAIが読みやすい形(Markdown)に整えて返してくれるツールだ。OSSとして公開されていて、自前サーバーで無料運用もできるし、登録するだけで使えるSaaS版もある(Firecrawl公式)。
技術的なポイントは、JavaScriptで描画される最近のサイトにも対応していること。昔ながらのデータ収集ツールは、ブラウザで見たときの画面と、プログラムが取得する中身が食い違うサイトでよく壊れた。Firecrawlはブラウザで実際に描画した後の状態を取りに行くので、人間が見ている画面とほぼ同じ情報が取れる。
できることを整理すると、こうなる。
- URLのリストや sitemap.xml から、サイトの全ページを一括取得
- ページの中の必要な部分だけを抜き出す
- ログインや動的な読み込みが必要なページも、描画後の中身を取得
- 取得結果を、そのままAI(LLM)に渡せる形で出力
最後の「そのままAIに渡せる形」が、他のツールとの一番の違いになる。従来はデータを取った後に、AIが読める形へ整える前処理がひと仕事だった。そこがほぼ要らなくなる。
Firecrawlの料金。無料枠500ページから
先に料金の全体像を出す。以下は2026年3月時点の公式プランだ。
プラン | 月額 | クレジット/月 | レート制限 |
|---|---|---|---|
Free | $0 | 500 | 10リクエスト/分 |
Hobby | $16 | 3,000 | 20リクエスト/分 |
Standard | $83 | 100,000 | 100リクエスト/分 |
Growth | 要問合せ | カスタム | カスタム |
課金の単位は「クレジット」で、1ページ取得するごとに1クレジット消費する。無料プランの500クレジットは、500ページ分だ。
まず試すだけなら無料枠で十分足りる。1ページの取得結果を見れば、自社の用途に合うかどうかはすぐ判断がつく。個人プロジェクトや小規模な業務ならHobby($16)で足りることが多い。月3,000ページあれば、中規模のサイトを数回まるごとクロールできる。継続的に大量のページを集める運用に育ったら、Standard以上を検討する流れになる。
料金を気にせず、データを外に出したくない事情がある場合は、OSS版を自前サーバーで動かす選択肢もある。この場合クレジットの概念もレート制限もない。ただし動かすにはブラウザ描画用の環境(Chromium)が必要で、メモリは最低4GBほど見ておく。運用の手間とサーバー代を、SaaSの月額と天秤にかける判断になる。
実際に使ってみる。5分で動く
ここからは手を動かす人向け。経営判断だけ知りたい方は「自社でやるか、外部に頼むか」まで飛ばして構わない。
Python SDKを入れて、APIキーを渡すだけで始まる。
pip install firecrawl-py
APIキーはFirecrawlのダッシュボードで取得する。
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も併せて取る。
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 は地味だが効く。これを入れないと、全ページにヘッダーやフッター、サイドバーが重複して混ざる。AIに渡すデータが無駄にふくらむ原因になるので、最初から入れておくのがいい。
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)}ページ")
AIで構造化データを抜き出す(extract)
Firecrawl v1で追加されたExtract機能を使うと、ページから必要な項目だけを構造化して取り出せる。取りたい形をスキーマで定義して渡す。
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': '会社の設立年、従業員数、所在地を抽出してください'
}
}
)
競合30社の会社概要から、設立年と従業員数と所在地だけを一覧化する。そういう仕事が、これで一気に片づく。
自社でやるか、外部に頼むか
ここが経営判断の分かれ目になる。Firecrawlは登録すれば触れるが、「触れる」と「業務として回る」の間には距離がある。判断軸を3つに絞る。
社内にPythonを書ける人がいて、しかもその人の時間が空いているか。ここが一番大きい。上のコードを見て「これなら書ける」と思う人が社内にいるなら、無料枠で試して、そのまま内製に進むのが一番安い。逆に、コードを書ける人が本業で手一杯なら、片手間の内製は途中で止まる。止まった自動化は誰も直さないまま放置される。
一度きりか、繰り返すか。競合を一回だけ調べたいなら、内製でも外注でも大差ない。むしろ外注のほうが早い。毎週・毎月データを取り続けて、AIに食わせて、業務に組み込む。そこまで育てるなら、誰かが継続的に面倒を見る前提の設計が要る。この設計を最初に間違えると、後で作り直しになる。
取るデータに個人情報や機微な情報が混ざるか。顧客データや社内の非公開情報を扱うなら、データをどこに置くか、誰がアクセスできるかの設計が先に必要になる。ここは「動けばいい」で進めると事故る領域だ。SaaS版に外部送信していいのか、OSS版を自社内で閉じて動かすべきか、の判断が絡む。
ざっくり言うと、社内に手の空いたエンジニアがいる一度きりの調査なら内製。継続運用や、機微なデータや、業務への組み込みが絡むなら、設計だけでも外部の目を入れたほうが結局は安い。
導入の費用と期間の目安
金額と期間の感覚を持っておくと、社内で話が進めやすい。
ツール自体の費用は、上の料金表のとおり。試すだけなら無料、小規模運用でHobbyの$16、本格運用でStandardの$83が目安になる。ここは大きな金額ではない。効いてくるのは、動かす人の時間のほうだ。
期間の目安は用途で変わる。1ページ試して手応えを確かめるだけなら、その日のうち。競合サイトを丸ごと取ってデータにするような一回きりの調査なら、数時間から1日。毎週データを取り続けて業務に組み込む仕組みまで作るなら、設計とテストを含めて数日から数週間を見ておく。
注意したいのは、一番時間を食うのが「Firecrawlを動かす部分」ではないことだ。取ったデータをどう使うか、どこに貯めるか、誰がメンテナンスするか。この周辺設計のほうが手間になる。ツールが安く動くからといって、プロジェクト全体が安く済むわけではない。この見誤りが、次の失敗パターンにつながる。
よくある失敗パターン
私が実際にぶつかった、あるいは踏みかけたものを挙げる。
無料枠を初日で使い切る。limit を設定せずにクロールを走らせると、リンクをたどれるだけたどってしまう。テスト段階で500クレジットが一瞬で溶ける。最初は limit: 10 で動作確認して、様子を見ながら増やすのが無難だ。
取れると思ったページが取れない。Firecrawlはデフォルトで robots.txt に従う。相手サイトが robots.txt でブロックしているパスは取得できない。自社サイトのデータ移行で使うなら、一時的に自社の robots.txt を調整する必要が出ることもある。
レート制限で詰まる。無料プランは1分あたり10リクエストの上限がある。大量のページを取るときは、scrape_url をループで回すより、crawl_url で一括取得したほうがいい。クロール機能は内部でレート制限をうまく管理してくれる。
法的な確認を飛ばす。ここが一番痛い失敗になりうる。robots.txt を無視する設定にしたり、商用サイトを利用規約を確認せずにスクレイピングしたりすると、法的リスクを負う。競合分析でよそのサイトを取る前に、そのサイトの利用規約を必ず確認する。この確認を「たぶん大丈夫」で飛ばさない。
作ったが誰も使わない。技術的に動くものを作っても、業務のどこで誰がその出力を使うかが決まっていないと、そのまま放置される。ツールを動かす前に、取ったデータを何の判断に使うのかを先に決めておく。
Scrapy・Playwrightとの使い分け
Firecrawlが常に最適というわけではない。用途で使い分ける。
要件 | 向いているツール |
|---|---|
細かいパーサーのカスタマイズが必要 | Scrapy |
ブラウザ操作(ログイン、クリック等)が必要 | Playwright |
サイト全体をMarkdownで一括取得したい | Firecrawl |
AIに渡す構造化データが欲しい | Firecrawl(Extract) |
無料で大量ページを取得したい | Scrapy(自己管理) |
Firecrawlの強みは「とにかく早く、きれいなデータが欲しい」場面にある。パーサーを書かなくていいぶん、試作や検証のスピードが上がる。本番のデータパイプラインに組み込むなら、コストとレート制限を見て判断する。
これを自社に入れるとどうなるか
冒頭の話に戻る。競合30社のサービスページを集める仕事が、数日から数時間になった。この「時間の縮み方」が、Firecrawlが自社にもたらす一番わかりやすい変化だ。
具体的には、こういう場面で効く。
- 競合の価格やサービス内容を定期的に一覧化して、自社の立ち位置を把握する
- 旧サイトから新サイトへ、数百ページの記事をまとめて移す
- 社内マニュアルや過去資料をデータ化して、問い合わせ対応AIの土台にする
どれも「人手でやると数日、放置すると誰もやらない」タイプの仕事だ。そこを仕組みで片づけると、担当者はもっと判断が要る仕事に時間を回せる。
ただし、ここまで読んでわかるとおり、ツールが動くことと業務が回ることは別だ。何のデータを、どう使い、誰が維持するのか。この設計を外すと、せっかく作った仕組みが止まる。
自社のどの業務にこれが効きそうか、内製と外注どちらで進めるのが現実的か。そのあたりを一度整理したいなら、無料の壁打ち相談で話を聞かせてほしい(f2t.jp/#f2t-cta)。売り込みではなく、まず「そもそも自動化すべき業務か」から一緒に見極める。今のやり方のまま人手で続けるほうが安い、という結論になることもある。
この記事を書いた人
Tomohiko Akiyama(F2T)
AIエージェント組織を自分の業務で毎日動かしている実装者。このブログの記事は、すべてその実作業の記録から生まれています。
この記事のテーマに合うサービス:業務フロー自動化
スプレッドシート・メール・Slackの往復を、自動化で終わらせる



