Claude-skill-registry chrome-automation
Chrome 浏览器自动化操作。当用户需要自动化浏览器操作、网页测试、数据抓取或 UI 自动化时使用此技能。
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/chrome-automation" ~/.claude/skills/majiayu000-claude-skill-registry-chrome-automation && rm -rf "$T"
manifest:
skills/data/chrome-automation/SKILL.mdsource content
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 被封
- 妥善处理验证码和登录
- 定期更新浏览器版本
- 注意内存泄漏,及时关闭页面和浏览器
- 使用无头模式提高性能
- 保存日志和错误截图便于调试