mcpField
B
browser-automation

browser-automation

github.com/alirezarezvani生产力29.0k640 次安装今天更新
代码仓库

关于 browser-automation

面向使用 Playwright 构建网页抓取和浏览器工作流自动化的开发者。内容涵盖数据提取、表单、截图、会话、动态页面及故障恢复。

主要功能

  1. 01提取网页结构化数据
  2. 02自动填写表单和多步流程
  3. 03捕获截图与 PDF
  4. 04保存和恢复浏览器会话
  5. 05处理动态内容与重试
  6. 06检查自动化检测风险

适用场景

  1. 01采集分页列表中的数据
  2. 02完成已登录门户的操作流程
  3. 03捕获页面或元素截图
  4. 04构建可重复的浏览器数据管道

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/alirezarezvani/claude-skills --skill browser-automation

安装后在 Claude Code 中输入/browser-automation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
anti_detection_patterns.md
data_extraction_recipes.md
playwright_browser_api.md
scripts/
anti_detection_checker.py
form_automation_builder.py
scraping_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. 网页抓取模式

选择器优先级(从最可靠到最不可靠):

  1. data-testid、data-id 或自定义 data 属性 — 在页面改版后依然稳定
  2. #id 选择器 — 唯一,但可能在两次部署之间发生变化
  3. 语义化选择器:article、nav、main、section — 对 CSS 变化有较强的适应性
  4. 基于类名的选择器:.product-card、.price — 如果类名是生成的(例如 CSS modules),则较为脆弱
  5. 基于位置的选择器: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. 反检测模式

现代网站会通过多种途径检测自动化行为。请按优先级顺序应用以下措施:

  1. 移除 WebDriver 标志:通过初始化脚本移除 navigator.webdriver = true(关键)
  2. 自定义 User Agent:轮换使用真实浏览器的 UA;切勿使用默认的 headless UA
  3. 真实视口:设置 1920x1080 或类似的真实分辨率(默认的 800x600 是明显的风险信号)
  4. 请求节流:在各操作之间添加 random.uniform() 延迟
  5. 代理支持:按浏览器或按上下文配置代理

完整的隐身方案(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 渲染内容的页面中提取产品数据。

步骤:

  1. 开发阶段以有界面模式启动浏览器(headless=False),生产环境切换为 headless 模式
  2. 导航到 URL 并等待内容选择器
  3. 使用 query_selector_all 配合字段映射提取数据
  4. 校验提取的数据(检查空值、预期类型)
  5. 输出为 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 页的搜索结果。

步骤:

  1. 使用反检测设置启动浏览器
  2. 导航到第一页
  3. 从当前页面提取数据
  4. 检查"下一页"按钮是否存在且可用
  5. 点击下一页,等待新内容加载完成(而不仅仅是页面导航完成)
  6. 重复上述步骤,直到没有下一页或达到最大页数
  7. 按唯一键对结果去重
  8. 增量写入输出(不要将所有数据都保存在内存中)
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:带身份验证的工作流自动化

场景: 登录门户网站,逐步填写多步表单,下载报告。

步骤:

  1. 检查是否存在已保存的会话状态文件
  2. 若没有会话,则执行登录并保存状态
  3. 使用已保存的会话导航至目标页面
  4. 使用提供的数据填写多步表单
  5. 等待下载触发
  6. 将下载的文件保存到目标目录
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、--outputPython 脚本或 JSON 配置
form_automation_builder.py根据字段规格生成表单填写自动化脚本--fields、--url、--outputPython 自动化脚本
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 — 用于安全管理身份验证自动化工作流中所使用的凭据。

评论

支持 Markdown