首页
/ Puppeteer Browser.cookies() 深度解析:从方法签名到 CDP/BiDi 底层实现的浏览器级 Cookie 读取

Puppeteer Browser.cookies() 深度解析:从方法签名到 CDP/BiDi 底层实现的浏览器级 Cookie 读取

2026-09-04 09:06:05作者:温艾琴Wonderful

本篇指南基于 Puppeteer 官方 API 文档中的 Browser.cookies() 方法展开,讲解如何获取默认浏览器上下文中的全部 Cookie,并结合开源仓库源码剖析该“快捷方法”在 CDP 与 WebDriver BiDi 两种协议下的真实调用链、Cookie 数据模型的字段语义,以及与页面级 page.cookies() 的边界差异。读完本文,你可以掌握浏览器级 Cookie 读取的完整实现路径,并在自动化测试、会话管理、爬虫状态保持等场景下正确选择 browser.cookies()browserContext.cookies()page.cookies()

方法定义与签名

Browser.cookies() 是 Puppeteer 提供的浏览器级(browser-level)Cookie API,其官方定义如下(见 docs/api/puppeteer.browser.cookies.md):

Returns all cookies in the default BrowserContext.(返回默认 BrowserContext 中的全部 Cookie)

方法签名与返回值:

class Browser {
  cookies(): Promise<Cookie[]>;
}
  • 返回值Promise<Cookie[]>,其中 Cookie 是描述单个 Cookie 对象的接口;
  • 文档 Remarks 说明:该方法本质上是 browser.defaultBrowserContext().cookies() 的快捷方式(shortcut)。

这一点在源码中得到逐字印证。在 packages/puppeteer-core/src/api/Browser.ts 中:

/**
 * Returns all cookies in the default {@link BrowserContext}.
 *
 * @remarks
 *
 * Shortcut for
 * {@link BrowserContext.cookies | browser.defaultBrowserContext().cookies()}.
 */
async cookies(): Promise<Cookie[]> {
  return await this.defaultBrowserContext().cookies();
}

也就是说,browser.cookies() 本身不包含任何协议逻辑,它只是把请求转发给默认上下文(defaultBrowserContext())的 BrowserContext.cookies() 抽象方法,由各协议的具体实现完成真正的查询。这也是理解整套浏览器级 Cookie API 的关键:Puppeteer 的 Browser 类对 Cookie 做“上下文级”管理,而真正的数据存取发生在 BrowserContext 层

cookies() 并列的另外三个浏览器级快捷方法(同在 api/Browser.ts 中定义)构成一组完整的读写删接口:

方法 作用 等价调用
browser.cookies() 读取默认上下文全部 Cookie browser.defaultBrowserContext().cookies()
browser.setCookie(...cookies) 向默认上下文写入 Cookie browser.defaultBrowserContext().setCookie(...)
browser.deleteCookie(...cookies) 删除指定 Cookie browser.defaultBrowserContext().deleteCookie(...)
browser.deleteMatchingCookies(...filters) 按过滤条件批量删除 browser.defaultBrowserContext().deleteMatchingCookies(...)

对应文档分别为 browser.setCookie()browser.deleteCookie()browser.deleteMatchingCookies()。当你需要隔离多个会话时,应改用 browser.createBrowserContext() 创建独立上下文,并直接在该上下文上调用这些方法,而不是使用浏览器级快捷方式。

底层实现:CDP 模式下的调用链

BrowserContext.cookies() 是一个抽象方法,Puppeteer 在 CDP(Chrome DevTools Protocol)和 WebDriver BiDi 两个后端各有一套实现。

CDP 后端

CDP 实现位于 packages/puppeteer-core/src/cdp/BrowserContext.ts

override async cookies(): Promise<Cookie[]> {
  const {cookies} = await this.#connection.send('Storage.getCookies', {
    browserContextId: this.#id,
  });
  return cookies.map(cookie => {
    return {
      ...cookie,
      partitionKey: cookie.partitionKey
        ? {
            sourceOrigin: cookie.partitionKey.topLevelSite,
            hasCrossSiteAncestor: cookie.partitionKey.hasCrossSiteAncestor,
          }
        : undefined,
    };
  });
}

