10月26日、Browser Useが「How to Extract Structured Data From Websites With an LLM (2026)」と題した記事を公開した。この記事では、LLMを活用してWebサイトから構造化データを抽出するための手法と、複数ツールの使い分けについて詳しく紹介されている。以下に、その内容を紹介する。
基本戦略:JSONスキーマを1つ書いて、あとはLLMに任せる
記事の核心はシンプルだ。抽出したいデータのJSONスキーマを1つ定義し、それをすべてのサイトで使い回す。静的なページであればHTMLをMarkdownに変換してLLMに渡し、スキーマを埋めさせる。ログインやJavaScriptの操作が必要なページにだけ、ブラウザエージェントを投入する。
この「必要なときだけブラウザを使う」という判断基準が、コストとシンプルさのバランスを保つ上で重要になる。
ツール比較:何を使えばいいか
記事では5つのアプローチを比較している。選定の判断軸は「ログイン・JS操作が必要か」「スキーマのバリデーションがあるか」「オープンソースか」の3点だ。
| ツール | 向いているケース | スキーマ検証 | OSS |
|---|---|---|---|
| Firecrawl | 既知URLの静的ページ、クロール | JSON Schema or プロンプト | コアのみAGPL-3.0 |
| Crawl4AI | セルフホスト、Pythonで任意モデル | PydanticモデルからJSON Schema(ベストエフォート) | Apache-2.0 |
| Browser Use | ログイン・フィルター・ページネーション・多段フォーム | スキーマ不一致で実行失敗(エラー明示) | エージェントライブラリはMIT |
| Stagehand | TypeScript/Python/GoでAIステップ付きブラウザ自動化 | Zod/Pydantic/Goの型で検証後に返却 | MIT |
| Fetch + Markdown + LLM | 既知URL・静的ページの最軽量構成 | モデルのstructured outputs依存 | 自前コード |
記事の推奨をまとめると:
- 既知URL・静的ページ:
Fetch + Markdown + LLMか Firecrawl JSONモード。ブラウザエージェントは不要でコスト増になるだけ。 - セルフホスト・任意モデル・Python: Crawl4AI
- TypeScript/Python/GoでAIステップ込みのブラウザ操作: Stagehand
- ログイン・フィルター・ページネーション・多段フォーム: Browser Use か Firecrawl の Interact
Browser Useのコード例:スキーマ不一致は「エラーで落とす」
記事で最も実践的な部分が、Browser Use Cloud APIを使ったコードサンプルだ。ポイントはスキーマに合わないレスポンスを「それらしいJSON」として返さず、実行ごと失敗させる設計にある。Could not produce output matching outputSchema というエラーで明示的に落ちるため、不正なデータが下流に流れ込むのを防げる。
# Python 3.10+
# pip install "browser-use-sdk>=3.12"
from browser_use_sdk.v4 import BrowserUse
from pydantic import BaseModel
class Product(BaseModel):
name: str
# required, may be null
price: float | None
currency: str | None
source_url: str
class Products(BaseModel):
products: list[Product]
# reads BROWSER_USE_API_KEY
client = BrowserUse()
run = client.runs.create(
"Open https://shop.example.com/laptops and go "
"through every results page. For each product "
"return its name, price, currency and product "
"URL as source_url. Use null for any value "
"the page does not show. Do not guess.",
output_schema=Products.model_json_schema(),
)
run = client.runs.wait_for_completion(run.id)
if run.status.value != "completed":
# flag the site, retry later
raise RuntimeError(run.error or run.status.value)
# validate again in your code
products = Products.model_validate(run.output)
price と currency は float | None と str | None で定義されており、ページに値がなければ null を返すよう明示している。「値がなければnullを返せ、推測するな(Do not guess)」というプロンプト指示との組み合わせが、データ品質を保つ上での実践的なパターンだ。
制限事項として、JSON Schema 2020-12形式、最大64KiB、ネスト64階層、値の総数約4,000件という上限がある。
また、定期実行ジョブには「スクリプト再利用」の仕組みが紹介されている。初回実行でテスト済みスクリプトをワークスペースに保存し、以降の実行では workspace_id を渡してサイトから最新データを取得する。サイトの構造が変わった場合はスクリプトを自動修復する(ドキュメント)。
信頼性チェックリスト:LLMの出力を「正しいデータ」にするために
記事では、抽出精度を高めるためのチェックリストも整理されている。特に実装上の落とし穴になりやすい点を抜粋する。
- 「有効なJSON ≠ 正しいデータ」:Pydantic や Zod でコード側からも必ずバリデーションする
- 欠損値は
null、推測させない:フィールドはnullable必須にして、ページに値がなければnullを返させる source_urlを全レコードに保持:根拠を追跡可能にする。重要フィールドはページからの短い引用も残す- robots.txtとレート制限を守る:ドメインごとにリクエストを制限し、robots.txt とサイトの利用規約に従う
- スポットチェックを実施:実行後にランダムサンプルをライブページと照合する。サイト変更後も同様
詳細はHow to Extract Structured Data From Websites With an LLM (2026)を参照していただきたい。




