mcpField
S
scrape-codegen-generate

scrape-codegen-generate

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

scrape-codegen-generate について

ページごとの抽出分析を統合し、スキーマとプロジェクト要件に沿った Python web-poet ページオブジェクトを生成する Claude スキルです。

主な機能

  1. 01複数ページの分析を統合
  2. 02スキーマに沿ったフィールド生成
  3. 03リストページの抽出に対応
  4. 04欠損値の処理

活用シーン

  1. 01ページ分析からページオブジェクトを生成
  2. 02リストページの抽出コードを作成
  3. 03異なるフィールド抽出パターンを統合

インストール

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

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

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

詳細

Web-poet のページオブジェクトコードを生成します。指定されたドメインのページから各フィールドを WHERE および HOW の観点で抽出する方法を記述した、ページごとの抽出分析(ステージ 1)を受け取ります。これらの分析を統合し、ドメイン全体で機能する単一のページオブジェクトクラスを生成します。

入力

生の引数文字列は $ARGUMENTS です。空白で区切られた 3 つの位置引数に分割します。

  1. work_path:ステージ 1 の分析ファイルを含むディレクトリ。例:.scrape/.work/spec
  2. output_path:生成したページオブジェクトの保存先。例:.scrape/spec/page_object.py
  3. spec_path:spec.json ファイルへのパス。例:.scrape/spec/spec.json

さらに、周囲のプロンプトテキストから取得する引数(引数文字列には含まれません):

  • fields:生成する特定のフィールド(任意)。プロンプトで「Only generate these fields: ...」として指定されます。指定されている場合は、そのフィールドの @field メソッドのみを生成します。指定されていない場合は、分析で見つかったすべてのフィールドを生成します。

手順

1. 入力を読み込む

${CLAUDE_SKILL_DIR}/../scrape/references/ から web-poet.md と docs-access.md を読み込みます。

{spec_path} からスキーマを読み込み、schema 内の properties オブジェクトを使用します。 {spec_path} から data_type も読み込みます。

data_type が -list で終わる場合は、is_list_type = true に設定します。

{work_path}/codegen-analyze/ からステージ 1 の分析ファイルをすべて読み込みます。

{work_path}/codegen-analyze/list-1.json
{work_path}/codegen-analyze/list-2.json
...

(リスト以外の spec の場合は detail-*.json を使用します)

2. ページ間で合意を形成する

スキーマ内の各フィールドについて、ページごとの分析をすべてまとめて確認します。

  • 共通パターンを特定する:すべてのページで同じ CSS セレクター/JSON-LD パスが使われていますか?そうであれば、それは強い根拠となります。
  • 相違点を解決する:分析でページごとに異なる方法が推奨されている場合は、次の点を判断します。
    • より汎用的な方法はありますか?(例:一部のページのみで機能するセレクターではなく、すべてのページで機能するセレクター)
    • 方法を組み合わせるべきですか?(例:まず JSON-LD を試し、次に CSS にフォールバックする)
    • 条件分岐が必要となる構造上の違いがありますか?
  • 取得値を検証する:推奨された抽出方法で、すべてのページから対象の値を取得できることを確認します。
  • データソースを決定する:各フィールドについて、HTML セレクター、JSON-LD、マイクロデータ、URL、またはそれらの組み合わせを使用するか決定します。
3. ページオブジェクトコードを生成する

コンテンツのフィルタリングは一切行わないでください。 ユーザーのプロンプトで値による結果のフィルタリング、除外、制限が求められていても、そのロジックをページオブジェクトに実装してはいけません。ページオブジェクトは抽出し、スパイダーはフィルタリングします。フィルタリングはスパイダーレベルで行うことを、概要に記載してください。

