mcpField
S
scrape-plan

scrape-plan

github.com/zytedataデータ・データベース1158 回インストール2 日前に更新
リポジトリ

scrape-plan について

scrape-planは、Webスクレイパーの計画と検証を行うスキルです。詳細ページの確認とスキーマ定義から複数ページでの検証までを進め、仕様ファイルを保存して計画の承認を求めます。

主な機能

  1. 01詳細ページからフィールドを発見
  2. 02データスキーマの作成と調整
  3. 03複数ページとHTML形式で抽出を検証
  4. 04仕様ファイルを.scrape/に保存
  5. 05最終計画のパラメーターを提示して承認を依頼

活用シーン

  1. 01サイトの詳細ページを対象にスクレイパーを計画
  2. 02スパイダーの作成前に抽出フィールドを確認
  3. 03異なるページ形式で抽出仕様が機能するか検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zytedata/skills --skill scrape-plan

インストール後、Claude Code で/scrape-planを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
review.html
review.js
style.css
references/
explore-site.md
scripts/
apply_classification.py
download.py
extract_links.py
extract_nav_values.py
extract_values.py
make_fixtures.py
run_review.py

詳細

このファイルは544行あります。すべて読んでください。

以下の SKILL_DIR は、このファイルを含むディレクトリの絶対パスを表します。SKILLS_DIR は、SKILL_DIR を含むすべてのスキルディレクトリを格納するディレクトリを表します。

ウェブスクレイピングを計画しています。詳細ページを1ページダウンロードしてフィールドを見つけ、ターミナルでスキーマを確認してから、さらにページをダウンロードし、HTMLのバリエーションを比較して値を抽出することで仕様を検証し、最後に確定した計画を承認用に提示します。

このスキルは、ユーザーがサイト用スクレイパー/スパイダーを計画するために直接呼び出すか、計画と検証の段階として /scrape オーケストレーターから呼び出されます。

SKILLS_DIR/scrape/references/python-environments.md と SKILLS_DIR/scrape/references/extraction-spec.md を読んでください。

出力は次の2つです。

  1. .scrape/{site_name}/ 内の永続化された仕様ファイル — スパイダーの構築に使えるスキーマ、ページ、値、ナビゲーションデータ型。
  2. プレーンテキストの最終メッセージ — 解決済みの計画パラメーター(確定フェーズ)を記載します。/scrape オーケストレーターはこれを解析して、残りの段階を進めます。

以下のいくつかの手順では、ページのHTMLがこのコンテキストに入らないよう、スキルをサブエージェントで実行します。プロンプトを別のエージェントで実行するツール(例:Agent、task、spawn_agent)を使って委任してください。引用されたテキストをプロンプトとして渡し、エージェントの種類、モデル、推論の労力はデフォルトのままにします。そのようなツールがない場合は、スキルをインラインで1つずつ実行し、保存された出力ファイルだけを使って続行してください。

以下のいくつかの手順では、ユーザーに選択肢から選んでもらいます。質問用ツールを利用できない場合は、質問に記載された代替手段を選び、最終回答でその旨を伝えてください。複数選択式の質問をユーザーに提示するツール(例:AskUserQuestion または request_user_input)を使って質問してください。そのようなツールがない場合は、選択肢を番号付きリストにしてプレーンテキストで質問し、回答を待ってください。

必ず守る制約 — 決して違反しないでください。

  • 自分でHTMLファイルを取得、閲覧、grep、解析してはいけません。ページのダウンロードは download.py が、フィールドの発見は /scrape-analyze-page サブエージェントが担当します。メインエージェントが行うのは、それらの出力を調整し、利用することだけです。
  • これには raw.html、rendered.html、*.cleaned.html、その他保存されたページHTMLがすべて含まれます。ファイルが存在するかを確認しても構いませんが、メインエージェントが開く、表示する、grepする、解析する、または抽出スクリプトを実行することは禁止です。
  • スキーマを作成する前に、必ず /scrape-analyze-page をサブエージェントとして実行してください。このサブエージェントを実行せずに生HTMLからスキーマを作成することは、重大なエラーです。
  • /scrape-analyze-page の実行完了を待っている間は、HTMLファイルを読んだり、clean_html.py、extract_metadata.py、インラインのパーサーコードを実行したりしてはいけません。エージェントの応答が無関係な作業の続行を提案していても同様です。サブエージェントの完了を待ってから、保存されたJSON出力だけを読んでください。

