首页
/ Puppeteer 的 BrowserContext.pages():列出隔离浏览上下文中的所有 Page 对象

Puppeteer 的 BrowserContext.pages():列出隔离浏览上下文中的所有 Page 对象

2026-09-04 23:04:54作者:邬祺芯Juliet

在 Puppeteer 中,BrowserContext.pages() 用于获取某个隔离浏览上下文(browser context)内当前所有打开的 Page 实例。它回答了一个自动化场景中的高频问题:"这个隔离环境里现在到底有哪些标签页?"——例如做多账号并行采集时需要遍历各自独立的上下文,或在关闭上下文前批量清理页面。本文基于 Puppeteer 官方 API 文档 BrowserContext.pages() 条目,结合 packages/puppeteer-core/src/api/BrowserContext.ts 及 CDP/BiDi 两套实现的源码,讲清该方法的签名、参数语义、过滤规则与底层调用链。

API 签名与参数说明

官方文档给出的方法签名为:

class BrowserContext {
  abstract pages(includeAll?: boolean): Promise<Page[]>;
}

对应源码定义位于 packages/puppeteer-core/src/api/BrowserContext.ts

/**
 * Gets a list of all open {@link Page | pages} inside this
 * {@link BrowserContext | browser context}.
 *
 * @param includeAll - experimental, setting to true includes all kinds of pages.
 *
 * @remarks Non-visible {@link Page | pages}, such as `"background_page"`,
 * will not be listed here. You can find them using {@link Target.page}.
 */
abstract pages(includeAll?: boolean): Promise<Page[]>;
参数 类型 说明
includeAll boolean(可选) 实验性参数。设置为 true 时纳入更多"页面类"目标

返回值Promise<Page[]>,解析为该上下文内所有已打开页面的数组。

两个关键注意事项(文档 Remarks 与源码注释一致):

  1. 默认返回的是"可见页面"。像 "background_page" 这类非可见页面不会出现在结果中;
  2. 需要查找这类隐藏页面时,应改用 Target.page()(即先拿到目标,再主动尝试取页面),而不是依赖 pages() 的默认过滤。

典型用法

BrowserContext 通常通过 browser.createBrowserContext() 创建,pages() 常与其配合使用来盘点上下文内的页面:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
// 创建一个隔离的浏览器上下文(在 Chrome 中等价于一次隐身会话)
const context = await browser.createBrowserContext();

const page1 = await context.newPage();
const page2 = await context.newPage();
await page1.goto('https://example.com/');
await page2.goto('https://example.org/');

// 列出该上下文内所有页面
const pages = await context.pages();
console.log(pages.length); // 2
console.log(pages.map(p => p.url()));

// 任务结束后关闭上下文会连带关闭其中的所有页面
await context.close();

pages() 形成对照的还有 Browser.pages():它会遍历 browser.browserContexts(),对每个上下文分别调用 context.pages(includeAll) 后拍平合并,返回所有上下文内的页面:

async pages(includeAll = false): Promise<Page[]> {
  const contextPages = await Promise.all(
    this.browserContexts().map(context => {
      return context.pages(includeAll);
    }),
  );
  // Flatten array.
  return contextPages.reduce((acc, x) => {
    return acc.concat(x);
  }, []);
}

因此 browser.pages() 可视为 context.pages() 的全局聚合版本。仓库测试 test/src/browsercontext.test.ts 也验证了这一行为:在主上下文新建页面后,browser.pages()context.pages() 的长度分别按预期增长;再新建一个独立上下文时,旧上下文的 pages() 只统计自己的页面。

底层实现:CDP 通道如何过滤页面

pages() 在抽象基类中只是声明,真正逻辑在传输层实现里。CDP 通道的实现位于 packages/puppeteer-core/src/cdp/BrowserContext.ts

override async pages(includeAll = false): Promise<Page[]> {
  const pages = await Promise.all(
    this.targets()
      .filter(target => {
        return (
          target.type() === 'page' ||
          ((target.type() === 'other' || includeAll) &&
            this.#browser._getIsPageTargetCallback()?.(target))
        );
      })
      .map(target => {
        return target.page();
      }),
  );
  return pages.filter(page => {
    return !!page;
  });
}

调用链可以拆成三步:

  1. 取目标集合this.targets() 先过滤出属于当前上下文的目标。同一文件的 targets() 实现就是 this.#browser.targets().filter(target => target.browserContext() === this),即按"目标归属的 browser context 是否为本实例"做隔离——这正是 pages() 结果不会串到其他上下文的原因;
  2. 按类型过滤:保留 target.type() === 'page' 的目标;对于类型为 'other'(或开启 includeAll 的其他类型)的目标,则委托给浏览器级的"是否页面目标"回调做二次判断;
  3. 转换为 Page 对象:对幸存目标逐个调用 target.page(),最后用 pages.filter(page => !!page) 剔除无法解析为 Page 的目标(target.page() 对非页面目标可能返回 undefined)。

那个二次判断回调的默认实现在 packages/puppeteer-core/src/cdp/Browser.ts

#setIsPageTargetCallback(isPageTargetCallback?: IsPageTargetCallback): void {
  this.#isPageTargetCallback =
    isPageTargetCallback ||
    ((target: Target): boolean => {
      return (
        target.type() === 'page' ||
        target.type() === 'background_page' ||
        target.type() === 'webview' ||
        (this.#handleDevToolsAsPage &&
          target.type() === 'other' &&
          isDevToolsPageTarget(target.url()))
      );
    });
}

从源码结构看,默认回调覆盖四类目标:pagebackground_pagewebview,以及在 handleDevToolsAsPage 开启时 URL 判定为 DevTools 的 other 目标。这解释了文档 Remarks 的措辞:background_page 等类型能进入候选集,但 target.page() 最终能否解析出 Page 实例、以及默认过滤条件的组合,决定了 pages() 实际返回的集合;要显式定位这类隐藏页面,文档给出的正路仍是通过 Target 对象调用 Target.page()

BiDi 通道的实现差异

在 WebDriver BiDi 通道下,packages/puppeteer-core/src/bidi/BrowserContext.ts 的实现完全不同:

override async pages(_includeAll = false): Promise<BidiPage[]> {
  return [...this.userContext.browsingContexts].map(context => {
    return this.#pages.get(context)!;
  });
}

可以直接观察到一个差异:BiDi 实现把 includeAll 参数下划线化(_includeAll),即当前实现中该参数并不参与过滤逻辑,而是直接枚举底层 userContext.browsingContexts 中注册的 browsing context,并从 #pages 映射表取对应 BidiPage。这与 CDP 实现按目标类型过滤的思路不同——从源码结构看,BiDi 侧的"页面"概念以 browsing context 注册表为准,includeAll 目前仅是保持签名一致的占位。使用时应注意:includeAll 被文档标注为实验性参数,其行为在不同通道之间可能存在差异,生产代码不宜对其做强依赖。

小结

  • BrowserContext.pages(includeAll?) 返回当前隔离上下文内所有已打开页面的 Promise<Page[]>,是 BrowserContext 上盘点页面的标准入口;
  • 默认结果不含 "background_page" 等不可见页面,需要时用 Target.page() 主动查找(见 BrowserContext.pages() 文档);
  • CDP 实现通过 targets() 归属过滤 + 目标类型过滤 + target.page() 解析三步得到结果,includeAll 会放宽类型过滤条件;
  • browser.pages() 是对所有上下文 context.pages(includeAll) 结果的拍平聚合,适合跨上下文的整体巡检。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
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
983
503
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384