Node.js + Puppeteer 常用代码片段

安装与基础设置

安装 Puppeteer

1
npm install puppeteer

基础启动代码(无头模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const puppeteer = require('puppeteer');

async function basicExample() {
// 启动浏览器(Puppeteer v19+ 使用 'new' 无头模式)
const browser = await puppeteer.launch({
headless: 'new', // 无头模式(可选 'new' | false 显示浏览器)
args: ['--no-sandbox', '--disable-setuid-sandbox'] // 非沙箱模式(部分环境需要)
});

// 创建新页面
const page = await browser.newPage();

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

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

console.log('页面标题:', await page.title());

// 关闭浏览器
await browser.close();
}

basicExample().catch(console.error);

页面操作

截图

1
2
3
4
5
6
7
8
9
// 截取全屏
await page.screenshot({
path: 'full_page.png',
fullPage: true
});

// 截取特定元素
const element = await page.$('#target-element');
await element.screenshot({ path: 'element.png' });

生成 PDF

1
2
3
4
5
await page.pdf({
path: 'document.pdf',
format: 'A4', // 纸张格式
printBackground: true // 打印背景
});

页面滚动

1
2
3
4
5
6
7
8
9
// 滚动到页面底部
await page.evaluate(() => {
window.scrollTo(0, document.body.scrollHeight);
});

// 滚动到指定位置
await page.evaluate((y) => {
window.scrollTo(0, y);
}, 500); // 滚动到500px位置

元素交互

选择器操作

1
2
3
4
5
6
7
8
9
10
// 获取单个元素文本内容
const title = await page.$eval('.title', el => el.textContent);

// 获取多个元素属性
const links = await page.$$eval('a', anchors =>
anchors.map(a => ({
text: a.textContent,
href: a.href
}))
);

表单操作

1
2
3
4
5
6
7
8
9
10
11
12
// 输入文本
await page.type('#username', 'testuser', { delay: 100 }); // 模拟真实输入速度

// 选择下拉框
await page.select('#country', 'China'); // 按值选择
await page.select('#country', 'value', 'CN'); // 显式指定按值选择

// 复选框操作
await page.click('#agree-terms'); // 点击切换状态

// 提交表单
await page.$eval('#login-form', form => form.submit());

鼠标操作

1
2
3
4
5
6
7
8
9
10
11
// 点击元素
await page.click('#submit-button');

// 双击操作
await page.dblclick('#double-click-element');

// 鼠标悬停
await page.hover('#menu-item');

// 拖拽操作
await page.dragAndDrop('#source', '#target');

数据提取

基础信息获取

1
2
3
4
5
6
7
8
9
// 获取页面标题
const title = await page.title();

// 获取当前URL
const url = page.url();

// 获取页面HTML
const html = await page.content();

高级数据提取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 提取表格数据
const tableData = await page.evaluate(() => {
const rows = Array.from(document.querySelectorAll('table tr'));
return rows.map(row => {
return Array.from(row.querySelectorAll('td, th')).map(cell => cell.textContent.trim());
});
});

// 提取JSON数据
const apiData = await page.evaluate(async () => {
const response = await fetch('/api/data');
return response.json();
});

高级功能

网络请求控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 拦截网络请求
await page.setRequestInterception(true);

page.on('request', request => {
// 阻止图片加载
if (request.resourceType() === 'image') {
request.abort();
} else {
request.continue();
}
});

// 监听响应
page.on('response', async response => {
if (response.url().includes('/api/data')) {
const data = await response.json();
console.log('API响应数据:', data);
}
});

处理弹窗

1
2
3
4
5
6
7
8
9
10
11
12
// 监听对话框事件
page.on('dialog', async dialog => {
console.log('弹窗内容:', dialog.message());
await dialog.accept(); // 确认弹窗
// await dialog.dismiss(); // 取消弹窗
});

// 触发弹窗
await page.evaluate(() => {
alert('测试弹窗');
});

设置认证信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 设置HTTP认证
await page.authenticate({
username: 'user',
password: 'pass'
});

// 设置Cookie
await page.setCookie({
name: 'session',
value: 'abc123',
domain: 'example.com',
path: '/',
expires: Math.floor(Date.now() / 1000) + 3600 // 1小时有效期
});

错误处理与调试

基本错误处理

1
2
3
4
5
6
7
8
9
try {
await page.goto('https://example.com');
await page.waitForSelector('#critical-element', { timeout: 5000 }); // 5秒超时
} catch (error) {
console.error('操作失败:', error.message);
} finally {
if (browser) await browser.close();
}

调试技巧

1
2
3
4
5
6
7
8
9
10
11
12
// 启用详细日志
const browser = await puppeteer.launch({
headless: false,
devtools: true, // 打开开发者工具
slowMo: 200 // 放慢操作速度,便于观察
});

// 在页面上下文中执行调试
await page.evaluate(() => {
debugger; // 配合devtools使用,会在开发者工具中断点
});

实用场景示例

网页截图对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function compareScreenshots() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');

// 首次截图作为基准
await page.screenshot({ path: 'baseline.png' });

// 执行某些操作后再次截图
await page.click('#change-content');
await page.screenshot({ path: 'after-change.png' });

await browser.close();
}

自动化表单提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
async function autoSubmitForm() {
const browser = await puppeteer.launch();
const page = await browser.newPage();

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

// 填写表单
await page.type('#name', 'John Doe');
await page.type('#email', 'john@example.com');
await page.type('#message', 'Hello, this is an automated message.');

// 提交表单并等待导航完成
await Promise.all([
page.click('#submit'),
page.waitForNavigation({ waitUntil: 'networkidle0' })
]);

// 验证提交结果
const successMessage = await page.$eval('.success-message', el => el.textContent);
console.log('提交结果:', successMessage);

await browser.close();
}

注意事项

  1. 版本兼容性:Puppeteer v19+ 使用 headless: 'new' 代替 headless: true
  2. 性能优化
    • 不需要加载的资源可以拦截(如图片、广告)
    • 使用 waitForSelector 代替固定延迟等待
    • 合理设置视口大小,避免不必要的渲染
  3. 反爬策略
    • 添加随机延迟模拟真人操作
    • 使用真实的User-Agent
    • 避免过快的连续操作
  4. 资源清理:确保在所有情况下都关闭浏览器,建议使用try/finally结构

常用配置选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 启动选项
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
'--disable-gpu',
'--disable-dev-shm-usage',
'--window-size=1280,720'
],
defaultViewport: {
width: 1280,
height: 720
},
slowMo: 100, // 放慢操作速度,便于调试
timeout: 30000 // 超时时间
});