首页
/ Puppeteer Browser.targets() API 详解:枚举浏览器中全部活跃 Target 的原理与实战

Puppeteer Browser.targets() API 详解:枚举浏览器中全部活跃 Target 的原理与实战

2026-09-07 17:32:11作者:贡沫苏Truman

Browser.targets() 是 Puppeteer 中获取浏览器当前所有活跃调试目标(Target)的核心 API,它一次性返回跨全部 Browser Context 的 Target 列表,是构建多页面协调、Target 类型识别、后台页面与 Worker 监控等自动化场景的入口。本文基于 Puppeteer 仓库中的 API 文档与 packages/puppeteer-core 源码实现,完整讲解该方法的签名语义、底层筛选机制、Target 对象的可用方法,以及它与 pages()waitForTarget() 之间的配合方式。

方法签名与核心语义

Browser.targets() 的定义在 Puppeteer 的 API 参考文档 puppeteer.browser.targets.md 中:

class Browser {
  abstract targets(): Target[];
}

返回值: Target[]

该方法的行为语义有两点,直接来自官方文档与 Browser 抽象类 的 TSDoc 注释:

  1. 同步返回,无需 await:与大多数 Puppeteer API 不同,targets() 是一个纯同步方法,返回 Target[] 而非 Promise,调用时无需等待;

  2. 跨 Browser Context 聚合:当浏览器存在多个 Browser Context(例如通过 browser.createBrowserContext() 创建的隔离上下文)时,browser.targets() 会返回所有 Browser Context 中的全部 Target,而不是仅默认上下文的 Target。这一点在 Browser.targets() 的文档注释中被明确强调:

    In case of multiple browser contexts, this returns all targets in all browser contexts.

如果需要按上下文筛选,应使用粒度更细的 BrowserContext.targets()(定义见 BrowserContext.targets()),它只返回该上下文内的 Target。

Target 是什么:CDP 调试目标的抽象

Target 的概念源自 Chrome DevTools Protocol:在 CDP 中,一个 Target 是任何可被调试的实体,例如页面(page)、Service Worker、WebWorker,甚至浏览器进程本身。Puppeteer 的 Target 类是对这一概念的封装。需要注意的约束是:Target 的构造函数在源码中被标记为内部实现,第三方代码不应直接构造 Target 实例或创建其子类,只能通过 browser.targets()waitForTarget() 等 API 获取现成实例。

一个 Target 实例暴露了以下关键方法(详见 Target 类文档):

方法 用途
type() 识别 Target 的类型("page""service_worker""browser" 等)
url() 获取 Target 当前的 URL
page() 若 Target 类型为 "page""webview""background_page",返回对应的 Page 对象,否则返回 null
asPage() 强制把任意类型的 Target 当作页面处理,适合处理类型为 "other" 的特殊 CDP Target
worker() 若类型为 "service_worker""shared_worker",返回 WebWorker 对象,否则为 null
browser() / browserContext() 反向定位 Target 所属的浏览器 / 浏览器上下文
opener() 返回打开当前 Target 的 Target;顶层 Target 返回 null,可用于还原弹窗/跳转的层级关系
createCDPSession() 在该 Target 上创建一条 CDP 会话,执行更底层的协议命令

其中 type() 的返回类型 TargetType 是一个枚举,在 TargetType 文档 中定义,常见取值包括 "browser"(浏览器本体)、"page"(普通页面)、"background_page"(扩展后台页)、"service_worker" / "shared_worker"(Worker)、"other"(其他,例如部分 Tab 层级的对象)。判断 Target 类型、再据此选择 page() 还是 worker() 的访问路径,是遍历 Target 列表时的标准做法。

源码实现:哪些 Target 会被返回

targets() 的 CDP 后端实现在 CdpBrowser.targets()

override targets(): CdpTarget[] {
  return Array.from(
    this.#targetManager.getAvailableTargets().values(),
  ).filter(target => {
    return (
      target._isTargetExposed() &&
      target._initializedDeferred.value() === InitializationStatus.SUCCESS
    );
  });
}

