Puppeteer 基础用法 #
浏览器生命周期 #
启动浏览器 #
javascript
const puppeteer = require('puppeteer');
// 基本启动
const browser = await puppeteer.launch();
// 带配置启动
const browser = await puppeteer.launch({
headless: false,
defaultViewport: { width: 1920, height: 1080 }
});
关闭浏览器 #
javascript
// 正常关闭
await browser.close();
// 断开连接(不关闭浏览器)
const wsEndpoint = browser.wsEndpoint();
await browser.disconnect();
// 重新连接
const browser = await puppeteer.connect({
browserWSEndpoint: wsEndpoint
});
完整示例 #
javascript
const puppeteer = require('puppeteer');
async function main() {
let browser;
try {
browser = await puppeteer.launch();
const page = await browser.newPage();
// 执行操作...
await page.goto('https://example.com');
} catch (error) {
console.error('Error:', error);
} finally {
if (browser) {
await browser.close();
}
}
}
main();
页面导航 #
基本导航 #
javascript
// 基本访问
await page.goto('https://example.com');
// 带选项访问
await page.goto('https://example.com', {
timeout: 30000, // 超时时间
waitUntil: 'load' // 等待条件
});
等待条件 #
text
┌─────────────────────────────────────────────────────────────┐
│ waitUntil 选项说明 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 'load' 等待 load 事件触发(默认) │
│ 'domcontentloaded' 等待 DOMContentLoaded 事件触发 │
│ 'networkidle0' 等待 500ms 内无网络请求 │
│ 'networkidle2' 等待 500ms 内不超过 2 个网络请求 │
│ 'commit' 收到响应头后立即返回 │
│ │
│ 可以组合使用: ['load', 'networkidle0'] │
│ │
└─────────────────────────────────────────────────────────────┘
导航示例 #
javascript
// 等待页面完全加载
await page.goto('https://example.com', {
waitUntil: 'load'
});
// 等待网络空闲
await page.goto('https://example.com', {
waitUntil: 'networkidle0'
});
// 组合条件
await page.goto('https://example.com', {
waitUntil: ['load', 'domcontentloaded']
});
// 快速返回(不等待资源加载)
await page.goto('https://example.com', {
waitUntil: 'commit'
});
页面操作 #
javascript
// 后退
await page.goBack();
// 前进
await page.goForward();
// 刷新
await page.reload();
// 刷新带选项
await page.reload({
waitUntil: 'networkidle0'
});
获取页面信息 #
javascript
// 获取 URL
const url = page.url();
console.log('Current URL:', url);
// 获取标题
const title = await page.title();
console.log('Page title:', title);
// 获取页面内容
const content = await page.content();
console.log('HTML content:', content);
元素选择器 #
CSS 选择器 #
javascript
// 选择单个元素
const element = await page.$('.my-class');
const button = await page.$('#submit-button');
const item = await page.$('div.container > ul > li:first-child');
// 选择多个元素
const elements = await page.$$('.my-class');
const links = await page.$$('a[href^="https"]');
const items = await page.$$('ul > li');
XPath 选择器 #
javascript
// 使用 XPath
const element = await page.$x('//div[@class="my-class"]');
const buttons = await page.$x('//button[contains(text(), "提交")]');
// XPath 返回数组
const [firstElement] = await page.$x('//h1');
文本选择器 #
javascript
// 精确文本匹配
const element = await page.locator('text=登录').element();
// 部分文本匹配
const element = await page.locator('text=/登录/i').element();
// 组合选择器
const element = await page.locator('button >> text=提交').element();
Locator API #
javascript
// 创建 Locator
const locator = page.locator('.my-element');
// 等待元素
await locator.waitFor();
// 点击元素
await locator.click();
// 填写内容
await locator.fill('Hello World');
// 获取元素
const element = await locator.element();
const elements = await locator.elements();
等待策略 #
waitForSelector #
等待元素出现或消失:
javascript
// 等待元素出现
await page.waitForSelector('.loading', { visible: true });
// 等待元素隐藏
await page.waitForSelector('.loading', { hidden: true });
// 等待元素从 DOM 移除
await page.waitForSelector('.loading', { hidden: true, timeout: 5000 });
waitForFunction #
等待自定义条件:
javascript
// 等待元素数量
await page.waitForFunction(
() => document.querySelectorAll('.item').length >= 10
);
// 等待元素文本
await page.waitForFunction(
(selector, text) => document.querySelector(selector)?.textContent.includes(text),
{}, '.status', '完成'
);
// 等待全局变量
await page.waitForFunction(
() => window.myData !== undefined
);
waitForTimeout #
固定时间等待(不推荐,仅用于调试):
javascript
// 等待 1 秒
await page.waitForTimeout(1000);
waitForNavigation #
等待页面导航完成:
javascript
// 点击后等待导航
await Promise.all([
page.waitForNavigation(),
page.click('a.link')
]);
// 等待特定 URL
await Promise.all([
page.waitForNavigation({ url: '**/success' }),
page.click('#submit')
]);
// 等待导航条件
await Promise.all([
page.waitForNavigation({
waitUntil: 'networkidle0',
timeout: 60000
}),
page.click('#submit')
]);
waitForResponse #
等待网络响应:
javascript
// 等待特定请求响应
const response = await page.waitForResponse(
response => response.url().includes('/api/data')
);
const data = await response.json();
// 点击触发请求
await Promise.all([
page.waitForResponse(response => response.url().includes('/api/submit')),
page.click('#submit')
]);
waitForRequest #
等待网络请求:
javascript
// 等待请求发出
const request = await page.waitForRequest(
request => request.url().includes('/api/data')
);
console.log('Request:', request.url());
页面设置 #
视口设置 #
javascript
// 设置视口大小
await page.setViewport({
width: 1920,
height: 1080,
deviceScaleFactor: 1,
isMobile: false,
hasTouch: false,
isLandscape: false
});
// 获取当前视口
const viewport = page.viewport();
console.log(viewport);
模拟设备 #
javascript
const puppeteer = require('puppeteer');
const devices = puppeteer.devices;
// 使用预定义设备
const iPhone = devices['iPhone 13 Pro'];
await page.emulate(iPhone);
// 常用设备列表
const deviceNames = [
'iPhone 13 Pro',
'iPhone 13 Pro Max',
'iPhone SE',
'iPad Pro',
'Pixel 5',
'Galaxy S5',
'Desktop Chrome',
'Desktop Firefox'
];
User-Agent 设置 #
javascript
// 设置 User-Agent
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
);
// 获取当前 User-Agent
const userAgent = await page.evaluate(
() => navigator.userAgent
);
Cookie 管理 #
javascript
// 设置 Cookie
await page.setCookie({
name: 'session',
value: 'abc123',
domain: 'example.com',
path: '/',
httpOnly: true,
secure: true
});
// 获取 Cookie
const cookies = await page.cookies();
console.log(cookies);
// 获取特定域名的 Cookie
const cookies = await page.cookies('https://example.com');
// 删除 Cookie
await page.deleteCookie({ name: 'session' });
// 清除所有 Cookie
const client = await page.createCDPSession();
await client.send('Network.clearBrowserCookies');
本地存储 #
javascript
// 设置 localStorage
await page.evaluate(() => {
localStorage.setItem('token', 'abc123');
localStorage.setItem('user', JSON.stringify({ id: 1, name: 'John' }));
});
// 获取 localStorage
const token = await page.evaluate(
() => localStorage.getItem('token')
);
// 清除 localStorage
await page.evaluate(() => localStorage.clear());
截图与 PDF #
截图 #
javascript
// 整页截图
await page.screenshot({
path: 'screenshot.png'
});
// 全页面截图(包括滚动区域)
await page.screenshot({
path: 'fullpage.png',
fullPage: true
});
// 指定区域截图
await page.screenshot({
path: 'clip.png',
clip: {
x: 0,
y: 0,
width: 800,
height: 600
}
});
// 元素截图
const element = await page.$('.card');
await element.screenshot({
path: 'element.png'
});
// 返回 Base64
const base64 = await page.screenshot({
encoding: 'base64'
});
// 返回 Buffer
const buffer = await page.screenshot();
PDF 生成 #
javascript
// 基本 PDF 生成
await page.pdf({
path: 'document.pdf'
});
// 详细配置
await page.pdf({
path: 'document.pdf',
format: 'A4',
printBackground: true,
margin: {
top: '20px',
bottom: '20px',
left: '20px',
right: '20px'
},
scale: 1,
displayHeaderFooter: true,
headerTemplate: '<div style="text-align: center; width: 100%;">Header</div>',
footerTemplate: '<div style="text-align: center; width: 100%;">Page <span class="pageNumber"></span></div>',
preferCSSPageSize: false
});
// 横向 PDF
await page.pdf({
path: 'landscape.pdf',
format: 'A4',
landscape: true
});
// 返回 Buffer
const buffer = await page.pdf();
页面内容获取 #
获取文本内容 #
javascript
// 获取单个元素文本
const text = await page.$eval('.title', el => el.textContent);
console.log(text);
// 获取多个元素文本
const texts = await page.$$eval('.item', elements =>
elements.map(el => el.textContent)
);
console.log(texts);
获取属性值 #
javascript
// 获取属性
const href = await page.$eval('a.link', el => el.getAttribute('href'));
const src = await page.$eval('img', el => el.getAttribute('src'));
// 获取 data 属性
const dataId = await page.$eval('.item', el => el.dataset.id);
获取表单值 #
javascript
// 获取输入框值
const value = await page.$eval('#username', el => el.value);
// 获取选中状态
const checked = await page.$eval('#checkbox', el => el.checked);
// 获取下拉框选中值
const selected = await page.$eval('#select', el => el.value);
获取元素信息 #
javascript
// 获取元素边界
const boundingBox = await page.$eval('.card', el => {
const rect = el.getBoundingClientRect();
return {
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height
};
});
// 检查元素是否可见
const isVisible = await page.$eval('.element', el => {
const style = window.getComputedStyle(el);
return style.display !== 'none' &&
style.visibility !== 'hidden' &&
style.opacity !== '0';
});
错误处理 #
Try-Catch 模式 #
javascript
async function safeClick(page, selector) {
try {
await page.waitForSelector(selector, { timeout: 5000 });
await page.click(selector);
return true;
} catch (error) {
console.error(`Failed to click ${selector}:`, error.message);
return false;
}
}
超时处理 #
javascript
// 设置默认超时
page.setDefaultTimeout(10000); // 10 秒
page.setDefaultNavigationTimeout(30000); // 30 秒
// 单独设置超时
await page.goto('https://example.com', {
timeout: 60000
});
元素存在检查 #
javascript
// 检查元素是否存在
async function elementExists(page, selector) {
const element = await page.$(selector);
return element !== null;
}
// 使用示例
if (await elementExists(page, '.popup')) {
await page.click('.popup .close');
}
完整示例 #
网页截图工具 #
javascript
const puppeteer = require('puppeteer');
async function screenshot(url, outputPath) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
await page.goto(url, { waitUntil: 'networkidle0' });
await page.screenshot({ path: outputPath, fullPage: true });
console.log(`Screenshot saved to ${outputPath}`);
} catch (error) {
console.error('Error:', error);
} finally {
await browser.close();
}
}
screenshot('https://example.com', 'example.png');
数据抓取示例 #
javascript
const puppeteer = require('puppeteer');
async function scrapeData(url) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
await page.goto(url);
await page.waitForSelector('.product-list');
const products = await page.$$eval('.product', items =>
items.map(item => ({
name: item.querySelector('.name')?.textContent.trim(),
price: item.querySelector('.price')?.textContent.trim(),
image: item.querySelector('img')?.src
}))
);
return products;
} finally {
await browser.close();
}
}
scrapeData('https://example.com/products').then(console.log);
表单自动填充 #
javascript
const puppeteer = require('puppeteer');
async function fillForm(url, data) {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto(url);
// 填写表单
await page.type('#name', data.name);
await page.type('#email', data.email);
await page.type('#phone', data.phone);
await page.select('#country', data.country);
// 勾选复选框
const checkbox = await page.$('#agree');
if (!(await checkbox.isChecked())) {
await checkbox.click();
}
// 提交表单
await page.click('#submit');
// 等待结果
await page.waitForSelector('.success-message');
await browser.close();
}
fillForm('https://example.com/form', {
name: 'John Doe',
email: 'john@example.com',
phone: '1234567890',
country: 'US'
});
下一步 #
现在你已经掌握了 Puppeteer 的基础用法,接下来学习 用户交互 了解更多高级交互操作!
最后更新:2026-03-28