mcpField
S
scrape-spec

scrape-spec

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

scrape-spec について

scrape-specは、Webサイトの抽出仕様を拡張・検証するスキルです。詳細ページや一覧ページをサンプリングし、HTMLの種類を比較して、抽出値とナビゲーションデータを作成します。

主な機能

  1. 01詳細ページと一覧ページのサンプル取得
  2. 02rawとrenderedのHTMLを比較
  3. 03仕様フィールドの抽出値を検証
  4. 04ナビゲーションデータ型を作成

活用シーン

  1. 01初期のサイト仕様の拡張
  2. 02ページ形式ごとの抽出結果の確認
  3. 03サンプルページからのナビゲーション値生成

インストール

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

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

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

詳細

/scrape-define で作成した抽出仕様を拡張し、検証します。さまざまな詳細ページと一覧ページをダウンロードして、HTML のバリエーションを比較し、値を抽出します。必要に応じて、ブラウザーで確認できる形で提示します。

${CLAUDE_SKILL_DIR}/../scrape/references/python-environments.md を読みます。

入力は、少なくとも 1 つのデータ型(スキーマと 1 ページを含む)がある仕様フォルダーです(/scrape-define で作成)。出力は、ページ、検証済みの値、ナビゲーションデータ型を追加した同じフォルダーです。

入力

生の引数文字列は $ARGUMENTS です。これはそのまま使用する単一の値です。

  1. site_path:サイト仕様フォルダーのパス。例:.scrape/books-toscrape

ステップ 1:既存の仕様を読む

{site_path}/spec.json を読み、url と data_types を取得します。

主要なデータ型(data_types のうち、最初に見つかる "navigation" 以外のデータ型)について、次を読みます。

  • {site_path}/{data_type}/spec.json → schema、html_variant

site_path の最後の要素から site_name を導出します。例:books-toscrape

ステップ 2:サイトを調査する

ステージ 1 ではページを保存せず、スキーマと値のみを保存します。ステージ 2 では、サブエージェント内で /scrape-explore-site を使用して、新しいページを少数ダウンロードします。

Agent(description="explore-site", prompt="Run /scrape-explore-site {url} .scrape/.work/{site_name}/explore 2 2")

これにより、開始ページ、最大 2 件の詳細ページ、最大 2 件の一覧ページがダウンロードされ、リンクが分類され、ナビゲーションの値が生成されます。出力はすべて .scrape/.work/{site_name}/explore/ に保存されます。

サブエージェントからサイトがブロックされていると報告された場合は、/scrape-zyte-login を実行します。完了後、上記の scrape-explore-site サブエージェントを再実行します。調査が成功するまで先に進まないでください。

その後、ページを適切なデータ型のサブフォルダーに振り分けます。

mkdir -p {site_path}/{data_type}/pages {site_path}/navigation/pages {site_path}/navigation/values

# Detail pages → data type
for d in .scrape/.work/{site_name}/explore/pages/detail-*; do
  [ -d "$d" ] && cp -r "$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" ] && cp -r "$d" {site_path}/navigation/pages/
done

# Navigation values (generated by explore-site)
cp .scrape/.work/{site_name}/explore/values/*.json {site_path}/navigation/values/ 2>/dev/null || true

ステップ 3:ナビゲーションの HTML バリエーションを判定する

詳細ページを分析する前に、ナビゲーションページに必要な HTML バリエーションを個別に判定します。すべてのナビゲーションページに対して、両方のバリエーションを使用して extract_links.py を実行します。

mkdir -p .scrape/.work/{site_name}/analyze-nav

uv run ${CLAUDE_SKILL_DIR}/../scrape-explore-site/scripts/extract_links.py \
  {site_path}/navigation/pages/*/raw.html \
  --group --base-url-from-meta \
  > .scrape/.work/{site_name}/analyze-nav/nav.raw.json 2>/dev/null || true