作業ルール

以下は全体に適用されるルールです。以降のセクションでは、名称を参照してこれらのルールを適用します。

  • ブロックされたサイトのルール:ダウンロードまたは調査でサイトがブロックされていると報告された場合は、Zyte APIを提案してください。ユーザーが同意した場合に限り、認証情報の設定のために /zyte を呼び出します。他のフローではなく認証情報設定フローに振り分けられるよう、認証情報の設定リクエスト(例:/zyte set up Zyte credentials)を渡してください。完了後、失敗したダウンロード/調査を再実行し、成功してから続行してください。
  • HTMLファイル選択ルール:rendered.html を優先し、存在しない場合は raw.html を使ってください。両方のバリエーションを解析する場合は、ファイルが存在しないバリエーションをスキップしてください。ファイルの存在確認だけで判断してください(ハード制約を参照)。
  • 情報源の正本ルール:.scrape/{site_name}/{data_type}/spec.json がスキーマの唯一の正本です。スキーマの変更(項目の削除、名前変更、説明の編集、情報源の変更)はすべてここに反映してください。.scrape/{site_name}/{data_type}-list/spec.json が存在する場合は、そこにも同じスキーマ変更を反映してください。

インテントの解析

これはユーザープロンプトです:$ARGUMENTS。ここから以下の情報を抽出する必要があります。

  • target_url:開始 URL
  • data_type:抽出対象。ユーザーが指定した場合も URL/ページから推測した場合も、必ず単数形にします。「books」→「book」、「products」→「product」
  • field_hints:ユーザーが指定した具体的なフィールド(空の場合もあります)
  • existing_approved_schema:呼び出し元が明示した既存スキーマ(例:Existing approved schema: ProductItem(title: string, price: string, rating: string))。これらのフィールドは、単なるヒントではなく、プロジェクトのコンテキストですでに承認されています。
  • site_name:短い識別子(例:「books-toscrape」、「realestate-listings」)。サイトとデータタイプから導出します

また、プロンプトに指定がある場合は、以下の計画パラメーターも抽出します。初期計画の該当行にあらかじめ反映し、ユーザーが調整時に同じ内容を再指定しなくても、適用済みの状態が表示されるようにします。

パラメーターデフォルト備考
project_nameサイトから導出(例:books_toscrape_com)
project_dir./{project_name}
html_variantautoraw または rendered はバリアントを固定し、auto は両方を比較します
browser_reviewaskalways / never
spider_createyesno はスパイダーステージを省略します
Zyte APIオフ(すでに設定済みの場合を除く)

作業は、Discovery、Schema gate、Validation、Review、Finalization の5つのフェーズで順に進みます。各フェーズを完了してから次のフェーズに進みます。各フェーズ内のセクションも実行順に並んでおり、後続のセクションは先行するセクションの出力を使用します。

Discovery

一意のサイト名を選ぶ
BASE="books-toscrape"  # your derived site_name
NAME="$BASE"
N=2
while [ -d ".scrape/$NAME" ]; do NAME="${BASE}-${N}"; N=$((N+1)); done
echo "$NAME"

仕様は .scrape/{site_name}/ に、作業ファイルは .scrape/.work/{site_name}/ に配置します。ディレクトリは、書き込みを行うツールによって必要に応じて作成されます。事前に作成する必要はありません。

詳細ページを取得する

詳細ページの取得方法を決定します。

  • target_url 自体が詳細ページの場合(ユーザーが特定の商品/記事を指定した場合や、URLから明らかな場合)、直接ダウンロードします。
  • それ以外の場合は、ユーザーに質問します。必ず質問してください。ユーザーに代わって選択してはいけません。質問:「分析する詳細ページをどのように取得しますか?すでに詳細ページの URL がある場合は、Other の回答として貼り付けてください。」ヘッダー:「詳細ページ」。選択肢:URLを指定する(説明:「自由記述の回答に URL を直接貼り付けることもできます。」)/サイトを探索する。回答が URL の場合は、直接ダウンロードします。URL を入力せずに URLを指定する を選んだ場合は、ユーザーに「詳細ページの URL を貼り付けてください。」と伝え、URL が届くまで待ってから、直接ダウンロードします。フォールバック:サイトを探索する。