从这段实现可以看出两个关键筛选条件:

  1. target._isTargetExposed():只有对 Puppeteer 用户“暴露”的 Target 才会被列出,部分内部 Target 被刻意隐藏;
  2. 初始化必须成功_initializedDeferred 的状态必须是 SUCCESS,即该 Target 完成 CDP 初始化握手之后才会出现在结果中。这意味着刚被 TargetCreated 事件通知、但尚未完成初始化的 Target 在瞬间调用 targets() 时可能还看不到——如果需要在“Target 出现”时精确等待,应使用 waitForTarget() 而不是轮询 targets()

此外,同一个方法内部也被 Puppeteer 复用于 browser.target() 的实现(CdpBrowser.target()):它就是在 targets() 结果中查找 type() === 'browser' 的那个条目,找不到时抛出 Browser target is not found。这说明 targets() 是浏览器级 Target 管理的事实数据源。

一个容易踩坑的细节来自 launchPWA() 的源码注释:PWA.launch 返回的 targetId 指向的是 Tab 层级的 Target,而 Tab Target 位于 Target 层级中页面的上一层,不通过 browser.targets() 暴露,因此代码需要借助 TargetManager 内部接口配合 waitForTarget() 来找到其子页面 Target。从源码结构看,可以推断 targets() 返回的是经过扁平化筛选后的“用户可见 Target 集合”,而非 CDP 协议中完整的原始 Target 树。

BiDi 后端(WebDriver BiDi 模式)在 BidiBrowser.targets() 中同样实现了该方法,但数据来源是各 Browser Context 的聚合,进一步印证了文档中“跨所有 Context 返回”的语义在两种协议后端下都成立。

实战示例

1. 枚举并分类所有 Target

const browser = await puppeteer.launch();
const targets = browser.targets();

for (const target of targets) {
  console.log(target.type(), target.url());
  switch (target.type()) {
    case 'page':
      // target.page() 返回 Page 实例
      break;
    case 'service_worker':
    case 'shared_worker':
      // target.worker() 返回 WebWorker 实例
      break;
  }
}

2. 与 pages() 的区别

browser.pages() 内部同样是遍历各 Browser Context(参见 Browser.pages()),但它只返回 type 为页面类且处于可见状态的 Page 对象,非可见页面(如 "background_page")不会列出。因此:

  • 只需要可见页面列表 → await browser.pages()
  • 需要 Worker、浏览器 Target、后台页等所有类型的调试目标 → browser.targets(),再逐个用 target.page() / target.worker() 向下转型。

3. 配合 waitForTarget 捕获新 Target

Browser.targets() 是快照式的,捕获“未来出现的 Target”应使用 waitForTarget(),它在 源码 中正是以 from(this.targets()) 作为初始候选集,再合并 TargetCreated / TargetChanged 事件流进行过滤。官方注释中给出的示例:

await page.evaluate(() => window.open('https://www.example.com/'));
const newWindowTarget = await browser.waitForTarget(
  target => target.url() === 'https://www.example.com/',
);

测试佐证

仓库测试目录中的 target.test.ts 覆盖了 Target 创建、类型识别、opener 关系等与 targets() 直接相关的行为验证,可作为上述语义的测试依据。运行测试前可参考 test/README.md 了解测试环境准备方式。

适用前提与限制

  • 本文描述的筛选行为基于当前仓库 packages/puppeteer-core 的 CDP 实现;BiDi 后端的数据聚合路径不同,但对外语义保持一致;
  • targets() 只返回已完成初始化且对用户暴露的 Target,刚创建尚未初始化完成的 Target 可能缺失,实时等待请用 waitForTarget()
  • Tab 层级等内部 Target 不出现在返回结果中(见 launchPWA 的源码注释),因此不要假设 targets() 与 CDP Target.getTargets 的原始输出完全一一对应。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

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