web-poet のリファレンスに従って、完全で自己完結した Python モジュールを生成してください。コードは次の要件を満たす必要があります。

  • ドメイン全体で動作すること:分析対象のページだけでなく、ドメイン全体で動作させてください。過剰適合を避け、商品名のハードコードや、特定のページごとの if/else などを使用しないでください。
  • シンプルであること:動作する最もシンプルな方法を優先してください。分析から、ページによってデータの取得元が実際に異なると確認された場合にのみ、フォールバックを追加してください。
  • ブラウザーのレスポンスが必要な場合は、BrowserPage を基底クラスとして使用してください。
  • データの欠損に対応すること:フィールドが存在しない場合は None を返してください(空文字列や [] は返さないでください)。
  • スキーマの型に一致させること:JSON スキーマの型に一致する値を返してください。
  • 推奨ライブラリを使用すること:JSON-LD/マイクロデータには extruct、価格には price_parser、JSON クエリには jmespath を使用してください。
  • すべてのインポートを含めること:モジュールは自己完結しており、実行可能でなければなりません。

リスト以外の型(is_list_type = false)の標準構造:

from web_poet import WebPage, field
# ... other imports as needed

class PageObject(WebPage[dict]):
    # shared helpers as @cached_property if multiple fields need them

    @field
    def field_name(self) -> type | None:
        # extraction logic
        ...

リスト型(is_list_type = true)では、web-poet の SelectorExtractor を使用してください (web-poet fields reference の「Processors for nested fields」セクションを参照)。項目ごとの抽出を行う非公開の SelectorExtractor サブクラスを定義し、items フィールドでコンテナセレクターを反復処理してください。各分析ファイルには、container_selector とフィールドごとの相対セレクターが含まれています。

import logging
from web_poet import WebPage, Returns, SelectorExtractor, field, handle_urls
from {project}.items import Product, ProductListItems

logger = logging.getLogger(__name__)


class _ProductExtractor(SelectorExtractor[Product]):
    @field
    def title(self) -> str | None:
        return self.css("h3 a::attr(title)").get()

    @field
    def price(self) -> str | None:
        return self.css("p.price_color::text").get()


@handle_urls("example.com")
class ProductListPage(WebPage, Returns[ProductListItems]):

    @field
    async def items(self) -> list[Product] | None:
        result = []
        for el in self.css("article.product_pod"):
            try:
                result.append(await _ProductExtractor(el).to_item())
            except Exception:
                logger.error("Failed to extract item from %s", self.url, exc_info=True)
        return result or None

リスト型のコードに関する主なルール:

  • SelectorExtractor[ItemClass] を継承し、項目フィールドごとに @field メソッドを1つ持つ _<ItemClass>Extractor クラス(例:_ProductExtractor)を定義してください。
  • to_item() はコルーチンであるため、items フィールドは async def にしてください。
  • 各 await extractor.to_item() を try/except Exception で囲み、logger.error(..., exc_info=True) を呼び出してください。これにより、抽出に失敗しても個々の項目に限定され、リスト全体を中断することなく完全なトレースバックがログに記録されます。
  • return result or None を使用してください([] は返さないでください)。
  • コンテナセレクターは、分析対象のすべてのページで一貫している必要があります。分析結果でセレクターが異なる場合は、最も汎用的なものを選んでください。
  • エクストラクターのフィールドセレクターは、各コンテナ要素からの相対指定にしてください(エクストラクターの self.css(...) はページ全体ではなく el を対象にします)。
  • プロジェクトの items モジュールから ItemClass と WrapperClass の両方をインポートしてください。
4. 保存して報告する

生成したコードを {output_path} に保存してください。

生成した内容の概要を返してください。

Generated page object with N fields:
  name: CSS h1.product-title::text
  price: JSON-LD offers.price, fallback to CSS span.price
  description: CSS div.product-description (text join)
  rating: JSON-LD aggregateRating.ratingValue
  image_url: CSS img.product-image::attr(src) + urljoin

合意が難しかったフィールドや、抽出が不安定になる可能性のあるフィールドについても、注記を含めてください。

コメント