从源码结构看,可以提炼出三个关键事实:

  1. 底层 CDP 命令是 Storage.getCookies,且请求体携带 browserContextId。这解释了为什么浏览器级 API 天然以“上下文”为粒度——CDP 的存储域(Storage domain)本身就是按浏览器上下文划分 Cookie 存储的。
  2. 返回结果会经过一次字段映射:CDP 原始的 partitionKey 使用 topLevelSite 字段名,而 Puppeteer 统一转换为自己的 CookiePartitionKey 结构 { sourceOrigin, hasCrossSiteAncestor }。这属于“Puppeteer 公共模型与协议私有模型之间的适配层”,调用方无需关心协议差异。
  3. partitionKey 的 Cookie 会被显式置为 undefined,保证返回结构一致,便于 JSON 序列化或断言比较。

同文件中的 setCookie()第 163-176 行)则发送 Storage.setCookies 命令,并在写入前把 Puppeteer 的 partitionKeysameSite 反向转换为 CDP 格式——这提示我们:读写两侧都存在模型转换逻辑,Cookie 的 sameSitepartitionKey 等字段是跨协议适配的重点

WebDriver BiDi 后端

BiDi 实现位于 packages/puppeteer-core/src/bidi/BrowserContext.ts

override async cookies(): Promise<Cookie[]> {
  const cookies = await this.userContext.getCookies();
  return cookies.map(cookie => {
    return bidiToPuppeteerCookie(cookie, true);
  });
}

与 CDP 直接发送命令不同,BiDi 后端通过 userContext.getCookies() 获取原始数据,再由 bidiToPuppeteerCookie 将 BiDi 的 Cookie 模型转换为 Puppeteer 统一的 Cookie 模型。两套实现对外表现一致:无论使用 protocol: 'cdp' 还是 protocol: 'webdriverBiDi' 启动浏览器,browser.cookies() 返回的都是同一形状的 Cookie[] 数组。

Cookie 数据模型:字段逐个解读

browser.cookies() 返回的每个元素都是 Cookie 接口对象。Cookie 继承自 CookieData(用于 setCookie() 的参数类型),并在其基础上补充了若干“只读描述”字段。

Cookie 扩展字段(Cookie 接口独有)

属性 类型 说明
expires number Cookie 过期时间,表示距离 UNIX 纪元的秒数;会话 Cookie 为 -1
partitionKeyOpaque boolean(可选) Cookie 的分区键是否为 opaque;仅 Chrome 支持
path string Cookie 的路径
secure boolean 是否为 Secure Cookie
session boolean 是否为会话 Cookie
size number Cookie 大小

CookieData 基础字段(继承而来)

CookieData 定义了在浏览器级 Cookie API 中设置 Cookie 所需的参数对象,其已确认包含的字段有:

属性 类型 说明
domain string Cookie 所属域名
name string Cookie 名称
expires number(可选) 过期时间;不设置则为会话 Cookie
httpOnly boolean(可选) 是否为 HttpOnly Cookie
partitionKey CookiePartitionKey | string(可选) 分区键,可用于第三方 Cookie 分区(CHIPS)相关场景

从 CDP 后端的 setCookie() 实现(cdp/BrowserContext.ts 第 163-176 行)中引用的字段还可以推断,完整的 Cookie 模型还支持 pathsecuresameSiteurlsourceSchemepriority 等属性——这些字段在写入时会被逐项转换并下发给浏览器,读取时(如 sourceSchemepriority)属于 Chrome 特有属性。若你要精确核对每个字段,建议直接查看仓库中 docs/api/puppeteer.cookiedata.mddocs/api/puppeteer.cookie.md 的完整属性表。

实战示例

下面的示例展示完整的“写入 → 读取 → 校验 → 清理”流程,全部使用浏览器级 API:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();

// 1. 向默认浏览器上下文写入 Cookie
await browser.setCookie({
  name: 'session_id',
  value: 'abc123',
  domain: 'example.com',
  path: '/',
  httpOnly: true,
  secure: true,
  sameSite: 'Lax',
});

// 2. 读取默认上下文中的全部 Cookie
const cookies = await browser.cookies();
for (const cookie of cookies) {
  console.log(cookie.name, cookie.domain, cookie.path, {
    httpOnly: cookie.httpOnly,
    secure: cookie.secure,
    session: cookie.session,
    size: cookie.size,
  });
}

