mcpField
P
playwright-web-scraper

playwright-web-scraper

github.com/dawiddutoitデータ・データベース2392 回インストール40 週間前に更新
リポジトリ

playwright-web-scraper について

Playwright Web Scraperは、Playwright MCPのブラウザツールで複数ページから構造化データを抽出するスキルです。URLとrobots.txtの確認、速度を抑えたクロール、エラー処理を扱い、JSON、CSV、Markdownに出力します。

主な機能

  1. 01URLとrobots.txtの検証
  2. 02複数ページの速度制限付きクロール
  3. 03JavaScriptによるデータ抽出
  4. 04ネットワークエラーと制限への対応
  5. 05JSON、CSV、Markdown出力

活用シーン

  1. 01複数ページの商品一覧の収集
  2. 02表やページ内の構造化項目の抽出
  3. 03分析用データへの変換

MCP 対応

Playwright MCPのブラウザツールを使い、ページの移動、内容の確認、データ抽出を行います。MCPサーバーを提供するとの記載はありません。

インストール

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

$npx skills add https://github.com/dawiddutoit/custom-claude --skill playwright-web-scraper

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

同梱ファイル

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

references/
ethical-scraping.md
extraction-patterns.md
scripts/
process_results.py
validate_urls.py

詳細

Playwright Web Scraper

礼儀正しく倫理的なクローリングを行い、複数の Web ページから構造化データを抽出します。

このスキルを使用する場面

「scrape data from」「extract information from pages」「collect data from site」「crawl multiple pages」といった表現で、Web サイトから構造化データを抽出する場合に使用します。

ワークフローのテストには使用しないでください(playwright-e2e-testingを使用してください)。エラーの監視には使用しないでください(playwright-console-monitorを使用してください)。ネットワークの分析には使用しないでください(playwright-network-analyzerを使用してください)。必ず robots.txt とレート制限を尊重してください。

クイックスタート

eコマースサイトの商品一覧をスクレイピングします。

// 1. Validate URLs
python scripts/validate_urls.py urls.txt

// 2. Scrape pages with rate limiting
const results = [];
for (const url of urls) {
  await browser_navigate({ url });
  await browser_wait_for({ time: Math.random() * 2 + 1 }); // 1-3s delay

  const data = await browser_evaluate({
    function: `
      Array.from(document.querySelectorAll('.product')).map(el => ({
        title: el.querySelector('.title')?.textContent?.trim(),
        price: el.querySelector('.price')?.textContent?.trim(),
        url: el.querySelector('a')?.getAttribute('href')
      }))
    `
  });

  results.push(...data);
}

// 3. Process results
python scripts/process_results.py scraped.json -o products.csv

目次

  1. 基本的なワークフロー
  2. レート制限の戦略
  3. URL の検証
  4. データの抽出
  5. エラー処理
  6. 結果の処理
  7. 関連ファイル
  8. 想定される結果

基本的なワークフロー

ステップ 1:URL リストを準備する

スクレイピング対象の URL を記載したテキストファイルを作成します(1 行に 1 件)。

https://example.com/products?page=1
https://example.com/products?page=2
https://example.com/products?page=3

URL を検証し、robots.txt に準拠しているか確認します。

python scripts/validate_urls.py urls.txt --user-agent "MyBot/1.0"
ステップ 2:スクレイピングセッションを初期化する

サイトに移動し、スナップショットを取得して構造を把握します。

await browser_navigate({ url: firstUrl });
await browser_snapshot();

スナップショットを使って、データ抽出用の CSS セレクターを特定します。

ステップ 3:レート制限付きのクローリングを実装する

リクエストの間にランダムな遅延を設けます(最低 1~3 秒)。

const results = [];

for (const url of urlList) {
  // Navigate to page
  await browser_navigate({ url });

  // Wait for content to load
  await browser_wait_for({ text: 'Expected content marker' });

  // Add respectful delay (1-3 seconds)
  const delay = Math.random() * 2 + 1;
  await browser_wait_for({ time: delay });

  // Extract data
  const pageData = await browser_evaluate({
    function: `/* extraction code */`
  });

  results.push(...pageData);

  // Check console for errors/warnings
  const console = await browser_console_messages();
  // Monitor for rate limit warnings
}
ステップ 4:構造化データを抽出する

browser_evaluateを使い、JavaScript でデータを抽出します。

const data = await browser_evaluate({
  function: `
    try {
      return Array.from(document.querySelectorAll('.item')).map(el => ({
        title: el.querySelector('.title')?.textContent?.trim(),
        price: el.querySelector('.price')?.textContent?.trim(),
        rating: el.querySelector('.rating')?.textContent?.trim(),
        url: el.querySelector('a')?.getAttribute('href')
      })).filter(item => item.title && item.price); // Filter incomplete records
    } catch (e) {
      console.error('Extraction failed:', e);
      return [];
    }
  `
});

