普通视图

发现新文章,点击刷新页面。
今天 — 2026年4月15日首页

CDP、Puppeteer 与无头浏览器:它们到底什么关系?

作者 Bacon
2026年4月14日 20:09

一分钟速览

概念 类比 角色
无头浏览器 一台"看不见屏幕"的电脑 运行环境 / 硬件
CDP 电脑的控制接口(USB / 串口协议) 通信协议
Puppeteer 你写的自动化脚本 / 遥控器 App 高层 SDK

1. 什么是无头浏览器(Headless Browser)

无头浏览器指没有图形界面 (GUI) 的浏览器,它拥有完整的浏览器引擎(HTML 解析、CSS 渲染、JS 执行),但不会在屏幕上绘制任何窗口。

chrome --headless --disable-gpu https://example.com

典型用途:

  • 自动化测试(截图、E2E 测试)
  • 爬虫 / 数据抓取
  • 服务端渲染 SSR 预渲染
  • 生成 PDF / 截图
  • Agent 的浏览器工具调用

常见实现:Chrome/Chromium headless、Firefox headless(历史上还有 PhantomJS,已停维护)。


2. 什么是 CDP(Chrome DevTools Protocol)

CDP 是 Chromium 团队定义的一套用于程序化控制浏览器的通信协议,本质是一套基于 WebSocket + JSON-RPC 的 API 集合。

你在 Chrome DevTools(F12)里做的一切——查看 DOM、网络请求、调试 JS、截图——背后都是 CDP 在驱动。

WS 消息示例(发送):
{
  "id": 1,
  "method": "Page.navigate",
  "params": { "url": "https://example.com" }
}

WS 消息示例(响应):
{
  "id": 1,
  "result": { "frameId": "...", "loaderId": "..." }
}

CDP 核心域(Domain):

Domain 能力
Page 页面导航、截图、PDF
Network 拦截请求、修改 Header
DOM 查询 / 操作 DOM 节点
Runtime 执行任意 JS、获取返回值
Input 模拟鼠标点击、键盘输入
Target 多标签页 / 多 iframe 管理

3. 什么是 Puppeteer

Puppeteer 是 Google 官方出品的 Node.js 库,它封装了 CDP 的所有细节,暴露出人类友好的 API。

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  const title = await page.title();
  console.log(title);
  await browser.close();
})();

一行 page.goto() 背后,Puppeteer 帮你发了十几条 CDP 命令。


4. 三者关系:分层架构图

graph TB
    subgraph USER["👨‍💻 开发者代码层"]
        A["你的 Node.js / Python 代码<br/>业务逻辑、Agent 工具调用"]
    end

    subgraph SDK["📦 高层 SDK 层"]
        B["Puppeteer"]
        B2["Playwright"]
        B3["selenium-webdriver<br/>(通过 WebDriver 协议)"]
    end

    subgraph PROTOCOL["🔌 协议层"]
        C["CDP\nChrome DevTools Protocol\nWebSocket + JSON-RPC"]
    end

    subgraph BROWSER["🌐 浏览器层"]
        D["Chrome / Chromium 内核"]
        E["无头模式\nHeadless"]
        F["有头模式\nHeaded(可见窗口)"]
    end

    A --> B
    A --> B2
    A --> B3
    B -->|"封装 CDP 调用"| C
    B2 -->|"封装 CDP 调用"| C
    B3 -->|"WebDriver 协议\n(另一套协议)"| D
    C -->|"WebSocket 通信"| D
    D --> E
    D --> F

    style USER fill:#dbeafe,stroke:#3b82f6
    style SDK fill:#d1fae5,stroke:#10b981
    style PROTOCOL fill:#fef3c7,stroke:#f59e0b
    style BROWSER fill:#fce7f3,stroke:#ec4899

层级关系: 无头浏览器是运行环境,CDP 是控制协议,Puppeteer 是对 CDP 的高层封装。


5. 一次页面访问的时序图

page.goto('https://example.com') 为例,看看底层发生了什么。

sequenceDiagram
    autonumber
    participant User as 开发者代码
    participant PP as Puppeteer
    participant WS as WebSocket 连接
    participant CDP as CDP 协议层
    participant Chrome as Chrome (无头)
    participant Net as 网络 / DNS

    User->>PP: page.goto('https://example.com')
    PP->>PP: 内部构建 CDP 命令

    PP->>WS: 发送 Page.navigate 消息
    WS->>CDP: JSON-RPC: { method: "Page.navigate", params: {url} }
    CDP->>Chrome: 触发导航

    Chrome->>Net: DNS 解析 + TCP 握手 + TLS
    Net-->>Chrome: 建立连接
    Chrome->>Net: 发送 HTTP GET 请求
    Net-->>Chrome: 返回 HTML 响应

    Chrome->>Chrome: HTML 解析 → DOM 树
    Chrome->>Chrome: CSS 解析 → CSSOM
    Chrome->>Chrome: JS 执行(同步脚本)
    Chrome->>Chrome: 触发 DOMContentLoaded

    CDP-->>WS: 事件推送: Page.loadEventFired
    WS-->>PP: 接收事件,Promise resolve
    PP-->>User: goto() 完成,返回 Response

6. CDP 连接建立时序图

Puppeteer launch() 时,如何与 Chrome 建立 CDP 连接。

