Agent Skills: Chrome 浏览器自动化

Chrome 浏览器自动化操作。当用户需要自动化浏览器操作、网页测试、数据抓取或 UI 自动化时使用此技能。

UncategorizedID: aAAaqwq/claude-code-skills/chrome-automation

Skill Files

Browse the full folder contents for chrome-automation.

Download Skill

Loading file tree…

chrome-automation/SKILL.md

Skill Metadata

Name
chrome-automation
Description
Chrome 浏览器自动化操作。当用户需要自动化浏览器操作、网页测试、数据抓取或 UI 自动化时使用此技能。

Chrome 浏览器自动化

功能说明

此技能专门用于 Chrome 浏览器自动化,包括:

  • 网页自动化操作
  • E2E 测试
  • 网页截图和 PDF 生成
  • 表单自动填充
  • 动态网页数据抓取
  • 性能测试和监控

使用场景

  • "自动化登录网站并抓取数据"
  • "批量截取网页截图"
  • "自动化测试购物流程"
  • "监控网站性能指标"
  • "自动填写表单并提交"
  • "生成网页 PDF 报告"

技术栈

自动化工具

  • Puppeteer:Chrome DevTools Protocol
  • Playwright:跨浏览器自动化
  • Selenium:经典自动化框架
  • Cypress:现代 E2E 测试框架

辅助工具

  • puppeteer-extra:Puppeteer 插件系统
  • puppeteer-stealth:反检测插件
  • chrome-launcher:Chrome 启动器

核心功能

1. 页面导航

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: false,  // 显示浏览器
  slowMo: 50        // 减慢操作速度
});

const page = await browser.newPage();

// 导航到页面
await page.goto('https://example.com', {
  waitUntil: 'networkidle2'  // 等待网络空闲
});

// 前进后退
await page.goBack();
await page.goForward();
await page.reload();

await browser.close();

2. 元素操作

// 点击元素
await page.click('#submit-button');

// 输入文本
await page.type('#username', 'user@example.com');
await page.type('#password', 'password123');

// 选择下拉框
await page.select('#country', 'CN');

// 上传文件
const fileInput = await page.$('input[type="file"]');
await fileInput.uploadFile('/path/to/file.pdf');

// 等待元素
await page.waitForSelector('.result', { timeout: 5000 });

// 获取元素文本
const text = await page.$eval('.title', el => el.textContent);

// 获取多个元素
const items = await page.$$eval('.item', elements =>
  elements.map(el => el.textContent)
);

3. 表单自动化

async function fillForm(page: Page) {
  // 填写文本输入框
  await page.type('#name', '张三');
  await page.type('#email', 'zhangsan@example.com');
  await page.type('#phone', '13800138000');

  // 选择单选按钮
  await page.click('input[name="gender"][value="male"]');

  // 选择复选框
  await page.click('#agree-terms');
  await page.click('#subscribe-newsletter');

  // 选择下拉框
  await page.select('#city', 'beijing');

  // 填写日期
  await page.type('#birthday', '1990-01-01');

  // 填写文本域
  await page.type('#message', '这是一条测试消息');

  // 提交表单
  await page.click('button[type="submit"]');

  // 等待提交完成
  await page.waitForNavigation();
}

4. 数据抓取

async function scrapeData(url: string) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  await page.goto(url);

  // 等待内容加载
  await page.waitForSelector('.product-list');

  // 抓取数据
  const products = await page.$$eval('.product-item', items =>
    items.map(item => ({
      title: item.querySelector('.title')?.textContent,
      price: item.querySelector('.price')?.textContent,
      image: item.querySelector('img')?.src,
      link: item.querySelector('a')?.href
    }))
  );

  await browser.close();
  return products;
}

5. 截图和 PDF

// 全页截图
await page.screenshot({
  path: 'screenshot.png',
  fullPage: true
});

// 元素截图
const element = await page.$('.chart');
await element.screenshot({ path: 'chart.png' });

// 生成 PDF
await page.pdf({
  path: 'page.pdf',
  format: 'A4',
  printBackground: true,
  margin: {
    top: '20px',
    right: '20px',
    bottom: '20px',
    left: '20px'
  }
});

6. 性能监控

async function measurePerformance(url: string) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  // 开始性能追踪
  await page.tracing.start({ path: 'trace.json' });

  await page.goto(url, { waitUntil: 'networkidle2' });

  // 停止追踪
  await page.tracing.stop();

  // 获取性能指标
  const metrics = await page.metrics();
  console.log('性能指标:', metrics);

  // 获取 Performance API 数据
  const performanceData = await page.evaluate(() => {
    const timing = performance.timing;
    return {
      loadTime: timing.loadEventEnd - timing.navigationStart,
      domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
      firstPaint: performance.getEntriesByType('paint')[0]?.startTime
    };
  });

  await browser.close();
  return performanceData;
}

高级功能

1. 拦截和修改请求

await page.setRequestInterception(true);

page.on('request', request => {
  // 阻止图片加载
  if (request.resourceType() === 'image') {
    request.abort();
  }
  // 修改请求头
  else if (request.url().includes('api')) {
    request.continue({
      headers: {
        ...request.headers(),
        'Authorization': 'Bearer token'
      }
    });
  }
  else {
    request.continue();
  }
});

