关于 playwright-web-scraper
Playwright Web Scraper 是使用 Playwright MCP 浏览器工具从多个网页提取结构化数据的技能,涵盖 URL 与 robots.txt 检查、限速爬取、错误处理,以及导出为 JSON、CSV 或 Markdown。
主要功能
- 01验证 URL 和 robots.txt
- 02限速爬取多个网页
- 03使用 JavaScript 提取数据
- 04处理网络错误与限流
- 05输出 JSON、CSV 和 Markdown
适用场景
- 01采集多个页面的商品列表
- 02提取表格或页面结构化字段
- 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.mdextraction-patterns.mdscripts/process_results.pyvalidate_urls.py详细介绍
Playwright 网页抓取
以尊重且合乎道德的爬取方式,从多个网页中提取结构化数据。
何时使用此技能
当需要从网站“抓取数据”“从页面提取信息”“收集网站数据”或“爬取多个页面”时使用。
请勿用于测试工作流(使用 playwright-e2e-testing)、监控错误(使用 playwright-console-monitor)或分析网络(使用 playwright-network-analyzer)。务必遵守 robots.txt 和速率限制。
快速开始
从电子商务网站抓取商品列表:
// 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
目录
- 核心工作流
- 速率限制策略
- URL 验证
- 数据提取
- 错误处理
- 结果处理
- 支持文件
- 预期结果
核心工作流
步骤 1:准备 URL 列表
创建一个包含待抓取 URL 的文本文件(每行一个):
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 Unavailable | 等待 60 秒,然后重试 |
| 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 响应码
- ❌ 抓取个人/私人信息
- ❌ 未监控控制台中的拦截消息
- ❌ 抓取明确禁止此类行为的网站(查看 ToS)
- ❌ 违反版权规定使用抓取的数据
- ❌ 未正确处理分页(导致数据缺失)
- ❌ 选择器写死且没有备用方案
- ❌ 未验证提取的数据结构
注意事项
- 默认采用礼貌爬取:至少延迟 1-3 秒,并根据网站响应进行调整
- 务必先检查 robots.txt:抓取前使用
validate_urls.py - 监控控制台和网络:留意速率限制警告并调整延迟
- 从小规模开始:先用 5-10 个 URL 测试,再扩展到数百个
- 保存进度:逐步写入结果,以防中断
- 遵守 ToS:有些网站在服务条款中禁止抓取
- 使用描述性用户代理:清楚标识你的机器人
- 妥善处理错误:记录失败以供手动审查,不要崩溃