关于 browser-automation
面向使用 Playwright 构建网页抓取和浏览器工作流自动化的开发者。内容涵盖数据提取、表单、截图、会话、动态页面及故障恢复。
主要功能
- 01提取网页结构化数据
- 02自动填写表单和多步流程
- 03捕获截图与 PDF
- 04保存和恢复浏览器会话
- 05处理动态内容与重试
- 06检查自动化检测风险
适用场景
- 01采集分页列表中的数据
- 02完成已登录门户的操作流程
- 03捕获页面或元素截图
- 04构建可重复的浏览器数据管道
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ alirezarezvani/ claude-skills --skill browser-automation安装后在 Claude Code 中输入/browser-automation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/anti_detection_patterns.mddata_extraction_recipes.mdplaywright_browser_api.mdscripts/anti_detection_checker.pyform_automation_builder.pyscraping_toolkit.py详细介绍
浏览器自动化 - POWERFUL
概述
浏览器自动化 Skill 提供了使用 Playwright 构建生产级网页自动化工作流所需的完整工具和知识。该 Skill 涵盖数据提取、表单填写、截图捕获、会话管理以及反检测模式,可帮助大规模实现可靠的浏览器自动化。
何时使用该 Skill:
- 从网站抓取结构化数据(表格、列表、搜索结果)
- 自动化多步骤浏览器工作流(登录、填写表单、下载文件)
- 捕获网页的截图或 PDF
- 从 SPA 和重度依赖 JavaScript 的网站提取数据
- 构建可重复执行的基于浏览器的数据管道
何时不使用该 Skill:
- 编写浏览器测试或 E2E 测试套件 — 请改用 playwright-pro
- 测试 API 端点 — 请改用 api-test-suite-builder
- 负载测试或性能基准测试 — 请改用 performance-profiler
为何选择 Playwright 而非 Selenium 或 Puppeteer:
- 内置自动等待 — 大多数操作无需显式调用
sleep()或waitForElement() - 通过同一 API 支持多浏览器 — Chromium、Firefox、WebKit 无需修改配置
- 网络拦截 — 原生支持拦截广告、模拟响应、捕获 API 调用
- 浏览器上下文 — 无需启动新的浏览器实例即可获得隔离的会话
- Codegen —
playwright codegen可录制你的操作并生成脚本 - 异步优先 — 使用 Python async/await 实现高吞吐量抓取
核心能力
1. 网页抓取模式
选择器优先级(从最可靠到最不可靠):
data-testid、data-id或自定义 data 属性 — 在页面改版后依然稳定#id选择器 — 唯一,但可能在两次部署之间发生变化- 语义化选择器:
article、nav、main、section— 对 CSS 变化有较强的适应性 - 基于类名的选择器:
.product-card、.price— 如果类名是生成的(例如 CSS modules),则较为脆弱 - 基于位置的选择器:
nth-child()、nth-of-type()— 最后手段,布局变化时容易失效
仅当 CSS 无法表达元素关系时才使用 XPath(例如祖先遍历、基于文本的选择)。
分页策略: 下一页按钮、基于 URL(?page=N)、无限滚动、加载更多按钮。完整的分页处理器和滚动模式请参阅 data_extraction_recipes.md。
2. 表单填写与多步骤工作流
将多步骤表单拆分为按步骤划分的独立函数。每个函数负责填写字段、点击"下一步"/"继续",并等待下一步加载完成(URL 变化或 DOM 元素出现)。
关键模式:登录流程、多页表单、文件上传(包括拖放区域)、原生与自定义下拉框处理。关于 fill()、select_option()、set_input_files() 和 expect_file_chooser() 的完整 API 参考,请参阅 playwright_browser_api.md。
3. 截图与 PDF 捕获
- 整页:
await page.screenshot(path="full.png", full_page=True) - 元素:
await page.locator("div.chart").screenshot(path="chart.png") - PDF(仅限 Chromium):
await page.pdf(path="out.pdf", format="A4", print_background=True) - 视觉回归: 在已知状态下截取屏幕截图,并将基线存放在版本控制中,命名格式为
{page}_{viewport}_{state}.png
完整的截图/PDF 选项请参阅 playwright_browser_api.md。
4. 结构化数据提取
核心提取模式:
- 表格转 JSON — 提取
<thead>表头和<tbody>行,并转换为字典 - 列表转数组 — 使用字段选择器映射表(支持用
::attr()提取属性)映射重复的卡片元素 - 嵌套/线程数据 — 对带回复的评论、分类树等进行递归提取
关于完整的提取函数、价格解析、数据清洗工具以及输出格式辅助函数(JSON、CSV、JSONL),请参阅 data_extraction_recipes.md。
5. Cookie 与会话管理
- 保存/恢复 Cookie:
context.cookies()和context.add_cookies() - 完整存储状态(Cookie + localStorage):使用
context.storage_state(path="state.json")保存,使用browser.new_context(storage_state="state.json")恢复
最佳实践: 登录后保存状态,并在多次抓取会话中复用。在开始长时间任务前检查会话是否有效——向受保护页面发送一个轻量请求,并确认没有被重定向到登录页。Cookie 和存储状态 API 的详细信息请参阅 playwright_browser_api.md。
6. 反检测模式
现代网站会通过多种途径检测自动化行为。请按优先级顺序应用以下措施:
- 移除 WebDriver 标志:通过初始化脚本移除
navigator.webdriver = true(关键) - 自定义 User Agent:轮换使用真实浏览器的 UA;切勿使用默认的 headless UA
- 真实视口:设置 1920x1080 或类似的真实分辨率(默认的 800x600 是明显的风险信号)
- 请求节流:在各操作之间添加
random.uniform()延迟 - 代理支持:按浏览器或按上下文配置代理
完整的隐身方案(navigator 属性加固、WebGL/Canvas 指纹规避、行为模拟(鼠标移动、输入速度、滚动模式)、代理轮换策略以及检测自测 URL)请参阅 anti_detection_patterns.md。
7. 动态内容处理
- SPA 渲染: 等待内容选择器(
wait_for_selector),而不是等待页面加载事件 - AJAX/Fetch 等待: 使用
page.expect_response("**/api/data*")拦截并等待特定的 API 调用 - Shadow DOM: Playwright 通过
>>运算符穿透开放的 Shadow DOM:page.locator("custom-element >> .inner-class") - 懒加载图片: 使用
scroll_into_view_if_needed()将元素滚动到可视区域以触发加载
等待策略、网络拦截和 Shadow DOM 的详细信息请参阅 playwright_browser_api.md。
8. 错误处理与重试逻辑
- 带退避的重试: 将页面交互包裹在带指数退避的重试逻辑中(例如 1 秒、2 秒、4 秒)
- 备用选择器: 遇到
TimeoutError时,在失败前尝试备用选择器 - 错误状态截图: 在意外失败时调用
page.screenshot(path="error-state.png")以便调试 - 速率限制检测: 检查 HTTP 429 响应并遵守
Retry-After响应头
完整的指数退避实现和速率限制器类请参阅 anti_detection_patterns.md。
工作流
工作流 1:单页数据提取
场景: 从一个包含 JavaScript 渲染内容的页面中提取产品数据。
步骤:
- 开发阶段以有界面模式启动浏览器(
headless=False),生产环境切换为 headless 模式 - 导航到 URL 并等待内容选择器
- 使用
query_selector_all配合字段映射提取数据 - 校验提取的数据(检查空值、预期类型)
- 输出为 JSON
async def extract_single_page(url, selectors):
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
context = await browser.new_context(
viewport={"width": 1920, "height": 1080},
user_agent="Mozilla/5.0 ..."
)
page = await context.new_page()
await page.goto(url, wait_until="networkidle")
data = await extract_listings(page, selectors["container"], selectors["fields"])
await browser.close()
return data
工作流 2:带分页的多页抓取
场景: 抓取超过 50 页的搜索结果。
步骤:
- 使用反检测设置启动浏览器
- 导航到第一页
- 从当前页面提取数据
- 检查"下一页"按钮是否存在且可用
- 点击下一页,等待新内容加载完成(而不仅仅是页面导航完成)
- 重复上述步骤,直到没有下一页或达到最大页数
- 按唯一键对结果去重
- 增量写入输出(不要将所有数据都保存在内存中)
async def scrape_paginated(base_url, selectors, max_pages=100):
all_data = []
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await (await browser.new_context()).new_page()
await page.goto(base_url)
for page_num in range(max_pages):
items = await extract_listings(page, selectors["container"], selectors["fields"])
all_data.extend(items)
next_btn = page.locator(selectors["next_button"])
if await next_btn.count() == 0 or await next_btn.is_disabled():
break
await next_btn.click()
await page.wait_for_selector(selectors["container"])
await human_delay(800, 2000)
await browser.close()
return all_data
工作流 3:带身份验证的工作流自动化
场景: 登录门户网站,逐步填写多步表单,下载报告。
步骤:
- 检查是否存在已保存的会话状态文件
- 若没有会话,则执行登录并保存状态
- 使用已保存的会话导航至目标页面
- 使用提供的数据填写多步表单
- 等待下载触发
- 将下载的文件保存到目标目录
async def authenticated_workflow(credentials, form_data, download_dir):
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
state_file = "session_state.json"
# Restore or create session
if os.path.exists(state_file):
context = await browser.new_context(storage_state=state_file)
else:
context = await browser.new_context()
page = await context.new_page()
await login(page, credentials["url"], credentials["user"], credentials["pass"])
await context.storage_state(path=state_file)
page = await context.new_page()
await page.goto(form_data["target_url"])
# Fill form steps
for step_fn in [fill_step_1, fill_step_2]:
await step_fn(page, form_data)
# Handle download
async with page.expect_download() as dl_info:
await page.click("button:has-text('Download Report')")
download = await dl_info.value
await download.save_as(os.path.join(download_dir, download.suggested_filename))
await browser.close()
工具参考
| 脚本 | 用途 | 关键参数 | 输出 |
|---|---|---|---|
scraping_toolkit.py | 生成 Playwright 抓取脚本骨架 | --url、--selectors、--paginate、--output | Python 脚本或 JSON 配置 |
form_automation_builder.py | 根据字段规格生成表单填写自动化脚本 | --fields、--url、--output | Python 自动化脚本 |
anti_detection_checker.py | 审计 Playwright 脚本中的检测风险点 | --file、--verbose | 带评分的风险报告 |
所有脚本仅依赖标准库。运行 python3 <script> --help 查看完整用法。
反模式
硬编码等待
错误做法: 在每个操作前都使用 await page.wait_for_timeout(5000)。
正确做法: 使用 wait_for_selector、wait_for_url、expect_response 或 wait_for_load_state。硬编码等待既不稳定又拖慢速度。
没有错误恢复
错误做法: 线性执行的脚本在首次失败时即崩溃。 正确做法: 将每个页面交互包裹在 try/except 中。截取错误状态截图。实现带指数退避的重试机制。
忽略 robots.txt
错误做法: 抓取时不检查 robots.txt 的指令。
正确做法: 抓取前获取并解析 robots.txt。遵守 Crawl-delay。跳过被禁止访问的路径。大规模运行时,在 User-Agent 中添加你的机器人名称。
在脚本中存储凭据
错误做法: 在 Python 文件中硬编码用户名和密码。
正确做法: 使用环境变量、.env 文件(已加入 gitignore),或密钥管理服务。通过命令行参数传递凭据。
没有速率限制
错误做法: 以每秒 100 次请求的速度冲击网站。 正确做法: 在请求之间添加随机延迟(礼貌抓取时为 1–3 秒)。监控 429 响应。实现指数退避。
选择器脆弱
错误做法: 依赖自动生成的类名(.css-1a2b3c)或过深的嵌套结构(div > div > div > span:nth-child(3))。
正确做法: 使用数据属性、语义化 HTML 或基于文本的定位器。先在浏览器 DevTools 中测试选择器。
未清理浏览器实例
错误做法: 启动浏览器后不关闭,导致资源泄漏。
正确做法: 始终使用 try/finally 或异步上下文管理器,确保调用 browser.close()。
在生产环境中使用有头模式
错误做法: 在生产环境或 CI 中使用 headless=False。
正确做法: 调试时使用有头模式,部署时使用 headless=True。通过环境变量切换:headless = os.environ.get("HEADLESS", "true") == "true"。
交叉引用
- playwright-pro — 浏览器测试技能。用于 E2E 测试、测试断言、测试夹具。浏览器自动化用于数据提取和工作流自动化,而非测试。
- api-test-suite-builder — 当网站提供公开 API 时,直接调用该 API,而不是抓取渲染后的页面。速度更快、更可靠,也更不易被检测。
- performance-profiler — 如果你的自动化脚本运行缓慢,请在增加并发之前先分析性能瓶颈。
- env-secrets-manager — 用于安全管理身份验证自动化工作流中所使用的凭据。