包括的な抽出パターンについては、references/extraction-patterns.mdを参照してください。

ステップ 5:エラーとレート制限に対処する

レート制限を示す兆候を監視します。

// Check HTTP responses via browser_network_requests
const requests = await browser_network_requests();
const rateLimited = requests.some(r => r.status === 429 || r.status === 503);

if (rateLimited) {
  // Back off exponentially
  await browser_wait_for({ time: 10 }); // Wait 10 seconds
  // Retry or skip
}

// Check console for blocking messages
const console = await browser_console_messages({ pattern: 'rate limit|blocked|captcha' });
if (console.length > 0) {
  // Handle blocking
}
ステップ 6:結果を集約して保存する

結果を JSON ファイルに保存します。

// In your scraping script
fs.writeFileSync('scraped.json', JSON.stringify({ results }, null, 2));

処理して、希望する形式に変換します。

# View statistics
python scripts/process_results.py scraped.json --stats

# Convert to CSV
python scripts/process_results.py scraped.json -o output.csv

# Convert to Markdown table
python scripts/process_results.py scraped.json -o output.md

レート制限の戦略

最小遅延時間

リクエストの間には、必ず遅延を設けてください。

  • 一般的なサイト:1~3 秒(ランダム)
  • アクセス数の多いサイト:3~5 秒
  • 小規模なサイト:5~10 秒
  • エラー発生後:指数バックオフ(5 秒、10 秒、20 秒、40 秒)
実装
// Random delay between 1-3 seconds
const randomDelay = () => Math.random() * 2 + 1;
await browser_wait_for({ time: randomDelay() });

// Exponential backoff after rate limit
let backoffSeconds = 5;
for (let retry = 0; retry < 3; retry++) {
  try {
    await browser_navigate({ url });
    break; // Success
  } catch (e) {
    await browser_wait_for({ time: backoffSeconds });
    backoffSeconds *= 2; // Double delay each retry
  }
}
適応型レート制限

応答に応じて遅延時間を調整します。

応答コード対応
200 OK通常の遅延(1~3 秒)で続行
429 Too Many Requests遅延を 10 秒に延長して再試行
503 Service Unavailable60 秒待ってから再試行
403 Forbiddenこのドメインのスクレイピングを中止

レート制限の戦略について詳しくは、references/ethical-scraping.mdを参照してください。

URL の検証

スクレイピングを開始する前にvalidate_urls.pyを使用して、準拠状況を確認します。

# Basic validation
python scripts/validate_urls.py urls.txt

# Check robots.txt with specific user agent
python scripts/validate_urls.py urls.txt --user-agent "MyBot/1.0"

# Strict mode (exit on any invalid/disallowed URL)
python scripts/validate_urls.py urls.txt --strict

出力に含まれる内容:

  • URL 形式の検証
  • ドメイン別のグループ化
  • robots.txt への準拠状況の確認
  • 統計の概要

データの抽出

基本パターン
// Single page extraction
const data = await browser_evaluate({
  function: `
    Array.from(document.querySelectorAll('.item')).map(el => ({
      field1: el.querySelector('.selector1')?.textContent?.trim(),
      field2: el.querySelector('.selector2')?.getAttribute('href')
    }))
  `
});
ページネーションパターン
let hasMore = true;
let page = 1;

while (hasMore) {
  await browser_navigate({ url: `${baseUrl}?page=${page}` });
  await browser_wait_for({ time: randomDelay() });

  const pageData = await browser_evaluate({ function: extractionCode });
  results.push(...pageData);

  // Check for next page
  hasMore = await browser_evaluate({
    function: `document.querySelector('.next:not(.disabled)') !== null`
  });

  page++;
}

以下については、references/extraction-patterns.mdを参照してください。

  • 高度なセレクター
  • データのクリーニングパターン
  • テーブルの抽出
  • JSON-LD の抽出
  • Shadow DOM へのアクセス

エラー処理

ネットワークエラー
try {
  await browser_navigate({ url });
} catch (e) {
  console.error(`Failed to load ${url}:`, e);
  failedUrls.push(url);
  continue; // Skip to next URL
}
コンテンツの検証
const data = await browser_evaluate({ function: extractionCode });

if (!data || data.length === 0) {
  console.warn(`No data extracted from ${url}`);
  // Log for manual review
}

// Validate data structure
const validData = data.filter(item =>
  item.title && item.price // Ensure required fields exist
);
監視する兆候