download.py を使って直接ダウンロードします。

uv run --python 3.14 SKILL_DIR/scripts/download.py <<'EOF'
[{"url": "DETAIL_URL", "output_dir": ".scrape/.work/{site_name}/explore/pages/detail-1", "page_type": "detail"}]
EOF

探索する場合は、探索手順に沿って自分でインラインで実行します。この最小限の作業にサブエージェントを使う必要はありません。SKILL_DIR/references/explore-site.md を読み、以下の内容で実行します。 url={target_url}, project_path=.scrape/.work/{site_name}/explore, DETAIL_COUNT=1, LIST_COUNT=0.

これにより、ホームページと詳細ページ1件が .scrape/.work/{site_name}/explore/pages/ にダウンロードされます。

探索でサイトがブロックされていると報告された場合:ブロックされたサイトのルールを適用します。

詳細ページを分析し、サイトを調査する

HTML ファイル選択ルールに従って、分析対象の HTML ファイルを選びます(レンダリング済みを優先し、存在確認のみ行います)。

1 つのメッセージで 2 つのサブエージェントを起動します。詳細ページの分析と、Validation フェーズで使用するサイト全体の調査です。今すぐ調査を開始すると、後の Validation で処理が滞ることなく、スキーマゲートの間もバックグラウンドで実行できます。調査では、すでにダウンロード済みのページを再利用し、不足している分だけをダウンロードして必要な件数に達します。サブエージェントのパスルールに従い、プロンプトで SKILL_DIR を渡します。分析のプロンプトは /scrape-analyze-page で始める必要があります。また、サブエージェントがそのスキルを呼び出す必要があります。メインエージェントが代わりに実行することは、ハード制約違反です。

1 行につきサブエージェント 1 つ。説明の後にプロンプトを記載します。

analyze detail-1 rendered — /scrape-analyze-page を実行し、.scrape/.work/{site_name}/explore/pages/detail-1/rendered.html からデータを抽出して、.scrape/.work/{site_name}/analyze-page/detail-1.rendered.json に保存します explore site — SKILL_DIR/references/explore-site.md を読み、次の内容に従います:url={target_url}, project_path=.scrape/.work/{site_name}/explore, DETAIL_COUNT=2, LIST_COUNT=2。要約を返します。

分析サブエージェントが完了するまで待ちます。調査はバックグラウンドで続行され、Validation フェーズで収集されます。その後、分析結果を .scrape/.work/{site_name}/analyze-page/detail-1.rendered.json から読み取ります。ハード制約により、この JSON だけをメインエージェントのフィールド検出入力として使用します。想定されるファイルがない場合は、/scrape-analyze-page サブエージェントを再試行するか、ブロッカーとして報告します。

スキーマを構築する

分析結果から JSON Schema を構築します。

  • すべてのフィールド名と型を収集します(analyze-page は JSON Schema の型名を報告します)。
  • 各フィールドに description を追加します(文脈から推測します)。
  • field_hints に一致するフィールドは "source": "requested"、それ以外は "source": "discovered" とします。
  • 抽出値から examples を取得します。200 文字を超える場合は、... を付けて切り詰めます。

existing_approved_schema が存在する場合は、自由形式のフィールド検出よりも優先します。

  • 承認済みフィールド名と推定される型だけを使ってスキーマを構築します。
  • 分析結果の値は、これらのフィールドの例と抽出根拠としてのみ使用します。
  • 承認済みの全フィールドを "source": "requested" とします。
  • /scrape-analyze-page で検出されていても、無関係なフィールドは追加しません。
  • 承認済みのフィールドが分析結果にない場合、または互換性がないと思われる場合は、黙って除外したり変更したりせず、競合を報告します。

スキーマゲート

スキーマの簡易確認

