惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
MyScale Blog
MyScale Blog
N
Netflix TechBlog - Medium
I
InfoQ
Jina AI
Jina AI
Martin Fowler
Martin Fowler
Recent Announcements
Recent Announcements
量子位
月光博客
月光博客
罗磊的独立博客
雷峰网
雷峰网
The Cloudflare Blog
V
V2EX
小众软件
小众软件
人人都是产品经理
人人都是产品经理
博客园 - Franky
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
S
SegmentFault 最新的问题

BlogFinder

日常漫步 Vol.24 之漫步前山河 - 雅余 周报 #1-聊聊本周的收获 - Edwin's Blog 我的OpenCode必装插件与Skill Write Something 掌中之物未必在掌握之中 · CRIVU PiliNara,一个更顺手的 PiliPlus 分支 「NekoEcho」:做一个必有回响的猫娘主题博客 2026-05 书影音总结 简化博客主题 - 安迪 我第一次发布 npm 包 拾花小记#45:中考前的二三事 – 小改学习志 黛西花园5月游 #18 枇杷又熟了的五月月报 一些奇奇怪怪的需求?word仿方正书版的几个小操作 - Xiobb's Blog 0419 御温泉之旅 修复了一些bug,网站基本上趋于稳定了 - 新锐博客 又回到四十年前 如何定义成功 迷鹿屋2026已重新上线 科技冰火两重天+一周回顾 ${title} 热度退了,我反而用得更深了-咕咚同学 我到底该不该换个域名? 随身WIFI折腾记 - 安迪 博客撰写体验提升——hexo pro插件 为什么不用相机把屏幕上的接关密码拍下来? 国清寺与天台山 – Ouroboros ★★★★☆《挽救计划》——久违的经济上行感 - Davidの3号基地 删除右键“打开方式”里多余选项 第三周刊_No.53|一切都会被支付两次
Puppeteer:Google 出品的浏览器自动化神器,从爬虫到测试全覆盖
Cheman · 2026-06-16 · via BlogFinder

今天在 GitHub Trending 上看到一个有意思的项目:Puppeteer,这是 Google 官方维护的浏览器自动化库,能够用几行代码控制 Chrome 或 Firefox 完成复杂任务。

一、项目概述

Puppeteer 是一个 JavaScript 库,提供高层 API 通过 DevTools ProtocolWebDriver BiDi 控制 Chrome 或 Firefox 浏览器。默认以无头模式(headless)运行,非常适合服务端自动化场景。

核心特性:

  • 🚀 支持 Chrome 和 Firefox 双引擎
  • 🔧 提供 DevTools Protocol 和 WebDriver BiDi 两种通信协议
  • 📦 安装时自动下载兼容版本的浏览器
  • 🧪 内置 Mocha 测试支持,适合 E2E 测试
  • 🔌 支持 MCP(Model Context Protocol)集成,可与 AI Agent 联动
  • 🌐 支持浏览器内运行(puppeteer-in-browser)

典型应用场景:

  • UI 自动化测试(E2E)
  • 网页截图和 PDF 生成
  • 服务端渲染(SSR)预渲染
  • 大规模网页爬取
  • 表单自动填充和提交
  • 性能分析和监控

二、技术原理

架构设计

Puppeteer 采用分层架构设计,核心由以下几个模块组成:

┌─────────────────────────────────────┐
│         User Code (Node.js)         │
├─────────────────────────────────────┤
│         Puppeteer API Layer         │
│  (puppeteer/puppeteer-core)        │
├─────────────────────────────────────┤
│    DevTools Protocol / WebDriver    │
│            BiDi Adapter            │
├─────────────────────────────────────┤
│  Chrome for Testing / Firefox       │
└─────────────────────────────────────┘

核心技术栈

package.jsoneslint.config.mjs 可以看到项目的技术选型:

