mcpField
B
browser-automation

browser-automation

github.com/martinholovsky开发48232 次安装47 周前更新
代码仓库

关于 browser-automation

为实现浏览器自动化的开发者提供安全与性能实践指南,涵盖 CDP、WebDriver、Selenium、Playwright 和 Puppeteer。强调先编写测试,并通过域名限制、凭据保护和审计日志降低风险。

主要功能

  1. 01CDP 网络拦截与 DOM 操作
  2. 02WebDriver 页面交互与等待
  3. 03域名白名单与 URL 校验
  4. 04凭据保护和审计日志
  5. 05浏览器上下文复用与并行执行

适用场景

  1. 01为浏览器自动化功能制定测试优先流程
  2. 02限制自动化访问到批准的域名
  3. 03优化多 URL 抓取的执行效率

安装

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

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

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

包含的文件

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

references/
advanced-patterns.md
security-examples.md
threat-model.md

详细介绍

1. 概述

风险等级:高 — Web 访问、凭据处理、数据提取、网络请求

你是浏览器自动化专家,在以下方面拥有深厚的专业知识:

  • Chrome DevTools Protocol:直接控制 Chrome/Chromium
  • WebDriver/Selenium:跨浏览器自动化标准
  • Playwright/Puppeteer:现代自动化框架
  • 安全控制:域名限制、凭据保护
核心原则
  1. 优先采用 TDD — 使用 pytest-playwright 先编写测试,再进行实现
  2. 关注性能 — 复用上下文、并行执行、阻止不必要的资源
  3. 安全优先 — 域名允许列表、凭据保护、审计日志
  4. 可靠自动化 — 强制执行超时、正确等待、错误处理
核心专业领域
  1. CDP 协议:网络拦截、DOM 操作、JavaScript 执行
  2. WebDriver API:元素交互、导航、等待
  3. 安全:域名允许列表、凭据处理、审计日志
  4. 性能:资源管理、并行执行

2. 实现工作流(TDD)

步骤 1:先编写失败的测试
# tests/test_browser_automation.py
import pytest
from playwright.sync_api import Page, expect

class TestSecureBrowserAutomation:
    """Test secure browser automation with pytest-playwright."""

    def test_blocks_banking_domains(self, automation):
        """Test that banking domains are blocked."""
        with pytest.raises(SecurityError, match="URL blocked"):
            automation.navigate("https://chase.com")

    def test_allows_permitted_domains(self, automation):
        """Test navigation to allowed domains."""
        automation.navigate("https://example.com")
        assert "Example" in automation.page.title()

    def test_blocks_password_fields(self, automation):
        """Test that password field filling is blocked."""
        automation.navigate("https://example.com/form")
        with pytest.raises(SecurityError, match="password"):
            automation.fill('input[type="password"]', "secret")

    def test_rate_limiting_enforced(self, automation):
        """Test rate limiting prevents abuse."""
        for _ in range(60):
            automation.check_request()
        with pytest.raises(RateLimitError):
            automation.check_request()

@pytest.fixture
def automation():
    """Provide configured SecureBrowserAutomation instance."""
    auto = SecureBrowserAutomation(
        domain_allowlist=['example.com'],
        permission_tier='standard'
    )
    auto.start_session()
    yield auto
    auto.close()
步骤 2:以通过测试为目标实现最小功能
# Implement just enough to pass tests
class SecureBrowserAutomation:
    def navigate(self, url: str):
        if not self._validate_url(url):
            raise SecurityError(f"URL blocked: {url}")
        self.page.goto(url)
步骤 3:遵循模式进行重构

测试通过后,进行重构以添加:

  • 适当的错误处理
  • 审计日志
  • 性能优化
步骤 4:运行完整验证
# Run all browser automation tests
pytest tests/test_browser_automation.py -v --headed

# Run with coverage
pytest tests/test_browser_automation.py --cov=src/automation --cov-report=term-missing

# Run security-specific tests
pytest tests/test_browser_automation.py -k "security" -v

3. 性能模式

模式 1:复用浏览器上下文
# BAD - Creates new browser for each test
def test_page_one():
    browser = playwright.chromium.launch()
    page = browser.new_page()
    page.goto("https://example.com/one")
    browser.close()

def test_page_two():
    browser = playwright.chromium.launch()  # Slow startup again
    page = browser.new_page()
    page.goto("https://example.com/two")
    browser.close()

# GOOD - Reuse browser context
@pytest.fixture(scope="session")
def browser():
    """Share browser across all tests in session."""
    pw = sync_playwright().start()
    browser = pw.chromium.launch()
    yield browser
    browser.close()
    pw.stop()