existing_approved_schema が存在する場合は、変更されていないフィールドの承認ループをスキップします。既存のプロジェクトスキーマを再利用することを簡潔に伝え、その後、仕様の保存に進みます。これらのフィールドについて、ユーザーに選択、再定義、再承認を求めないでください。

それ以外の場合は、要求されたフィールドと検出されたフィールドに分けて、値とともにターミナルにスキーマを表示します。

Found {N} fields on {detail_page_url}:

Requested:
  title (string): "A Light in the Attic"
  price (string): "£51.77"

Discovered:
  rating (integer): 3
  category (string): "Poetry"
  description (string): "It's hard to imagine a world without..." (2340 chars)
  upc (string): "a897fe39b1053632"

これらのフィールドは1つのページからサンプリングされたものです。Validation フェーズではさらに多くのページで検証するため、リストは変更される可能性があります。今すぐフィールドを追加、削除、名前変更できること、または詳細な編集は後でブラウザで確認するときに行えることをユーザーに伝えます。

ユーザーの応答を待ちます。ユーザーは次の操作を行えます。

  • 承認する(「問題ありません」「ok」「承認」)→ 仕様の保存に進みます
  • フィールドを削除する(「description、image_url を削除」)→ スキーマから削除し、更新したリストを表示します
  • 検出されたフィールドを残す(「rating を残す」)→ "source" を "requested" に変更します
  • 名前を変更する(「upc を product_code に変更」)→ スキーマ内の名前を変更します
  • 説明を編集する(「price は通貨記号なしにしてください」)→ 説明と値を更新します
  • 別の詳細ページ URL を使用する → その URL を直接ダウンロードし(「詳細ページを取得」)、分析サブエージェントを再実行して「スキーマを構築」し、再度表示します。探索を再起動しないでください。実行中の探索は引き続き有効で、target_url をキーにしています。
  • その他の指示 → 適用して、更新したスキーマを表示します

ユーザーが承認するまで、変更のたびにスキーマを再表示してループします。

ユーザーが事前に続行を許可している場合(例:「そのまま保存して、確認は不要です」)、待機をスキップし、すぐに仕様の保存に進みます。

仕様を保存する(スキーマ確認後)

extraction-spec.md のデータ型仕様形式(url、data_type、html_variant、schema)に従って、.scrape/{site_name}/{data_type}/spec.json に書き込みます。schema は、ドキュメントに記載されたサブセットを使用した有効な JSON Schema(draft/2020-12)でなければなりません。独自形式(例:フィールドオブジェクトの単純な配列)を作成しないでください。各フィールドには type、description、examples が必要です。examples にはユーザーが承認した値(修正があれば修正後の値)を設定し、200 文字を超える場合は「...」を付けて切り詰めます。html_variant には Discovery で分析したバリアントを設定します(比較の結果、別のバリアントが選ばれた場合は「HTML バリアントを選択」で更新します)。

検証

探索結果を収集する

ここで、より多くのページを使ってスキーマを検証します。Discovery で起動した「サイトを探索」サブエージェントがまだ実行中の場合は、今すぐ完了を待ちます。通常、スキーマ確認中に完了します。失敗した場合、または起動されていない場合は、同じプロンプトで起動して完了を待ちます。

完了すると、探索結果には開始ページ、詳細ページ2つ、一覧ページ2つ、分類済みリンク、ナビゲーション値が含まれ、すべて .scrape/.work/{site_name}/explore/ の下に保存されます。概要に記載されたリンク抽出バリアントを nav_html_variant として保存します。「値を抽出」でこれがナビゲーション仕様に書き込まれます。

サイトがブロックされている場合は、ブロックされたサイトに関するルールを適用します。

その後、ページを適切なデータ型のサブフォルダーに振り分けます(site_path は .scrape/{site_name} です)。後続処理が読み込むものだけをコピーしてください。つまり、HTML バリアントと meta.json です。links.json と groups.txt は作業ディレクトリに残します。

