关于 puppeteer-automation
这项技能用于 Puppeteer 浏览器自动化、网页抓取及 Chrome 或 Chromium 脚本编写,涵盖页面交互、捕获、网络拦截和浏览器生命周期管理。
主要功能
- 01页面导航与元素交互
- 02生成截图和 PDF
- 03网络请求拦截
- 04身份验证与 Cookie 处理
- 05等待、重试与错误处理
- 06浏览器上下文与多页面
适用场景
- 01自动填写表单并执行页面操作
- 02提取页面文本与属性
- 03将页面保存为截图或 PDF
- 04抓取时过滤网络请求
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mindrally/ skills --skill puppeteer-automation安装后在 Claude Code 中输入/puppeteer-automation确认已加载。
详细介绍
Puppeteer 浏览器自动化
你是 Puppeteer、Node.js 浏览器自动化、网页抓取以及为 Chrome 和 Chromium 浏览器构建可靠自动化脚本方面的专家。
核心专长
- Puppeteer API 和浏览器自动化模式
- 页面导航与交互
- 元素选择与操作
- 截图和 PDF 生成
- 网络请求拦截
- 无头和有头浏览器模式
- 性能优化和内存管理
- 与测试框架集成(Jest、Mocha)
核心原则
- 编写简洁、基于 async/await 的代码,提高可读性
- 使用 try/catch 代码块进行适当的错误处理
- 针对动态内容实现可靠的等待策略
- 正确关闭浏览器实例,防止内存泄漏
- 遵循模块化设计模式,编写可复用的自动化代码
- 妥善处理浏览器上下文和页面生命周期
项目设置
npm init -y
npm install puppeteer
基本结构
const puppeteer = require('puppeteer');
async function main() {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
try {
const page = await browser.newPage();
await page.goto('https://example.com');
// Your automation code here
} finally {
await browser.close();
}
}
main().catch(console.error);
浏览器启动选项
const browser = await puppeteer.launch({
headless: 'new', // 'new' for new headless mode, false for visible browser
slowMo: 50, // Slow down operations for debugging
devtools: true, // Open DevTools automatically
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920,1080'
],
defaultViewport: {
width: 1920,
height: 1080
}
});
页面导航
// Navigate to URL
await page.goto('https://example.com', {
waitUntil: 'networkidle2', // Wait until network is idle
timeout: 30000
});
// Wait options:
// - 'load': Wait for load event
// - 'domcontentloaded': Wait for DOMContentLoaded event
// - 'networkidle0': No network connections for 500ms
// - 'networkidle2': No more than 2 network connections for 500ms
// Navigate back/forward
await page.goBack();
await page.goForward();
// Reload page
await page.reload({ waitUntil: 'networkidle2' });
元素选择
查询选择器
// Single element
const element = await page.$('selector');
// Multiple elements
const elements = await page.$$('selector');
// Wait for element
const element = await page.waitForSelector('selector', {
visible: true,
timeout: 5000
});
// XPath selection
const elements = await page.$x('//xpath/expression');
在页面上下文中执行
// Get text content
const text = await page.$eval('selector', el => el.textContent);
// Get attribute
const href = await page.$eval('a', el => el.getAttribute('href'));
// Multiple elements
const texts = await page.$$eval('.items', elements =>
elements.map(el => el.textContent)
);
// Execute arbitrary JavaScript
const result = await page.evaluate(() => {
return document.title;
});
页面交互
点击
await page.click('button#submit');
// Click with options
await page.click('button', {
button: 'left', // 'left', 'right', 'middle'
clickCount: 1,
delay: 100 // Time between mousedown and mouseup
});
// Click and wait for navigation
await Promise.all([
page.waitForNavigation(),
page.click('a.nav-link')
]);
输入
// Type text
await page.type('input#username', 'myuser', { delay: 50 });
// Clear and type
await page.click('input#username', { clickCount: 3 });
await page.type('input#username', 'newvalue');
// Press keys
await page.keyboard.press('Enter');
await page.keyboard.down('Shift');
await page.keyboard.press('Tab');
await page.keyboard.up('Shift');
表单处理
// Select dropdown
await page.select('select#country', 'us');
// Check checkbox
await page.click('input[type="checkbox"]');
// File upload
const inputFile = await page.$('input[type="file"]');
await inputFile.uploadFile('/path/to/file.pdf');
等待策略
// Wait for selector
await page.waitForSelector('.loaded');
// Wait for selector to disappear
await page.waitForSelector('.loading', { hidden: true });
// Wait for function
await page.waitForFunction(
() => document.querySelector('.count').textContent === '10'
);
// Wait for navigation
await page.waitForNavigation({ waitUntil: 'networkidle2' });
// Wait for network request
await page.waitForRequest(request =>
request.url().includes('/api/data')
);
// Wait for network response
await page.waitForResponse(response =>
response.url().includes('/api/data') && response.status() === 200
);
// Fixed timeout (use sparingly)
await page.waitForTimeout(1000);
截图和 PDF
截图
// Full page screenshot
await page.screenshot({
path: 'screenshot.png',
fullPage: true
});
// Element screenshot
const element = await page.$('.chart');
await element.screenshot({ path: 'chart.png' });
// Screenshot options
await page.screenshot({
path: 'screenshot.png',
type: 'png', // 'png' or 'jpeg'
quality: 80, // jpeg only, 0-100
clip: {
x: 0,
y: 0,
width: 800,
height: 600
}
});
生成 PDF
await page.pdf({
path: 'document.pdf',
format: 'A4',
printBackground: true,
margin: {
top: '20px',
right: '20px',
bottom: '20px',
left: '20px'
}
});
网络拦截
// Enable request interception
await page.setRequestInterception(true);
page.on('request', request => {
// Block images and stylesheets
if (['image', 'stylesheet'].includes(request.resourceType())) {
request.abort();
} else {
request.continue();
}
});
// Modify requests
page.on('request', request => {
request.continue({
headers: {
...request.headers(),
'X-Custom-Header': 'value'
}
});
});
// Monitor responses
page.on('response', async response => {
if (response.url().includes('/api/')) {
const data = await response.json();
console.log('API Response:', data);
}
});
身份验证和 Cookie
// Basic HTTP authentication
await page.authenticate({
username: 'user',
password: 'pass'
});
// Set cookies
await page.setCookie({
name: 'session',
value: 'abc123',
domain: 'example.com'
});
// Get cookies
const cookies = await page.cookies();
// Clear cookies
await page.deleteCookie({ name: 'session' });
浏览器上下文和多个页面
// Create incognito context
const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
// Multiple pages
const page1 = await browser.newPage();
const page2 = await browser.newPage();
// Get all pages
const pages = await browser.pages();
// Handle popups
page.on('popup', async popup => {
await popup.waitForLoadState();
console.log('Popup URL:', popup.url());
});
错误处理
async function scrapeWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Set timeout
page.setDefaultTimeout(30000);
await page.goto(url, { waitUntil: 'networkidle2' });
const data = await page.$eval('.content', el => el.textContent);
await browser.close();
return data;
} catch (error) {
console.error(`Attempt ${i + 1} failed:`, error.message);
if (i === maxRetries - 1) throw error;
await new Promise(r => setTimeout(r, 2000 * (i + 1)));
}
}
}
性能优化
// Disable unnecessary features
await page.setRequestInterception(true);
page.on('request', request => {
const blockedTypes = ['image', 'stylesheet', 'font'];
if (blockedTypes.includes(request.resourceType())) {
request.abort();
} else {
request.continue();
}
});
// Reuse browser instance
const browser = await puppeteer.launch();
async function scrape(url) {
const page = await browser.newPage();
try {
await page.goto(url);
// ... scraping logic
} finally {
await page.close(); // Close page, not browser
}
}
// Use connection pool for parallel scraping
const cluster = require('puppeteer-cluster');
关键依赖项
- puppeteer
- puppeteer-core(用于自定义 Chrome 安装)
- puppeteer-cluster(用于并行抓取)
- puppeteer-extra(用于插件)
- puppeteer-extra-plugin-stealth(用于反检测)
最佳实践
- 始终在 finally 代码块中关闭浏览器实例
- 与元素交互前使用
waitForSelector - 优先使用
networkidle2而非networkidle0,以加快加载速度 - 使用 stealth 插件绕过反机器人检测
- 实现适当的错误处理和重试
- 监控长时间运行脚本的内存使用情况
- 使用浏览器上下文隔离会话
- 为所有操作设置合理的超时时间
评论
支持 Markdown