sequenceDiagram
    autonumber
    participant PP as Puppeteer
    participant OS as 操作系统
    participant Chrome as Chrome 进程
    participant WS as WebSocket

    PP->>OS: 启动子进程: chrome --headless --remote-debugging-port=9222
    OS->>Chrome: 创建 Chrome 进程
    Chrome-->>OS: 监听 9222 端口,打印 WS 调试地址

    PP->>Chrome: HTTP GET /json/version
    Chrome-->>PP: 返回 { webSocketDebuggerUrl: "ws://localhost:9222/..." }

    PP->>WS: 建立 WebSocket 连接到调试地址
    WS-->>PP: 连接建立成功

    PP->>WS: 发送 Target.getTargets
    WS-->>PP: 返回已有标签页列表

    PP->>WS: 发送 Target.createTarget(新建标签页)
    WS-->>PP: 返回 targetId

    PP-->>PP: 封装为 Page 对象,供用户使用

7. 核心能力对比

quadrantChart
    title 浏览器自动化工具能力对比
    x-axis 学习曲线低 --> 学习曲线高
    y-axis 能力弱 --> 能力强
    quadrant-1 专家工具
    quadrant-2 首选工具
    quadrant-3 入门工具
    quadrant-4 高风险区
    Puppeteer: [0.35, 0.72]
    Playwright: [0.40, 0.88]
    CDP 原生: [0.80, 0.95]
    Selenium: [0.55, 0.55]
    PhantomJS: [0.30, 0.30]

8. Puppeteer vs 直接用 CDP

flowchart LR
    subgraph RAW["直接使用 CDP(原始方式)"]
        R1["手动管理 WebSocket"]
        R2["手动序列化 JSON 命令"]
        R3["手动等待事件"]
        R4["手动管理多标签页"]
        R5["需要熟记每个 Domain 命令"]
        R1 --> R2 --> R3 --> R4 --> R5
    end

    subgraph PPT["使用 Puppeteer(推荐)"]
        P1["puppeteer.launch()"]
        P2["browser.newPage()"]
        P3["page.goto(url)"]
        P4["page.click(selector)"]
        P5["page.screenshot()"]
        P1 --> P2 --> P3 --> P4 --> P5
    end

    RAW -- "Puppeteer 帮你封装了这些" --> PPT

9. 典型使用场景流程图

flowchart TD
    Start([需要自动化浏览器?]) --> Q1{是否需要\n真实浏览器渲染?}

    Q1 -- 否 --> Axios["使用 axios / fetch\n直接 HTTP 请求更简单"]
    Q1 -- 是 --> Q2{是否需要\n可见界面调试?}

    Q2 -- 是,开发阶段 --> Headed["headless: false\n有头模式,肉眼观察"]
    Q2 -- 否,生产环境 --> Headless["headless: true\n无头模式,服务端运行"]

    Headed --> Q3{用哪个库?}
    Headless --> Q3

    Q3 -- 简单任务 --> Puppeteer2["Puppeteer\n(Google 维护,API 简洁)"]
    Q3 -- 多浏览器兼容 --> Playwright2["Playwright\n(微软维护,支持 Firefox/Safari)"]
    Q3 -- 精细控制 --> CDP2["直接操作 CDP\n(需要深度定制时使用)"]

    Puppeteer2 --> Done["完成自动化任务 🎉"]
    Playwright2 --> Done
    CDP2 --> Done

10. 生态关系图

graph LR
    subgraph Google["Google 生态"]
        Chromium["Chromium 开源浏览器"]
        CDP["CDP 协议"]
        Puppeteer3["Puppeteer"]
        Chromium --> CDP
        CDP --> Puppeteer3
    end

    subgraph Microsoft["Microsoft 生态"]
        Playwright3["Playwright"]
        Playwright3 -->|"复用 CDP"| CDP
        Playwright3 -->|"Firefox Protocol"| FF["Firefox"]
        Playwright3 -->|"WebKit Protocol"| Safari["WebKit/Safari"]
    end

    subgraph W3C["W3C 标准"]
        WebDriver["WebDriver 协议\n(W3C 标准)"]
        Selenium3["Selenium"]
        WebDriver --> Selenium3
    end

    subgraph Agent["AI Agent 工具"]
        BrowserUse["browser-use"]
        LangChain["LangChain Browser Tool"]
        BrowserUse -->|"底层使用"| Playwright3
        LangChain -->|"底层使用"| Puppeteer3
    end

    style Google fill:#e0f2fe
    style Microsoft fill:#e8f5e9
    style W3C fill:#fff8e1
    style Agent fill:#f3e5f5

11. 一句话总结

无头浏览器  是一台"无屏幕的 Chrome"
     ↑
    CDP     是它暴露的"远程控制接口(协议)"
     ↑
 Puppeteer  是对 CDP 的"人性化封装库"
     ↑
 你的代码   调用 Puppeteer 实现自动化 / AI Agent 工具

12. 常见误区澄清

误区 正确理解
Puppeteer = 无头浏览器 ❌ Puppeteer 是库,无头浏览器是 Chrome
无头模式性能更好 ✅ 省去 GPU 渲染管线,内存和 CPU 更低
CDP 只有 Puppeteer 能用 ❌ Playwright、DevTools、各种调试工具都用 CDP
Headless Chrome 和普通 Chrome 行为不同 ⚠️ 部分 CSS / JS 行为有细微差异,需测试覆盖
Puppeteer 只能跑 Chrome ✅ 是的(官方支持 Chromium 和 Edge),跨浏览器用 Playwright

参考资料

❌
❌