uv run ${CLAUDE_SKILL_DIR}/../scrape-explore-site/scripts/extract_links.py \
  {site_path}/navigation/pages/*/rendered.html \
  --group --base-url-from-meta \
  > .scrape/.work/{site_name}/analyze-nav/nav.rendered.json 2>/dev/null || true

両方の出力ファイルを読み、リンクのグループを分析します。グループ構造、各バリエーションに有用なナビゲーションリンクがあるかどうか、一方のバリエーションで他方が見落とすリンクが見つかるかどうかを考慮して、どちらの HTML バリエーションがナビゲーションをよりよく網羅しているかを判定します。レンダリング済みのバリエーションがナビゲーションを明らかに大幅に網羅できる証拠がない限り、raw を優先してください。

ステップ 6 で使用するため、結果を nav_html_variant として保存します。

ステップ 4:詳細ページのサンプルと一覧ページを並行して分析する

まず、両方の HTML バリアントがある詳細ページのサンプルを絞って分析します。一覧ページがある場合は、raw.html と rendered.html の両方がある最初の詳細ページを使用します。一覧ページがない場合は、最初の 1~2 件の詳細ページを使用します。つまり、詳細ページのバリアント比較に使用するページ数は、一覧ページも分析する場合は最大 1 件、一覧ページがない場合は最大 2 件です。バリアント比較のために、詳細ページ分析エージェントを 4 つより多く起動しないでください。これにより、ワークフローの応答性を保ちつつ、raw または rendered のどちらから承認済みスキーマのフィールドを抽出できるかを検証できます。

また、データ型スキーマを使用して、{site_path}/navigation/pages/ のすべての一覧ページを raw バリアントで分析します。詳細サンプルのエージェントに加え、一覧ページごとに 1 つの Agent を、並列実行のため単一のメッセージで起動します。プロバイダーのスレッド数制限を超えないよう、起動する Agent の合計は 5 つ以下にします。一覧ページがある場合は、2 件目の詳細ページを分析するよりも、detail-1 の raw/rendered と一覧ページのエージェントを優先してください。すべての Agent 呼び出しは、間にツール呼び出しを挟まず、1 回の応答ですべて実行してください。残りのエージェントを起動する前に結果を待たないでください。

エージェントを起動する前に、出力ディレクトリを作成します。

mkdir -p .scrape/.work/{site_name}/analyze-page
mkdir -p {site_path}/{data_type}-list/values
Agent(description="analyze detail-1 raw", prompt="/scrape-analyze-page Extract data from {site_path}/{data_type}/pages/detail-1/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-1.raw.json ")
Agent(description="analyze detail-1 rendered", prompt="Run /scrape-analyze-page {site_path}/{data_type}/pages/detail-1/rendered.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-1.rendered.json")
Agent(description="analyze list-1", prompt="/scrape-analyze-page --list-mode Extract all {data_type} items from {site_path}/navigation/pages/list-1/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into {site_path}/{data_type}-list/values/list-1.json")
Agent(description="analyze list-2", prompt="/scrape-analyze-page --list-mode Extract all {data_type} items from {site_path}/navigation/pages/list-2/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into {site_path}/{data_type}-list/values/list-2.json")
... (all list pages in the same message)

If there are no list pages, add the second detail-page pair instead:

Agent(description="analyze detail-2 raw", prompt="Run /scrape-analyze-page {site_path}/{data_type}/pages/detail-2/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-2.raw.json")
Agent(description="analyze detail-2 rendered", prompt="Run /scrape-analyze-page {site_path}/{data_type}/pages/detail-2/rendered.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-2.rendered.json")

HTML ファイルが存在しないバリアントはスキップします。{site_path}/navigation/pages/ に一覧ページがない場合は、一覧ページのエージェントと {data_type}-list/values の mkdir をスキップします。schema_path は、承認済みのフィールド名、説明、例を analyze-page に渡すため、正しい名前と値の形式で抽出できます。ステップ 5 でバリアントを選択した後は、追加の詳細ページ分析を起動しないでください。すべての一覧ページエージェントの完了を待つ必要はありません。絞り込んだ詳細サンプルが完了し、少なくとも 1 つの一覧ページの values ファイルが利用可能になったら、完了済みの一覧ページ出力を使ってステップ 4.5 に進みます。これにより、任意の一覧ページ分析の遅延で最終処理が妨げられることはありません。

ステップ 4.5:一覧ページのデータ型を作成するか判断する

このステップは、ステップ 4 で一覧ページが見つかり、分析された場合にのみ実行します。

完了済みの {site_path}/{data_type}-list/values/list-*.json ファイルを読み込みます。各完了済みファイルについて、スキーマの source: "requested" フィールドがすべて、values 配列内の少なくとも 1 つの項目のキーとして存在するか確認します。一覧ページの values ファイルがまだ完了していない場合は、list_spec_created = false に設定し、待たずに詳細ページの抽出に進みます。

完了済みのすべての一覧ページ 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/ ディレクトリが残っていても、無視されます。

ステップ 5:HTML のバリアントを選択する

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

各ページについて、{page_id}.raw.json と {page_id}.rendered.json を比較します。

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

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

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

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

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 ビューにフィールドの大半は含まれているものの、すべては含まれていない場合は、AskUserQuestion を使ってユーザーにどちらのバリアントを使用するか尋ね、詳細を提示します。

  • question: "抽出にはどちらの HTML バリアントを使用しますか?"
  • header: "HTML バリアント"
  • options: "Use raw" と "Use rendered"。推奨するものに推奨マークを付けます。

この場合は、ユーザーが選択したバリアントを使用します。

範囲を限定したサンプルで両方のバリアントが承認済みのスキーマフィールドをすべて検出した場合は、すぐに raw を選択します。バリアントがステージ 1 で使用したものから変わる場合は、{site_path}/{data_type}/spec.json の html_variant を新しい値に更新します。バリアントを選択したら、そのままステップ 6 に進みます。分析エージェントを追加で起動しないでください。

ステップ 6:値を抽出する(list_spec_created が true の場合はスキップ)

list_spec_created が true の場合は、このステップをスキップします。値はステップ 4 で既に {data_type}-list/values/ に書き込まれています。

そうでない場合は、extract_values.py を使って、スキーマでフィルタリングした分析ファイルから値を生成します。

uv run ${CLAUDE_SKILL_DIR}/../scrape-explore-site/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/

これにより、既存の値ファイル(ステージ 1 で作成したものを含む)はすべて、分析済みの詳細ページサンプルから新たに抽出した値で上書きされます。--renames は不要です。ステージ 2 の analyze-page にはスキーマ全体(名前、説明、例)が渡されるため、正しいフィールド名で直接抽出できます。

ナビゲーション

${CLAUDE_SKILL_DIR}/../scrape/references/extraction-spec.md の固定ナビゲーションスキーマを使い、サイト URL と nav_html_variant(ステップ 3 で決定)を指定して、{site_path}/navigation/spec.json を作成します。

ナビゲーションの値は、ステップ 2 で explore-site の出力から既にコピーされています。

ステップ 7:任意のブラウザレビュー

まず抽出統計(「{N} 件の詳細ページと {M} 件のナビゲーションページの値を抽出しました。」)をユーザーに伝え、その後、ブラウザレビューを希望するか AskUserQuestion で尋ねます。

環境上、追加の質問ができない場合は、ブラウザレビューをスキップして続行します。

  • question: "抽出した値をブラウザで確認しますか?"
  • header: "ブラウザレビュー"
  • options:
    • Skip browser review — "ブラウザを開かずに続行します。"
    • Open browser review — "ブラウザで値を確認します。"

ユーザーが Skip review を選択した場合は、ステップ 9 に進みます。

ユーザーが Open browser review を選択した場合は、データ型の spec を指定して /scrape-review-schema を呼び出します。

/scrape-review-schema {site_path}/{data_type} .scrape/.work/{site_name} {schema_json} {html_variant}

ブラウザを開く前に、レビュー用ディレクトリのパスをユーザーに伝えます。

ステップ 8:フィードバックを適用する

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

フィードバックが APPROVED で始まる場合:含まれているスキーマの変更(フィールドの削除、名前の変更、説明の編集、保持するフィールド → ソースを "requested" に変更)を適用し、ステップ 9 に進みます。ユーザーの承認を得ています。

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

  • スキーマの変更(フィールドの削除、名前の変更、説明の編集)を直接適用します
  • 値の修正については、まずもう一方のバリアントの分析ファイルを確認します。もう一方のバリアントに正しい値がある場合は、バリアントの切り替えを提案します:
    You corrected price to "$24.99" — the rendered variant already extracts this correctly (across 3/3 pages).
    Switch to rendered? [Y/n]
    
    ユーザーが同意した場合は、バリアントを切り替え、仕様を更新して、値を再生成します。
  • もう一方のバリアントで解決しない場合:選択したバリアントを使って、すべての詳細ページで修正対象フィールドの分析を再実行します。ページごとに 1 つずつ Agent を起動し、並行して実行します。

分析の再実行またはバリアントの切り替え後、値を再抽出し(ステップ 6)、再度レビューを依頼します。/scrape-review-schema の 5 番目の引数として変更の概要を渡します:

/scrape-review-schema {site_path}/{data_type} .scrape/.work/{site_name} {schema_json} {html_variant} '["Re-analyzed price across all pages","Dropped field isbn"]'

ユーザーがレビューを承認するかスキップするまで、ステップ 7~8 を繰り返します。

ステップ 9:確定する

レビューでスキーマに変更があった場合は、{site_path}/{data_type}/spec.json を更新します(詳細ページを使用した場合に限り該当します。list_spec_created が false の場合のみ)。

{site_path}/spec.json を更新し、data_types を次のように設定します:

  • list_spec_created が true の場合:["{data_type}-list", "navigation"] — 詳細ページからの抽出は不要なため、"{data_type}" は省略します。
  • それ以外の場合:["{data_type}", "navigation"]

報告:

list_spec_created が true の場合:

Spec finalized at {site_path}/:
  {data_type}-list: {N} list pages, {F} fields, {K} items extracted
  navigation: {M} pages

All requested fields found on list pages — skipping detail-page extraction.
Ready for codegen: /scrape-codegen {site_path}/{data_type}-list ./{project_dir}

それ以外の場合:

Spec finalized at {site_path}/:
  {data_type}: {N} detail pages, {F} fields
  navigation: {M} pages

Ready for codegen: /scrape-codegen {site_path}/{data_type} ./{project_dir}

コメント