copy_page() {
  dest="$2/$(basename "$1")"; mkdir -p "$dest"
  for f in "$1"/*.html "$1"/meta.json; do [ -f "$f" ] && cp "$f" "$dest"; done
}

# Detail pages → data type
for d in .scrape/.work/{site_name}/explore/pages/detail-*; do
  [ -d "$d" ] && copy_page "$d" {site_path}/{data_type}/pages
done

# Start + list pages → navigation
for d in .scrape/.work/{site_name}/explore/pages/start-* .scrape/.work/{site_name}/explore/pages/list-*; do
  [ -d "$d" ] && copy_page "$d" {site_path}/navigation/pages
done

# Navigation values (generated by the exploration)
mkdir -p {site_path}/navigation/values
cp .scrape/.work/{site_name}/explore/values/*.json {site_path}/navigation/values/ 2>/dev/null || true
詳細ページのサンプルとリストページを並行して分析する

範囲を限定した詳細ページのサンプル(承認済みのスキーマフィールドを抽出できる方を確認するため、両方の HTML バリアント)と、すべてのリストページを並行して分析し、スキーマを検証します。

Discovery の分析結果を再利用してください。 Detail-1 の Discovery JSON はすでに .scrape/.work/{site_name}/analyze-page/ にあり、スキーマもそこから構築されているため、このページとバリアントは再分析する必要はありません。例外:スキーマのゲートで、フィールドの承認、削除、維持以外(名前の変更、説明や値の形式の編集、フィールドの追加)を行った場合、JSON はスキーマに一致しなくなるため、そのバリアントを起動リストに戻してください。

起動リストを作成します。

  1. 詳細ページのサンプル。 サンプルページを選びます。

    • {site_path}/navigation/pages/ にリストページがある場合:1 ページ — raw.html と rendered.html の両方がある最初の詳細ページ。該当するページがなければ detail-1 を選びます。
    • それ以外の場合:detail-1 と detail-2。

    サンプルページごと、HTML バリアントごとにサブエージェントを 1 つ起動します。ただし、ファイルが存在しないバリアント(HTML ファイル選択ルール)、再利用可能な Discovery JSON で分析済みのバリアント、html_variant が固定されている場合のもう一方のバリアントは除きます。詳細ページのサブエージェントは最大 4 つです。

  2. リストページ。 {site_path}/navigation/pages/ の各ページにつき 1 つ、--list-mode サブエージェントを raw バリアントで起動し、値を {site_path}/{data_type}-list/values/ に直接書き込みます。リストページが存在する場合は必須です。ユーザーがデータ型 ID を指定していても、省略する理由にはなりません。この ID は {data_type}-list の生成元であり、以下のリストデータ型の判断は意図を推測するのではなく、フィールドの網羅性に基づいて行われます。詳細ページのためにリストページのサブエージェントを決して省略しないでください。

すべてのサブエージェントを、ツール呼び出しを挟まず 1 つのメッセージで起動します。残りを起動する前に結果を待ってはいけません。また、起動数は 5 つ以下にします。ハーネスが並行実行できない場合は、1 つずつ実行します。詳細ページの起動対象が空でも問題ありません(既存のバリアントが Discovery ですでに分析されている場合など)。起動リスト全体が空の場合は、Discovery JSON のみを使って続行します。

1 行につきサブエージェントを 1 つ、説明の後にプロンプトを記載します。

analyze detail-1 raw — /scrape-analyze-page を実行して、{site_path}/{data_type}/pages/detail-1/raw.html から {site_path}/{data_type}/spec.json のスキーマを使ってデータを抽出し、.scrape/.work/{site_name}/analyze-page/detail-1.raw.json に保存します。 analyze list-1 — /scrape-analyze-page --list-mode を実行して、{site_path}/navigation/pages/list-1/raw.html からすべての {data_type} 項目を {site_path}/{data_type}/spec.json のスキーマを使って抽出し、{site_path}/{data_type}-list/values/list-1.json に保存します。 analyze list-2 — /scrape-analyze-page --list-mode を実行して、{site_path}/navigation/pages/list-2/raw.html からすべての {data_type} 項目を {site_path}/{data_type}/spec.json のスキーマを使って抽出し、{site_path}/{data_type}-list/values/list-2.json に保存します。 ... (残りの各リストページについて同様に、同じメッセージ内に 1 つずつ記載)

スキーマのパスを指定することで、analyze-page は承認済みのフィールド名、説明、例を参照できるため、正しい名前と値の形式で抽出できます。 ここで起動するサブエージェントは、Validation フェーズで起動する唯一の分析サブエージェントです。これは希望ではなく厳格な上限です。このフェーズの残りの作業は、範囲を限定したサンプルの出力のみを使って進めます。探索中にサンプルの分析対象より多くの詳細ページをダウンロードしていても同様です。

分析済みの出力間で値の形式に食い違いがある場合(例:あるリストページの価格に、他のすべての出力とは異なる通貨が付いている場合)、再分析はしないでください。他の出力から正しい形式がすでに確定している場合は、小さなスクリプトで該当する値ファイルを直接修正し、計画を提示するときに修正内容を伝えます。本当に判断できない場合は、抽出された値をそのまま保持し、計画に不一致があることを記載します。

リストページ用のデータ型を作成するかどうかを判断する

この判断は、上記の並行分析でリストページが見つかり、分析されている場合にのみ適用されます。

判断は以下のフィールド網羅ルールだけに基づいて行います。ユーザーが要求したデータ型を理由にスキップしたり、判断を覆したりしないでください。リストページからの抽出では、要求されたフィールドを正確に取得でき、より低コストです(アイテムは個別の詳細ページへのリクエストを行わず、リストページから直接取得できます)。

{site_path}/{data_type}-list/values/list-*.json ファイルを読み込みます。各ファイルについて、スキーマ内のすべての source: "requested" フィールドが、values 配列内の少なくとも1つのアイテムのキーとして存在するか確認します。

すべてのリストページの values ファイルですべての要求フィールドが見つかった場合:

list_spec_created = true に設定します。

  1. {site_path}/{data_type}-list/spec.json を書き込みます:

    {
      "url": "{url}",
      "data_type": "{data_type}-list",
      "html_variant": "raw",
      "schema": {<same schema object as in {site_path}/{data_type}/spec.json>}
    }
    
  2. リストページを新しいデータ型にコピーします:

    mkdir -p {site_path}/{data_type}-list/pages
    for d in {site_path}/navigation/pages/list-*; do
      [ -d "$d" ] && cp -r "$d" {site_path}/{data_type}-list/pages/
    done
    

それ以外の場合: list_spec_created = false に設定します。通常どおり詳細ページの抽出に進みます。{data_type}-list/values/ ディレクトリは残っていてもかまいませんが、無視されます。

HTML バリアントを選択する

計画で html_variant が固定されている場合は、この比較をスキップし、固定されたバリアントを使用します。

.scrape/.work/{site_name}/analyze-page/ の範囲を限定したサンプルについて、raw と rendered の結果を比較します。

各ページで、{page_id}.raw.json と {page_id}.rendered.json を比較します:

  • どちらのバリアントで、より多くのスキーマフィールドが見つかりましたか?
  • 一方のバリアントでのみ見つかったフィールドはどれですか?
  • 同じフィールドの値は、バリアント間で異なりますか?

この比較には、Python スクリプトを1つだけ使用します。スクリプトでは、{site_path}/{data_type}/spec.json を読み込み、.scrape/.work/{site_name}/analyze-page/*.json を列挙し、スキーマフィールドの網羅状況と値だけを比較して、簡潔な要約を出力します。rendered で raw では見つからない要求スキーマフィールドが一貫して見つかる場合を除き、raw を推奨します。

デフォルトでは raw を優先します。raw は高速で、低コストで、より信頼性が高いためです。raw では一貫して見つからないスキーマフィールドが rendered で見つかる場合、または raw HTML が実質的に空の場合(SPA サイト)のみ rendered を使用します。

比較結果をターミナルに表示します:

HTML variant comparison:
  Both variants found: name, price, brand, description, image_url
  Only in rendered: reviews_count (3/3 pages), sale_price (2/3 pages)
  Only in raw: (none)
  Value differences:
    price: raw="$29.99", rendered="$24.99" (detail-1) — rendered may show sale price

  Recommendation: raw (all schema fields found)
  Note: rendered also has reviews_count, sale_price — say "use rendered" if you need these.

使用するバリアントが明確な場合は、それを使用します。明確でない場合(たとえば、raw ビューにフィールドのほとんどは含まれているものの、すべては含まれていない場合)は、ユーザーにどちらのバリアントを使用するか尋ねます(質問「抽出にはどの HTML バリアントを使用しますか?」、ヘッダー「HTML バリアント」、選択肢「raw を使用」「rendered を使用」とし、推奨する選択肢にその旨を示します)。その後、ユーザーが選んだバリアントを使用します。回答が得られない場合は、推奨されたバリアントを使用します。

範囲を限定したサンプルですべての承認済みスキーマフィールドが両方のバリアントから見つかった場合は、直ちに raw を選択します。 選択したバリアントが spec の設定と異なる場合は、{site_path}/{data_type}/spec.json の html_variant を新しい値に更新します。 バリアントを選択したら、追加の分析サブエージェントを起動せず、直接値の抽出に進みます。

値を抽出する

list_spec_created が true の場合は、以下の詳細ページからの値の抽出をスキップします。並行分析によって、値はすでに {data_type}-list/values/ に書き込まれています。 以下のナビゲーションの手順は引き続き適用されます。

それ以外の場合は、extract_values.py を使い、スキーマでフィルタリングしながら分析ファイルから値を作成します:

uv run --python 3.14 SKILL_DIR/scripts/extract_values.py \
  .scrape/.work/{site_name}/analyze-page/ \
  {site_path}/{data_type}/spec.json \
  --variant {html_variant} \
  -O {site_path}/{data_type}/values/

これにより、分析済みの詳細ページサンプルから新たに値が抽出されます。

ナビゲーション

SKILLS_DIR/scrape/references/extraction-spec.md にある固定のナビゲーションスキーマを使って、{site_path}/navigation/spec.json を書き込みます。サイト URL、探索で報告された nav_html_variant、クロールの開始 URL、および対象範囲を示す平易な英語の scope を使用します。対象範囲には、ユーザーが指定したセクション、または制限が指定されていない場合はサイト全体を含めます。

ナビゲーションの値は、探索の出力からすでにコピーされています。

レビュー

ブラウザーレビュー

計画中に解決された browser_review ポリシーに従います。

  • never → 最終処理フェーズに進みます。
  • always → 確認せずにレビューを開きます(以下を参照)。
  • ask → まずユーザーに抽出統計を伝えます(「{N} 件の詳細ページと {M} 件のナビゲーションページから値を抽出しました。」)。次に、ブラウザーレビューを希望するかどうか尋ねます(質問「抽出した値のブラウザーレビューを開きますか?」、ヘッダー「ブラウザーレビュー」、選択肢 Skip browser review — 「ブラウザーを開かずに続行します。」および Open browser review — 「ブラウザーで値を確認します。」)。フォールバック:ブラウザーレビューをスキップします。ユーザーが Skip browser review を選択した場合、または確認できなかった場合は、最終処理フェーズに進みます。

レビューを開くには:

  1. {site_path}/{data_type}/spec.json に最新のスキーマが含まれていることを確認します。レビューページはここから読み込みます。
  2. レビューを実行し、コマンドが完了するまで待ちます。ブラウザーでレビューページを開き、ユーザーがフィードバックを送信するのを待ち、フィードバックを出力して自動的に終了します。
    uv run --python 3.14 SKILL_DIR/scripts/run_review.py {site_path}/{data_type} .scrape/.work/{site_name} --variant {html_variant}
    
    変更後に再レビューする場合は、--changes '["Re-analyzed price across all pages","Dropped field isbn"]' を追加して、実施内容がページに表示されるようにします。
フィードバックの適用

ユーザーがレビューしてフィードバックを提供した場合:

信頼できる唯一の情報源のルールに従って、スキーマの変更(削除、名前変更、説明の編集、保持したフィールドのソースを「requested」に変更)をすべて適用します。list_spec_created が true の場合は、{site_path}/{data_type}-list/spec.json にも反映します。反映後、リストモードの分析サブエージェントを再実行し、リストの値を更新後のスキーマに合わせます。

フィードバックが APPROVED で始まる場合:スキーマの変更を適用し、最終処理フェーズに進みます。ユーザーの承認を得ています。

フィードバックが APPROVED で始まらない場合(ユーザーが「変更をリクエスト」をクリックした場合):

  • スキーマの変更を適用します。
  • 値の修正については、選択したバリアントを使用して、修正対象のフィールドをすべての詳細ページで再分析します。ハーネスで可能な場合は、ページごとにサブエージェントを1つ起動し、並列で実行します。

再分析後、値を再抽出(「値を抽出」)し、--changes で変更の概要を渡して、再度レビューを案内します。

ユーザーが承認するか、レビューをスキップするまで、レビューフェーズを繰り返します。

最終処理

最終計画を提示して承認を得る

選択した HTML バリアントと実際に抽出した値を用いて、すべての詳細ページでスキーマの検証が完了しました。以下のテンプレートに従って、最終計画と具体的な次のステップをユーザーに提示します。「Parse intent」の上書き設定は事前に設定されたものとして反映し、ユーザーがスキップを希望した場合は「スパイダーを生成する」ステップを省略します(spider_create = no)。

## Scrape plan: {host} → {data_type}

**Target**
- URL: {target_url}
- Data type: {data_type}
- Extraction: {from list pages (all requested fields found there) | from detail pages}
- Site name: `{site_name}`
- Use Zyte API: {yes | no — note if already configured}

**Schema** ({N} fields, validated across {P} pages, variant `{html_variant}`)

Requested:
- `title` (string) — "A Light in the Attic"
- `price` (string) — "£51.77"

Discovered:
- `rating` (integer) — 3
- `category` (string) — "Poetry"
- `description` (string) — "It's hard to imagine a world without…" (2340 chars)
- `upc` (string) — "a897fe39b1053632"

**Next steps**

1. Create the Scrapy project
   - Directory: `{project_dir}`
   - Project: `{project_name}`
2. Generate the extraction code
3. Generate the spider, run it and fix possible issues
4. (Optional) Deploy the spider to Scrapy Cloud and run it there

**Outputs**
- Spec: `.scrape/{site_name}/`
- Project: `{project_dir}/`

ユーザーがブラウザーレビュー(レビューフェーズ)でスキーマをすでに承認している場合、フィールドを再度確認せず、計画にはその承認が反映されているため、次のステップに焦点を当てます。

この計画を承認するか、提示内容を変更するかをユーザーに尋ねます。

承認されたら、レポートに進みます。変更の指示があれば適用して、再度提示します。

  • スキーマの変更(削除/保持/名前変更/編集)→ {site_path}/{data_type}/spec.json を更新します。
  • 対象範囲の変更(別のセクション、フィルタリングの追加、開始 URL の変更)→ {site_path}/navigation/spec.json の scope/start_urls を更新します。
  • スパイダーをスキップ → 「スパイダーを生成する」ステップを省略し、spider_create = no に設定します。
  • 設定(プロジェクトのディレクトリ/名前、Zyte、バリアント)→ 対応する行を更新します。

ユーザーが承認するまで繰り返します。ユーザーが事前に続行を許可している場合(例:「そのまま保存して、確認は不要です」)、待機だけを省略します。上記の計画は引き続き提示し、その後、同じメッセージ内でそのままレポートに進みます。

レポート

スキルの最後に、仕様書の保存先と以下の情報を報告するプレーンテキストの最終メッセージを出力します。すべての値は、最初のデフォルト値ではなく、調整後のユーザーの最終的な選択を反映する必要があります。プランがどのように承認された場合でも、最終メッセージには必ず、確定したプランに続いてこのレポートを含めます。プランは、同じ情報を自由形式で要約したものではなく、ユーザーが次のステップを確認するためのものです。

Plan approved. Spec validated and saved to .scrape/{site_name}/.

Details:
- Data types: {comma-separated list, e.g. "product-list, navigation" when list_spec_created, else "product, navigation"}
- Project dir: {project_dir}
- Project name: {project_name}
- Create the spider: {yes | no}
- Start URLs: {comma-separated list}
- Scope: {scope}
- Using Zyte API: {yes | no}

/scrape からではなく単独で実行された場合は、続行方法もユーザーに伝えます。Data types の各エントリーに対して /scrapy-extra {site_path}/{data_type_entry} {project_dir} を実行するか、ワークフロー全体を実行するには /scrape を実行してください。

コメント