scrape-codegen-generate について
ページごとの抽出分析を統合し、スキーマとプロジェクト要件に沿った Python web-poet ページオブジェクトを生成する Claude スキルです。
主な機能
- 01複数ページの分析を統合
- 02スキーマに沿ったフィールド生成
- 03リストページの抽出に対応
- 04欠損値の処理
活用シーン
- 01ページ分析からページオブジェクトを生成
- 02リストページの抽出コードを作成
- 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 つの位置引数に分割します。
- work_path:ステージ 1 の分析ファイルを含むディレクトリ。例:
.scrape/.work/spec - output_path:生成したページオブジェクトの保存先。例:
.scrape/spec/page_object.py - 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
合意が難しかったフィールドや、抽出が不安定になる可能性のあるフィールドについても、注記を含めてください。