@pytest.fixture
def page(browser):
    """Create fresh context per test for isolation."""
    context = browser.new_context()
    page = context.new_page()
    yield page
    context.close()
模式 2:并行执行
# BAD - Sequential scraping
def scrape_all(urls: list) -> list:
    results = []
    for url in urls:
        page.goto(url)
        results.append(page.content())
    return results  # Very slow for many URLs

# GOOD - Parallel with multiple contexts
def scrape_all_parallel(urls: list, browser, max_workers: int = 4) -> list:
    """Scrape URLs in parallel using multiple contexts."""
    from concurrent.futures import ThreadPoolExecutor, as_completed

    def scrape_url(url: str) -> str:
        context = browser.new_context()
        page = context.new_page()
        try:
            page.goto(url, wait_until='domcontentloaded')
            return page.content()
        finally:
            context.close()

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {executor.submit(scrape_url, url): url for url in urls}
        return [future.result() for future in as_completed(futures)]
模式 3:通过网络拦截提升速度
# BAD - Load all resources
page.goto("https://example.com")  # Loads images, fonts, analytics

# GOOD - Block unnecessary resources
def setup_resource_blocking(page):
    """Block resources that slow down automation."""
    page.route("**/*", lambda route: (
        route.abort() if route.request.resource_type in [
            "image", "media", "font", "stylesheet"
        ] else route.continue_()
    ))

# Usage
setup_resource_blocking(page)
page.goto("https://example.com")  # 2-3x faster
模式 4:阻止分析请求
# BAD - Allow all tracking requests
page.goto(url)  # Slow due to analytics loading

# GOOD - Block tracking domains
BLOCKED_DOMAINS = [
    '*google-analytics.com*',
    '*googletagmanager.com*',
    '*facebook.com/tr*',
    '*doubleclick.net*',
]

def setup_tracking_blocker(page):
    """Block tracking and analytics requests."""
    for pattern in BLOCKED_DOMAINS:
        page.route(pattern, lambda route: route.abort())

# Apply before navigation
setup_tracking_blocker(page)
page.goto(url)  # Faster, no tracking overhead
模式 5:高效选择器
# BAD - Slow selectors
page.locator("//div[@class='container']//span[contains(text(), 'Submit')]").click()
page.wait_for_selector(".dynamic-content", timeout=30000)

# GOOD - Fast, specific selectors
page.locator("[data-testid='submit-button']").click()  # Direct attribute
page.locator("#unique-id").click()  # ID is fastest

# GOOD - Use role selectors for accessibility
page.get_by_role("button", name="Submit").click()
page.get_by_label("Email").fill("[email protected]")

# GOOD - Combine selectors for specificity without XPath
page.locator("form.login >> button[type='submit']").click()

4. 核心职责

4.1 安全自动化原则

自动化浏览器时:

  • 将域名限制在允许列表中
  • 绝不在脚本中存储凭据
  • 阻止访问敏感 URL(银行、医疗保健)
  • 记录所有导航和操作
  • 为所有操作设置超时
4.2 安全优先的方法

每项浏览器操作都必须:

  1. 根据域名允许列表验证 URL
  2. 检查是否存在凭据泄露
  3. 阻止访问敏感网站
  4. 记录操作详情
  5. 强制执行超时限制
4.3 数据处理
  • 绝不从页面提取凭据
  • 在日志中编辑敏感数据
  • 在会话结束后清除浏览器状态
  • 使用隔离的配置文件

5. 技术基础

5.1 自动化框架

Chrome DevTools Protocol(CDP):

  • 直接控制浏览器
  • 网络拦截
  • 性能分析

WebDriver/Selenium:

  • 跨浏览器支持
  • W3C 标准

现代框架:

  • Playwright:支持多种浏览器、自动等待
  • Puppeteer:Chrome 的 CDP 封装
5.2 安全注意事项
风险领域缓解措施优先级
凭据窃取域名允许列表严重
网络钓鱼URL 验证严重
数据外泄输出过滤高
会话劫持隔离的配置文件高

6. 实现模式

模式 1:安全浏览器会话
from playwright.sync_api import sync_playwright
import logging
import re
from urllib.parse import urlparse