技术用途
TypeScript主要开发语言,提供类型安全
Mocha测试框架,支持异步测试和重试
Wireit构建任务编排工具
Hereby类似 make 的任务运行器
Rollup打包工具,用于浏览器版本
esbuild快速 TypeScript 编译

关键算法与通信机制

Puppeteer 的核心在于与浏览器的通信机制。以 DevTools Protocol 为例:

// 简化的通信流程
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();

// 通过 CDP 发送命令
await page.goto('https://example.com');
// 底层:Page.navigate command

协议适配层支持两种模式:

  1. DevTools Protocol(默认):Chrome 原生调试协议,功能最全
  2. WebDriver BiDi:W3C 标准,跨浏览器兼容性好

数据流分析

// 从源码 example 中提取的真实数据流
const browser = await puppeteer.launch();  // 1. 启动浏览器进程
const page = await browser.newPage();       // 2. 创建新页面(CDP Target)
await page.goto(url);                      // 3. 导航(发送 Page.navigate)
await page.setViewport({width, height});   // 4. 设置视口(Emulation.setDeviceMetricsOverride)
await page.keyboard.press('/');            // 5. 键盘输入(Input.dispatchKeyEvent)
const element = await page.locator('selector');  // 6. 元素定位(CSS/XPath/ARIA)
await element.click();                     // 7. 点击(Input.dispatchMouseEvent)
const text = await element.evaluate(el => el.textContent); // 8. 执行 JS(Runtime.evaluate)
await browser.close();                    // 9. 清理资源

三、安装与快速开始

环境要求

  • Node.js 18+(推荐使用 Active LTS 版本)
  • npm / pnpm / yarn / bun 任一包管理器

安装步骤

# 完整安装(自动下载 Chrome)
npm i puppeteer

# 仅安装库(需手动管理浏览器)
npm i puppeteer-core

⚠️ 注意:现代包管理器(npm、pnpm、yarn、bun、deno)默认阻止依赖的安装脚本。如果安装脚本被阻止,Puppeteer 不会自动下载浏览器,会导致运行时错误。

手动安装浏览器的方法:

npx puppeteer browsers install

或者在 package.json 中允许 puppeteer 的运行脚本:

{
  "allowScripts": ["puppeteer"]
}

最简运行示例

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.goto('https://developer.chrome.com/');
await page.setViewport({width: 1080, height: 1024});

// 使用键盘快捷键打开搜索
await page.keyboard.press('/');
await page.locator('::-p-aria(Search)').fill('automate beyond recorder');
await page.locator('.devsite-result-item-link').click();

const textSelector = await page
  .locator('::-p-text(Customize and automate)')
  .waitHandle();
const fullTitle = await textSelector?.evaluate(el => el.textContent);

console.log('The title of this blog post is "%s".', fullTitle);
await browser.close();

四、使用方法与实战

基础用法

1. 截图功能

await page.screenshot({ 
  path: 'example.png',
  fullPage: true  // 全页截图
});

2. 生成 PDF

await page.pdf({
  path: 'page.pdf',
  format: 'A4',
  printBackground: true
});

3. 等待元素出现

// 等待选择器出现
await page.waitForSelector('.my-element');

// 等待函数返回真值
await page.waitForFunction(() => document.readyState === 'complete');

// 使用 locator(推荐)
const element = await page.locator('.my-element').waitHandle();

进阶用法

1. 拦截网络请求

await page.setRequestInterception(true);
page.on('request', request => {
  if (request.url().includes('ads'))
    request.abort();  // 阻止广告请求
  else
    request.continue();
});

2. 执行注入脚本

// 在页面加载前注入
await page.evaluateOnNewDocument(() => {
  Object.defineProperty(navigator, 'webdriver', {get: () => false});
});

// 在已加载的页面执行
const result = await page.evaluate(() => {
  return document.title;
});

3. 并行处理多个页面

const browser = await puppeteer.launch({ 
  headless: 'shell'  // 使用 chrome-headless-shell,更轻量
});

