Puppeteer BrowserContext.targets():获取并处理浏览器上下文中所有活跃 Target
发布时间:2026/9/7 3:12:52 锦皓数字建站
:获取并处理浏览器上下文中所有活跃 Target`)
Puppeteer BrowserContext.targets()获取并处理浏览器上下文中所有活跃 Target【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteerBrowserContext.targets()是 Puppeteer 中浏览上下文BrowserContext上的一个同步方法用于一次性拿到当前上下文内所有活跃的Target页面、Web Worker、背景页等可调试对象。本篇以 Puppeteer 仓库中的 API 文档为骨架深入其 CDP 与 WebDriver BiDi 两套协议实现讲清targets()的签名语义、返回值构成、与pages()/waitForTarget()的协作关系帮助你在自动化脚本中正确枚举、过滤和等待上下文内的目标对象。方法签名与返回值根据 API 文档该方法的定义如下class BrowserContext { abstract targets(): Target[]; }功能获取当前浏览器上下文内所有活跃的 Target参数无返回值Target[]一个包含该上下文中全部活跃 Target 实例的数组同步返回不产生 Promise声明位置抽象声明 位于BrowserContext基类中具体行为由各协议后端CDP / BiDi实现类覆写。BrowserContext本身表示浏览器中相互隔离的用户环境启动浏览器后至少存在一个默认上下文其余可通过browser.createBrowserContext()创建在 Chrome 中所有非默认上下文均为 incognito 模式。每个上下文拥有独立的存储cookies/localStorage 等targets()正是以这个隔离边界为范围进行枚举的。什么是 Target理解targets()的返回值先要看 Target 抽象类它代表一个 CDP target即“任何可以被调试的对象”例如页面、frame 或 worker。Target 类型由TargetType枚举定义定义位置枚举值字面量含义PAGEpage普通页面BACKGROUND_PAGEbackground_page扩展/后台背景页SERVICE_WORKERservice_workerService WorkerSHARED_WORKERshared_workerShared WorkerBROWSERbrowser浏览器自身WEBVIEWwebviewWebViewOTHERother其他类型TABtab内部使用的 tab 目标每个 Target 实例提供了若干关键方法见 Target 类 与 实现源码type()返回TargetType是过滤targets()结果的首要依据url()返回目标当前 URLpage()当类型为page、webview或background_page时返回Page否则返回nullworker()当类型为service_worker或shared_worker时返回WebWorker否则返回nullasPage()强制将任意类型的 target 当作 page 处理适合处理other类型目标opener()返回打开当前 target 的上级 target顶层目标返回nullbrowserContext()/browser()返回所属上下文与浏览器可用于反向归属判断。典型用法是遍历并做类型分派const context browser.defaultBrowserContext(); for (const target of context.targets()) { if (target.type() page) { console.log(target.url()); } else if (target.type() service_worker) { const worker await target.worker(); // 处理 worker ... } }源码实现CDP 后端的过滤链在 CDP 实现中CdpBrowserContext.targets()的实现只有一行过滤逻辑override targets(): CdpTarget[] { return this.#browser.targets().filter(target { return target.browserContext() this; }); }即先从所属CdpBrowser拿到浏览器级全量 target再按“目标所属上下文 当前上下文”做引用相等过滤。这就解释了Browser.targets()与BrowserContext.targets()的边界关系前者覆盖所有上下文后者是前者的子集。而浏览器层的 CdpBrowser.targets() 还叠加了两道筛选条件override targets(): CdpTarget[] { return Array.from(this.#targetManager.getAvailableTargets().values()) .filter(target target._isTargetExposed() target._initializedDeferred.value() InitializationStatus.SUCCESS ); }从源码结构看只有同时满足“已被暴露_isTargetExposed”和“初始化成功InitializationStatus.SUCCESS”的目标才会出现在结果中。因此targets()返回的是一个稳定、已就绪的快照正在初始化中或尚未暴露的目标不会混入调用方无需再做初始化状态判断。源码实现BiDi 后端的目标集合在 WebDriver BiDi 后端中targets()的数据来源完全不同。BidiBrowserContext 内部维护了一张#targets映射表结构定义readonly #targets new Map BidiPage, [ BidiPageTarget, MapBidiFrame | BidiWebWorker, BidiFrameTarget | BidiWorkerTarget, ] (); override targets(): Target[] { return [...this.#targets.values()].flatMap(([target, frames]) { return [target, ...frames.values()]; }); }即“页面 → [页面 Target, {frame/worker → frame/worker Target}]”的结构targets()将其拍平为一维数组返回。这张表是随着页面事件动态维护的在#createPage中每当新浏览上下文出现时创建BidiPageTarget帧挂载FrameAttached时注册BidiFrameTargetworker 创建WorkerCreated时注册BidiWorkerTarget对应地TargetCreated、TargetChanged、TargetDestroyed事件会在创建、导航和销毁时通过trustedEmitter发出。BiDi 后端因此返回的 target 集合粒度更细——不仅包含页面目标还包含每个 frame 与 worker 对应的 target 对象。两种实现的差异提示了一点targets()的具体元素构成与协议后端相关跨后端编写脚本时尽量依赖type()、url()等抽象方法做判断而不是假设元素数量或类型分布。与 pages() 的关系pages 是 targets 的投影BrowserContext.pages()的文档说明“非可见页面如background_page不会出现在列表中可用Target.page自行查找”。在 CDP 实现中可以看到pages()正是对targets()的投影实现位置override async pages(includeAll false): PromisePage[] { const pages await Promise.all( this.targets() .filter(target { return ( target.type() page || ((target.type() other || includeAll) this.#browser._getIsPageTargetCallback()?.(target)) ); }) .map(target target.page()), ); return pages.filter(page !!page); }其规则是只保留type() page的目标外加经_getIsPageTargetCallback判定为页面性质的other目标includeAll为true时放宽随后调用target.page()并把返回null的条目剔除。因此当你需要拿到pages()遗漏的目标例如后台页、无法直接映射为Page的对象时回退到targets()asPage()是文档推荐的思路。配合 waitForTarget() 等待新目标出现targets()是同步快照对于“目标稍后才出现”的场景典型如window.open打开弹窗应使用同类的waitForTarget()async waitForTarget( predicate: (x: Target) boolean | Promiseboolean, options: WaitForTargetOptions {}, ): PromiseTarget { const {timeout: ms 30000} options; return await firstValueFrom( merge( fromEmitterEvent(this, BrowserContextEvent.TargetCreated), fromEmitterEvent(this, BrowserContextEvent.TargetChanged), from(this.targets()), ).pipe(filterAsync(predicate), raceWith(timeout(ms))), ); }从实现可以看到三个关键细节默认超时 30 秒timeout: ms 30000可通过options.timeout覆盖它把“TargetCreated事件流 TargetChanged事件流 当前targets()快照”合并为一个数据流也就是说已经存在且满足条件的目标会立即命中无需等待新事件支持同步或异步谓词filterAsync因此可以在谓词内调用target.page()等异步方法做条件判断。官方文档给出的示例是捕获window.open产生的新窗口 targetawait page.evaluate(() window.open(https://www.example.com/)); const newWindowTarget await context.waitForTarget( target target.url() https://www.example.com/, );仓库测试 test/src/target.test.ts 中有一个更完整的异步版本用Promise.all同时发起等待与打开动作谓词内通过target.page().then(...)比对 URL并在{timeout: 3000}下断言新 page 与otherPage不是同一实例——这正是waitForTarget的推荐写法。而 枚举场景的用例 则验证了browser.targets()中应同时存在about:blank的 page 目标与browser类型目标可作为targets()行为的对照基准。使用建议与边界作用域context.targets()只返回该上下文内的目标跨上下文枚举请使用browser.targets()Browser.targets 文档。快照语义方法同步返回数组快照不随后续页面打开/关闭而变化实时追踪请订阅 BrowserContextEvent 中的TargetCreated/TargetChanged/TargetDestroyed事件BiDi 与 CDP 后端均会发出。就绪保证在 CDP 后端中结果已过滤掉未暴露或未初始化成功的目标CdpBrowser.targetsBiDi 后端则随#targets映射实时增删。与页面列表的取舍拿Page对象用await context.pages()需要 worker、后台页或自定义过滤逻辑时用targets()遍历后按type()分派page()/worker()/asPage()。相关文件索引内容路径方法 API 文档docs/api/puppeteer.browsercontext.targets.mdTarget 类文档docs/api/puppeteer.target.md抽象声明与 waitForTargetpackages/puppeteer-core/src/api/BrowserContext.tsTarget 抽象类packages/puppeteer-core/src/api/Target.tsCDP 上下文实现packages/puppeteer-core/src/cdp/BrowserContext.tsCDP 浏览器实现packages/puppeteer-core/src/cdp/Browser.tsBiDi 上下文实现packages/puppeteer-core/src/bidi/BrowserContext.ts行为测试test/src/target.test.ts【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。