2. 模拟移动设备

const iPhone = puppeteer.devices['iPhone 12'];

await page.emulate(iPhone);
await page.goto('https://example.com');

3. 处理弹窗

// 处理 alert/confirm/prompt
page.on('dialog', async dialog => {
  console.log(dialog.message());
  await dialog.accept();  // 或 dialog.dismiss()
});

// 处理新窗口
const newPagePromise = new Promise(resolve =>
  browser.once('targetcreated', target => resolve(target.page()))
);

await page.click('a[target="_blank"]');
const newPage = await newPagePromise;

4. Cookie 管理

// 设置 Cookie
await page.setCookie({
  name: 'session',
  value: 'abc123',
  domain: 'example.com'
});

// 获取 Cookie
const cookies = await page.cookies();

// 删除 Cookie
await page.deleteCookie({ name: 'session' });

5. 执行 JavaScript

// 在页面上下文中执行代码
const result = await page.evaluate(() => {
  return document.title;
});

// 传递参数
const sum = await page.evaluate((a, b) => {
  return a + b;
}, 5, 3);

// 暴露函数给页面
await page.exposeFunction('md5', (text: string) => {
  return crypto.createHash('md5').update(text).digest('hex');
});

E2E 测试示例

Playwright 测试

import { test, expect } from '@playwright/test';

test.describe('登录功能', () => {
  test('成功登录', async ({ page }) => {
    await page.goto('https://example.com/login');

    await page.fill('#email', 'user@example.com');
    await page.fill('#password', 'password123');
    await page.click('button[type="submit"]');

    await expect(page).toHaveURL('https://example.com/dashboard');
    await expect(page.locator('h1')).toContainText('欢迎');
  });

  test('登录失败提示', async ({ page }) => {
    await page.goto('https://example.com/login');

    await page.fill('#email', 'wrong@example.com');
    await page.fill('#password', 'wrongpass');
    await page.click('button[type="submit"]');

    await expect(page.locator('.error')).toBeVisible();
    await expect(page.locator('.error')).toContainText('用户名或密码错误');
  });
});

Cypress 测试

describe('购物车功能', () => {
  beforeEach(() => {
    cy.visit('/products');
  });

  it('添加商品到购物车', () => {
    cy.get('.product-item').first().within(() => {
      cy.get('.add-to-cart').click();
    });

    cy.get('.cart-badge').should('contain', '1');
  });

  it('从购物车删除商品', () => {
    cy.get('.cart-icon').click();
    cy.get('.cart-item').first().within(() => {
      cy.get('.remove-button').click();
    });

    cy.get('.cart-empty').should('be.visible');
  });
});

反检测技术

Puppeteer Stealth

import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';

puppeteer.use(StealthPlugin());

const browser = await puppeteer.launch({
  headless: true,
  args: [
    '--no-sandbox',
    '--disable-setuid-sandbox',
    '--disable-blink-features=AutomationControlled'
  ]
});

const page = await browser.newPage();

// 设置真实的 User-Agent
await page.setUserAgent(
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
);

// 设置视口大小
await page.setViewport({
  width: 1920,
  height: 1080
});

// 隐藏 webdriver 标识
await page.evaluateOnNewDocument(() => {
  Object.defineProperty(navigator, 'webdriver', {
    get: () => false
  });
});

最佳实践

1. 错误处理

async function robustScrape(url: string) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  try {
    await page.goto(url, {
      waitUntil: 'networkidle2',
      timeout: 30000
    });

    const data = await page.evaluate(() => {
      // 数据提取逻辑
    });

    return data;
  } catch (error) {
    console.error('抓取失败:', error);
    // 截图保存错误现场
    await page.screenshot({ path: 'error.png' });
    throw error;
  } finally {
    await browser.close();
  }
}

2. 并发控制

import pLimit from 'p-limit';

async function scrapeMultiplePages(urls: string[]) {
  const browser = await puppeteer.launch();
  const limit = pLimit(5);  // 最多 5 个并发

  const results = await Promise.all(
    urls.map(url =>
      limit(async () => {
        const page = await browser.newPage();
        try {
          await page.goto(url);
          return await page.evaluate(() => {
            // 提取数据
          });
        } finally {
          await page.close();
        }
      })
    )
  );

  await browser.close();
  return results;
}

3. 资源优化

// 禁用不必要的资源
await page.setRequestInterception(true);
page.on('request', request => {
  const resourceType = request.resourceType();
  if (['image', 'stylesheet', 'font'].includes(resourceType)) {
    request.abort();
  } else {
    request.continue();
  }
});

// 设置超时
page.setDefaultTimeout(10000);
page.setDefaultNavigationTimeout(30000);

注意事项

  • 遵守网站的 robots.txt 和服务条款
  • 控制请求频率,避免对服务器造成压力
  • 使用代理池避免 IP 被封
  • 妥善处理验证码和登录
  • 定期更新浏览器版本
  • 注意内存泄漏,及时关闭页面和浏览器
  • 使用无头模式提高性能
  • 保存日志和错误截图便于调试