// 3. 清理:按条件批量删除
await browser.deleteMatchingCookies({name: 'session_id'});
console.log(await browser.cookies()); // []

await browser.close();

几点使用说明:

  • browser.cookies() 不带 URL 参数,它返回默认上下文的“全量” Cookie;如果你只想看某个页面/域下的 Cookie,应使用页面级 API page.cookies(...urls)
  • 由于底层按 browserContextId 查询,通过 browser.createBrowserContext() 创建的隔离上下文中的 Cookie 不会出现在 browser.cookies() 的结果里,必须对具体上下文调用 context.cookies()
  • 仓库测试 test/src/browsercontext-cookies.test.ts 覆盖了空上下文返回 []、写入后断言字段(domain/expires/httpOnly/sameSite 等)、以及删除后清空等场景,可作为你编写断言的参考写法。

边界辨析:browser.cookies() 与 page.cookies()

Puppeteer 中“浏览器级”与“页面级”两套 Cookie API 经常被混淆,结合源码可以明确它们的差异:

维度 browser.cookies() page.cookies(...urls)
作用域 默认浏览器上下文的全部 Cookie 指定 URL(或当前页面 URL)匹配的 Cookie
参数 可选的 ...urls: string[]
CDP 命令 Storage.getCookies(按 browserContextId Network.getCookies(按 urls
实现位置 cdp/BrowserContext.ts#L146-L161 cdp/Page.ts#L701-L717

CDP 后端的页面级实现(packages/puppeteer-core/src/cdp/Page.ts)细节值得注意:

override async cookies(...urls: string[]): Promise<Cookie[]> {
  const originalCookies = (
    await this.#primaryTargetClient.send('Network.getCookies', {
      urls: urls.length ? urls : [this.url()],
    })
  ).cookies;

  const unsupportedCookieAttributes = ['sourcePort'];
  // ... 过滤不支持的属性后返回
}
  • 不传 URL 时默认查询当前页面 URL 对应的 Cookie;
  • 会主动剔除当前协议版本不支持的属性(如 sourcePort),保证返回模型稳定。

因此经验法则是:管理 Cookie(导入会话、批量清理、跨页面共享)用 browser.cookies() / browserContext.cookies();断言某个页面可见的 Cookie 用 page.cookies(url)。测试代码 test/src/cookies.test.tstest/src/defaultbrowsercontext.test.ts 分别验证了这两类 API 的行为。

测试用例与行为验证

仓库测试为 browser.cookies() 所属的上下文级 API 提供了行为基线(见 test/src/browsercontext-cookies.test.ts):

  • 新建隔离上下文后,context.cookies() 应返回 []——证明上下文间 Cookie 完全隔离;
  • 调用 context.setCookie() 后读取,断言 domainexpireshttpOnlysameSite 等字段与写入值一致;
  • 删除(deleteCookie / deleteMatchingCookies)后再次读取,长度归零。

这些用例与源码中的 Storage.getCookies 调用链相互印证,说明浏览器级 Cookie API 的语义边界就是 browserContextId,而不是“整个浏览器进程”。

总结

  • Browser.cookies() 的签名是 cookies(): Promise<Cookie[]>,语义为“返回默认浏览器上下文中的全部 Cookie”,源码上仅是 defaultBrowserContext().cookies() 的一行转发(api/Browser.ts#L691-L693);
  • CDP 后端通过 Storage.getCookies + browserContextId 查询并做 partitionKey 字段映射(cdp/BrowserContext.ts#L146-L161);BiDi 后端通过 userContext.getCookies() 获取后统一转换模型(bidi/BrowserContext.ts#L374-L379),两种协议对外返回同一 Cookie[] 结构;
  • 返回的 Cookie 对象在 CookieDatadomainnamehttpOnlypartitionKey 等)之上扩展了 expirespathsecuresessionsizepartitionKeyOpaque(仅 Chrome)等描述字段;
  • 需要精确到 URL/页面粒度的查询时,改用 page.cookies(...urls)Network.getCookies 命令);需要多会话隔离时,使用 createBrowserContext() 并在具体上下文上操作 Cookie;
  • 完整的 Cookie 使用指引可进一步参考仓库的 docs/guides/cookies.mdBrowserContext.cookies() 文档
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
503
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384