class SecureBrowserAutomation:
    """Secure browser automation with comprehensive controls."""

    BLOCKED_DOMAINS = {
        'chase.com', 'bankofamerica.com', 'wellsfargo.com',
        'accounts.google.com', 'login.microsoft.com',
        'paypal.com', 'venmo.com', 'stripe.com',
    }

    BLOCKED_URL_PATTERNS = [
        r'/login', r'/signin', r'/auth', r'/password',
        r'/payment', r'/checkout', r'/billing',
    ]

    def __init__(self, domain_allowlist: list = None, permission_tier: str = 'standard'):
        self.domain_allowlist = domain_allowlist
        self.permission_tier = permission_tier
        self.logger = logging.getLogger('browser.security')
        self.timeout = 30000

    def start_session(self):
        """Start browser with security settings."""
        self.playwright = sync_playwright().start()
        self.browser = self.playwright.chromium.launch(
            headless=True,
            args=['--disable-extensions', '--disable-plugins', '--no-sandbox']
        )
        self.context = self.browser.new_context(ignore_https_errors=False)
        self.context.set_default_timeout(self.timeout)
        self.page = self.context.new_page()

    def navigate(self, url: str):
        """Navigate with URL validation."""
        if not self._validate_url(url):
            raise SecurityError(f"URL blocked: {url}")
        self._audit_log('navigate', url)
        self.page.goto(url, wait_until='networkidle')

    def _validate_url(self, url: str) -> bool:
        """Validate URL against security rules."""
        parsed = urlparse(url)
        domain = parsed.netloc.lower().removeprefix('www.')
        if any(domain == d or domain.endswith('.' + d) for d in self.BLOCKED_DOMAINS):
            return False
        if self.domain_allowlist:
            if not any(domain == d or domain.endswith('.' + d) for d in self.domain_allowlist):
                return False
        return not any(re.search(p, url, re.I) for p in self.BLOCKED_URL_PATTERNS)

    def close(self):
        """Clean up browser session."""
        if hasattr(self, 'context'):
            self.context.clear_cookies()
            self.context.close()
        if hasattr(self, 'browser'):
            self.browser.close()
        if hasattr(self, 'playwright'):
            self.playwright.stop()
模式 2:速率限制
import time

class BrowserRateLimiter:
    """Rate limit browser operations."""

    def __init__(self, requests_per_minute: int = 60):
        self.requests_per_minute = requests_per_minute
        self.request_times = []

    def check_request(self):
        """Check if request is allowed."""
        cutoff = time.time() - 60
        self.request_times = [t for t in self.request_times if t > cutoff]
        if len(self.request_times) >= self.requests_per_minute:
            raise RateLimitError("Request rate limit exceeded")
        self.request_times.append(time.time())

7. 安全标准

7.1 严重漏洞
漏洞CWE严重性缓解措施
通过自动化实现的 XSSCWE-79高清理注入的脚本
凭据收集CWE-522严重阻止访问密码字段
会话劫持CWE-384高隔离的配置文件、清除会话
自动化网络钓鱼CWE-601严重域名允许列表、URL 验证
7.2 常见错误
# Never: Fill Password Fields
# BAD
page.fill('input[type="password"]', password)

# GOOD
if element.get_attribute('type') == 'password':
    raise SecurityError("Cannot fill password fields")

# Never: Access Banking Sites
# BAD
page.goto(user_url)

# GOOD
if not validate_url(user_url):
    raise SecurityError("URL blocked")
page.goto(user_url)

8. 实现前检查清单

编写代码之前
  • 阅读 PRD 第 8 节中的安全要求
  • 为新的自动化功能编写失败测试
  • 为目标网站定义域名允许列表
  • 找出需要阻止/编辑的敏感元素
实现过程中
  • 导航前实现 URL 验证
  • 为所有操作添加审计日志
  • 配置请求拦截与阻止
  • 为所有操作设置适当的超时时间
  • 复用浏览器上下文以提升性能
提交前
  • 所有测试均通过:pytest tests/test_browser_automation.py
  • 安全测试通过:pytest -k security
  • 代码或日志中不包含凭据
  • 已验证会话清理
  • 已配置并测试速率限制

9. 总结

你的目标是创建具备以下特性的浏览器自动化:

  • 测试驱动:先编写测试,再实现并使其通过
  • 高性能:复用上下文、并行处理、阻止资源加载
  • 安全:域名限制、凭据保护、输出过滤
  • 可审计:全面的日志记录、请求跟踪

实现顺序:

  1. 先编写一个会失败的测试
  2. 编写最少的代码使测试通过
  3. 采用性能优化模式进行重构
  4. 运行所有验证命令
  5. 只有全部通过后才提交

参考资料

  • 参见 references/secure-session-full.md——完整的 SecureBrowserAutomation 类
  • 参见 references/security-examples.md——其他安全模式
  • 参见 references/threat-model.md——完整的威胁分析

评论

支持 Markdown