3、Puppeteer 基础:启动浏览器实例、打开新页面、页面导航与等待、截图与 PDF 生成

好,咱们正式开始动手了。

前面聊了那么多无头浏览器的概念和选型,说白了都是铺垫。真正干活,还得靠 Puppeteer。这一章我带你走一遍最核心的基础操作——启动浏览器、打开页面、导航等待、截图和 PDF。这些动作你以后每天都会用,就像吃饭喝水一样自然。

3.1 启动浏览器实例

Puppeteer 操作 Chrome,第一步永远是启动一个浏览器实例。我个人习惯把这个实例叫做 browser,它代表一个完整的浏览器进程。

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true, // 无头模式,默认就是 true
    args: ['--no-sandbox', '--disable-setuid-sandbox'] // 服务器上常用
  });
  console.log('浏览器启动成功');
  // ... 后续操作
  await browser.close();
})();

这里有个坑,我一开始就踩过。在 Linux 服务器上,如果不加 --no-sandbox,Puppeteer 会直接报错退出。为什么?因为默认的沙箱模式需要系统权限,而很多服务器环境没有。所以,服务器部署时,这两个参数几乎是标配。

注意: 每次用完浏览器,记得调用 browser.close()。否则进程会一直挂着,内存越吃越多。我曾经在线上忘记关,结果服务器 OOM 了,惨痛教训。

3.2 打开新页面

浏览器启动后,你得开个标签页才能干活。Puppeteer 里,每个标签页就是一个 Page 对象。

const page = await browser.newPage();
await page.goto('https://example.com');

就这么简单。但注意,newPage() 创建的是一个空白页,你需要用 goto() 告诉它去哪。我建议你每次创建新页面后,顺手设置一下视口大小,不然截图出来可能不是你想要的尺寸。

await page.setViewport({ width: 1280, height: 800 });

嗯,这个习惯我保持了很久。尤其是做截图对比测试时,视口不一致会导致误报。

3.3 页面导航与等待

导航,说白了就是让页面跳转。但网络环境复杂,你不能假设页面瞬间加载完。所以,等待是必须的。

3.3.1 基本导航

await page.goto('https://example.com', {
  waitUntil: 'networkidle0' // 等待网络空闲
});

waitUntil 有几种选项:

选项 含义
load 页面 load 事件触发后
domcontentloaded DOM 解析完成后
networkidle0 500ms 内没有网络请求
networkidle2 500ms 内网络请求数不超过 2 个

我个人最常用 networkidle0。为什么?因为很多页面会异步加载数据,光等 load 事件不够。你想想看,页面框架出来了,但数据还没到,这时候截图就是一张白板。

3.3.2 显式等待

有时候,导航完成不代表你要的元素出现了。这时候需要显式等待。

// 等待某个选择器出现
await page.waitForSelector('.content-loaded');

// 等待指定时间(不推荐,除非万不得已)
await page.waitForTimeout(3000);
技巧: 尽量用 waitForSelectorwaitForFunction,别用固定延时。固定延时不稳定,网络慢时不够用,网络快时浪费时间。我见过太多人用 setTimeout 来等页面,结果测试时灵时不灵。

3.4 截图与 PDF 生成

这两个功能是 Puppeteer 的杀手锏。截图用于视觉验证,PDF 用于生成报告或存档。

3.4.1 截图

await page.screenshot({
  path: 'screenshot.png',
  fullPage: true // 截取整个页面,包括滚动部分
});

这里有个细节:fullPage: true 会把页面从头到尾截成一张长图。但有些页面无限滚动,你截不完。我建议在截图前先获取页面高度,做个限制。

const height = await page.evaluate(() => document.body.scrollHeight);
if (height > 10000) {
  console.warn('页面过长,可能包含无限滚动');
}

另外,截图格式支持 PNG 和 JPEG。PNG 清晰但文件大,JPEG 体积小但有损。看场景选吧。

3.4.2 PDF 生成

PDF 生成是 Puppeteer 的独家优势。别的工具很难做到这么高质量的页面转 PDF。

await page.pdf({
  path: 'page.pdf',
  format: 'A4',
  printBackground: true // 打印背景颜色和图片
});

注意,PDF 生成时,页面会被渲染成打印样式。如果你发现 PDF 里少了某些元素,很可能是 CSS 里用了 @media screen 而不是 @media print。这时候可以模拟屏幕模式:

await page.emulateMediaType('screen');
await page.pdf({
  path: 'page.pdf',
  format: 'A4',
  printBackground: true
});
核心要点:
  • 启动浏览器时,服务器环境记得加 --no-sandbox
  • 导航等待用 networkidle0,元素等待用 waitForSelector
  • 截图用 fullPage: true 但要小心无限滚动
  • PDF 生成时注意 CSS 媒体类型

好了,这一章的基础操作就这些。你想想看,启动浏览器、打开页面、等待加载、截图或生成 PDF——这一套组合拳,已经能覆盖 80% 的自动化场景了。下一章我会讲更高级的页面交互,比如点击、输入、表单提交。到时候你会发现,Puppeteer 能干的事远不止这些。