chrome-automation
29
总安装量
30
周安装量
#7243
全站排名
安装命令
npx skills add https://github.com/aaaaqwq/claude-code-skills --skill chrome-automation
Agent 安装分布
claude-code
22
opencode
20
codex
17
cursor
17
gemini-cli
15
antigravity
13
Skill 文档
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 被å°
- 妥åå¤çéªè¯ç åç»å½
- å®ææ´æ°æµè§å¨çæ¬
- 注æå åæ³æ¼,åæ¶å ³é页é¢åæµè§å¨
- ä½¿ç¨æ å¤´æ¨¡å¼æé«æ§è½
- ä¿åæ¥å¿åé误æªå¾ä¾¿äºè°è¯