ブロックやエラーがないか確認します。

// Monitor console
const console = await browser_console_messages({
  pattern: 'error|rate|limit|captcha',
  onlyErrors: true
});

if (console.length > 0) {
  console.log('Warnings detected:', console);
}

// Monitor network
const requests = await browser_network_requests();
const errors = requests.filter(r => r.status >= 400);

結果の処理

統計を表示する
python scripts/process_results.py scraped.json --stats

出力:

📊 Statistics:
  Total records: 150
  Fields (5): title, price, rating, url, image
  Sample record: {...}
形式を変換する
# To CSV
python scripts/process_results.py scraped.json -o products.csv

# To JSON (compact)
python scripts/process_results.py scraped.json -o products.json --compact

# To Markdown table
python scripts/process_results.py scraped.json -o products.md
統計の表示と変換を組み合わせる
python scripts/process_results.py scraped.json -o products.csv --stats

関連ファイル

スクリプト
  • scripts/validate_urls.py - URL リストを検証し、robots.txt への準拠状況を確認して、ドメイン別にグループ化します
  • scripts/process_results.py - スクレイピングした JSON を CSV/JSON/Markdown に変換し、統計を表示します
リファレンス
  • references/ethical-scraping.md - レート制限、robots.txt、エラー処理、監視に関する包括的なガイド
  • references/extraction-patterns.md - データ抽出、セレクター、ページネーション、テーブルに関する JavaScript パターン

想定される結果

スクレイピング成功時
✅ Validated 50 URLs
✅ Scraped 50 pages in 5 minutes (6 req/min)
✅ Extracted 1,250 products
✅ Zero rate limit errors
✅ Exported to products.csv (1,250 rows)
エラー処理を含む場合
⚠️  Validated 50 URLs (2 disallowed by robots.txt)
✅ Scraped 48 pages
⚠️  3 pages returned no data (logged for review)
✅ Extracted 1,100 products
⚠️  1 rate limit warning (backed off successfully)
✅ Exported to products.csv (1,100 rows)
レート制限の検出
❌ Rate limited after 20 pages (429 responses)
✅ Backed off exponentially (5s → 10s → 20s)
✅ Resumed scraping successfully
✅ Extracted 450 products from 25 pages

期待される効果

指標導入前導入後
セットアップ時間30-45 分5-10 分
レート制限エラー頻繁まれ
robots.txt 違反発生する可能性あり防止
データ形式の変換手動自動
エラー検出手動レビュー自動監視

成功指標

  • 成功率 > 95%(スクレイピングに成功したページ)
  • レート制限エラー リクエストの < 5%
  • 有効なデータの割合 > 90%(完全なレコード)
  • スクレイピング速度 6-12 リクエスト/分(配慮したクローリング)

要件

ツール
  • Playwright MCP ブラウザツール
  • Python 3.8+(スクリプト用)
  • 標準ライブラリのみ(スクリプトに外部依存関係なし)
知識
  • CSS セレクターの基礎
  • データ抽出のための JavaScript
  • HTTP ステータスコードの理解
  • ウェブスクレイピングの倫理に関する認識

避けるべき危険信号

  • ❌ robots.txt を確認せずにスクレイピングする
  • ❌ リクエスト間に待機時間を設けない(サーバーに過剰な負荷をかける)
  • ❌ 429/503 レスポンスコードを無視する
  • ❌ 個人情報やプライベート情報をスクレイピングする
  • ❌ ブロックを示すメッセージがないかコンソールを監視しない
  • ❌ 明示的に禁止しているサイトをスクレイピングする(利用規約を確認する)
  • ❌ 著作権に違反する形でスクレイピングしたデータを使用する
  • ❌ ページネーションを正しく処理せず、データを取りこぼす
  • ❌ フォールバックなしでセレクターをハードコードする
  • ❌ 抽出したデータ構造を検証しない

注意事項

  • 配慮したクローリングを基本とします:最低 1-3 秒の待機時間を設け、サイトの応答に応じて調整します
  • 必ず最初に robots.txt を確認します:スクレイピング前に validate_urls.py を使用します
  • コンソールとネットワークを監視します:レート制限の警告に注意し、待機時間を調整します
  • 小規模から始めます:数百件に拡大する前に、5-10 件の URL でテストします
  • 進行状況を保存します:中断に備え、結果を逐次書き込みます
  • 利用規約を尊重します:利用規約でスクレイピングを禁止しているサイトもあります
  • 説明的なユーザーエージェントを使用します:ボットであることが明確にわかるようにします
  • エラーを適切に処理します:失敗を記録して手動レビューに回し、クラッシュさせないようにします

コメント