const pages = await Promise.all([
  browser.newPage(),
  browser.newPage(),
  browser.newPage(),
]);

await Promise.all(
  pages.map((page, i) => 
    page.goto(`https://example.com/page/${i}`)
  )
);

实际项目示例:批量爬取文章标题

import puppeteer from 'puppeteer';

async function scrapeArticles(url: string) {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  
  await page.goto(url, { waitUntil: 'networkidle2' });
  
  const articles = await page.evaluate(() => {
    return Array.from(document.querySelectorAll('article h2'))
      .map(h2 => ({
        title: h2.textContent?.trim(),
        link: h2.querySelector('a')?.href
      }));
  });
  
  await browser.close();
  return articles;
}

// 使用
const results = await scrapeArticles('https://blog.example.com');
console.log(results);

五、常见问题与解决方案

安装失败

问题npm install puppeteer 后运行时报错 Failed to launch chrome

原因:包管理器的沙箱机制阻止了安装脚本执行,浏览器未下载。

解决方案

# 方法1:手动下载浏览器
npx puppeteer browsers install

# 方法2:允许安装脚本(npm)
npm config set ignore-scripts false
npm install puppeteer

# 方法3:使用 --unsafe-perm(CI 环境)
npm install puppeteer --unsafe-perm=true

运行时错误

问题Protocol error: Connection closed

原因:浏览器进程意外退出,可能是内存不足或超时。

解决方案

const browser = await puppeteer.launch({
  args: [
    '--no-sandbox',
    '--disable-setuid-sandbox',
    '--disable-dev-shm-usage',  // 解决 Docker 环境共享内存不足
    '--max-old-space-size=4096'  // 增加内存限制
  ],
  timeout: 60000  // 增加启动超时
});

性能问题

问题:爬取大量页面时速度慢

解决方案

// 1. 使用同一个 browser 实例,复用连接
// 2. 禁用图片和 CSS 加载
await page.setRequestInterception(true);
page.on('request', req => {
  if (['image', 'stylesheet', 'font'].includes(req.resourceType()))
    req.abort();
  else
    req.continue();
});

// 3. 使用 chrome-headless-shell(更轻量)
const browser = await puppeteer.launch({
  headless: 'shell'  // 比默认 headless 更快
});

兼容性问题

问题:某些网站检测到 Puppeteer 并拒绝访问

解决方案

const browser = await puppeteer.launch({
  headless: false,  // 使用有头模式
  args: [
    '--disable-blink-features=AutomationControlled',  // 移除自动化特征
    '--user-agent="Mozilla/5.0 ..."'  // 自定义 UA
  ]
});

// 注入脚本隐藏 webdriver 特征
await page.evaluateOnNewDocument(() => {
  Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
  window.navigator.chrome = {runtime: {}};
});

六、总结

Puppeteer 作为 Google 官方维护的浏览器自动化库,凭借其简洁的 API、强大的功能和活跃的社区,已成为 Node.js 生态中浏览器自动化的首选方案。无论是做 E2E 测试、网页爬取,还是服务端渲染,Puppeteer 都能提供可靠的支持。

项目亮点总结:

  • ✅ TypeScript 编写,类型定义完善
  • ✅ 支持 Chrome 和 Firefox 双引擎
  • ✅ 完善的文档和示例
  • ✅ 活跃的社区和持续的维护(Google 团队)
  • ✅ 支持 MCP 协议,可与 AI Agent 集成

如果你正在寻找一个可靠的浏览器自动化工具,Puppeteer 绝对值得一试。项目 GitHub 地址:https://github.com/puppeteer/puppeteer


参考资料:

  • 官方文档:https://pptr.dev/
  • GitHub 仓库:https://github.com/puppeteer/puppeteer
  • Chrome DevTools Protocol:https://chromedevtools.github.io/devtools-protocol/