news 2026/9/5 16:04:36

Puppeteer Browser.version() 解析:获取浏览器名称与版本号的 API 用法与源码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Puppeteer Browser.version() 解析:获取浏览器名称与版本号的 API 用法与源码实现

Puppeteer Browser.version() 解析:获取浏览器名称与版本号的 API 用法与源码实现

【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer

Browser.version()是 Puppeteer 中用于获取当前已连接浏览器的名称和版本号字符串的实例方法,返回形如"Chrome/61.0.3153.0"Promise<string>。它在自动化测试中用于环境检测、浏览器兼容性判断、版本门控等功能,是理解 Puppeteer 底层 CDP / WebDriver BiDi 协议差异的关键入口。

方法签名与返回值

Browser.version()在 api/Browser.ts 中作为抽象方法声明:

class Browser { abstract version(): Promise<string>; }

方法无参数,返回一个Promise<string>,resolve 值为浏览器的名称加版本号字符串。根据运行环境和浏览器类型,返回值的格式存在差异:

运行环境返回值示例说明
无头 Chrome(旧 headless)"HeadlessChrome/61.0.3153.0"名称前缀为HeadlessChrome
有头 Chrome 或新 headless 模式"Chrome/61.0.3153.0"名称前缀为Chrome
Firefox"Firefox/116.0a1"名称前缀为Firefox

官方文档明确提示:返回值的格式可能随浏览器的未来版本发布而变化。因此,生产代码中不应将返回值与某个固定字符串做严格相等比较,而应通过解析前缀或版本号区间来判断特性。

CDP 协议的实现:调用Browser.getVersion

Chrome/Chromium 浏览器通过 Chrome DevTools Protocol(CDP)通信。在 cdp/Browser.ts 中,version()方法的具体实现如下:

// packages/puppeteer-core/src/cdp/Browser.ts override async version(): Promise<string> { const version = await this.#getVersion(); return version.product; }

它调用了私有方法#getVersion()(第 713-725 行),该方法内部通过Connection.send发送 CDP 命令Browser.getVersion

async #getVersion(): Promise<Protocol.Browser.GetVersionResponse> { if (!this.#version) { this.#version = Deferred.create<Protocol.Browser.GetVersionResponse>(); try { this.#version.resolve( await this.#connection.send('Browser.getVersion'), ); } catch (error) { this.#version.reject(error as Error); } } return await this.#version.valueOrThrow(); }

这段实现有两个关键设计点:

  1. 结果缓存#version是一个Deferred实例,首次调用时发起 CDP 请求,之后所有调用都复用缓存的 Promise,避免重复向浏览器端发送Browser.getVersion命令。
  2. 错误传播:若 CDP 请求失败(例如连接已断开),Deferred.reject会将错误传播给所有等待该 Promise 的调用方。

version()方法返回的是GetVersionResponse中的product字段。在旧版 headless 模式下,该字段值为"HeadlessChrome/xx.x.x.x";在新 headless(Chrome 112+ 默认)或有头模式下,则为"Chrome/xx.x.x.x"。这与userAgent()方法(第 685-688 行)返回userAgent字段的逻辑形成对照——两者共用同一个#getVersion()缓存,但提取的字段不同。

WebDriver BiDi 协议的实现

对于通过 WebDriver BiDi 协议连接的浏览器(如 Firefox 的 BiDi 模式),bidi/Browser.ts 中的实现直接拼接内部字段:

// packages/puppeteer-core/src/bidi/Browser.ts override async version(): Promise<string> { return `${this.#browserName}/${this.#browserVersion}`; }

#browserName#browserVersion在 BiDi 连接建立时,从session.new的 capabilities 响应中提取。这种实现不依赖额外的协议命令调用,而是在会话初始化阶段就已经拿到了版本信息,因此version()的调用几乎是零开销的。

实际用法示例

以下代码演示了如何启动浏览器并获取版本号:

import puppeteer from 'puppeteer'; const browser = await puppeteer.launch(); const version = await browser.version(); console.log(version); // 例如: "Chrome/131.0.6778.204" 或 "HeadlessChrome/131.0.6778.204" // 版本门控示例:判断是否为 Chrome 149+ const majorVersion = parseInt(version.match(/\d+/)?.[0] ?? '0', 10); if (majorVersion < 149) { console.warn('某些功能需要 Chrome 149 或更高版本'); } // 判断是否为 headless 模式 const isHeadless = version.startsWith('HeadlessChrome'); console.log(`当前运行模式: ${isHeadless ? '无头' : '有头'}`); await browser.close();

上述版本门控模式在 Puppeteer 源码中本身就有应用。在 cdp/Browser.ts 的create静态方法中,当用户传入allowlist选项时,会主动调用#getVersion()解析主版本号并检查是否满足最低要求:

if (allowlist) { const version = await browser.#getVersion(); const majorVersion = parseInt( version.product.match(/\d+/)?.[0] ?? '0', 10, ); if (majorVersion < 149) { throw new Error('The allowlist option require Chrome 149 or greater.'); } }

这说明version()的返回值在 Puppeteer 内部不仅用于用户侧检测,也是实现特性门控的基础设施。

userAgent()方法的区别

方法返回内容示例(Chrome)示例(Firefox)
browser.version()名称/版本号"Chrome/131.0.6778.204""Firefox/134.0"
browser.userAgent()完整 User-Agent 字符串"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36""Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0"

version()返回的是简洁的标识字符串,适合用于版本比较和程序逻辑判断;userAgent()返回的是完整的 HTTP User-Agent,适合用于需要精确匹配 UA 的场景(如反爬检测模拟)。两者在 CDP 实现中共用同一个Browser.getVersion命令的结果缓存(第 680-688 行),不会产生额外的协议调用开销。

测试验证

Puppeteer 仓库中的 test/src/browser.test.ts 包含了针对Browser.version()的专项测试:

describe('Browser.version', function () { it('should return version', async () => { const {browser} = await getTestState(); const version = await browser.version(); expect(version.length).toBeGreaterThan(0); expect(version.toLowerCase()).atLeastOneToContain(['firefox', 'chrome']); }); });

该测试验证了两个核心不变量:

  1. 返回值非空;
  2. 返回值(不区分大小写)必须包含firefoxchrome字样。

这确保了无论底层是 Chrome(CDP 或 BiDi)还是 Firefox,version()的返回值都遵循名称/版本的基本格式约定。

注意事项与最佳实践

  1. 不要在browser.close()之后调用:CDP 实现依赖活动连接,连接断开后调用将抛出错误。BiDi 实现不受此影响,因为它从会话初始化时就缓存了版本信息。
  2. 不要依赖固定格式:文档明确声明返回值格式可能随浏览器版本变化。建议通过正则提取数字部分做版本比较,而非字符串全等匹配。
  3. 区分 headless 与有头模式:旧版 headless Chrome 返回HeadlessChrome/...前缀,新 headless 和有头模式返回Chrome/...前缀。如果需要判断运行模式,应使用version.startsWith('Headless')而非!version.startsWith('Chrome')
  4. 版本缓存的语义:CDP 实现中版本信息在首次version()调用时被缓存,之后不会更新。由于浏览器进程在运行期间版本号不会变化,这是合理的设计。

相关文档

  • Browser 类完整 API
  • Browser.userAgent() 方法
  • Browser 类源码(抽象定义)
  • CDP Browser 实现
  • BiDi Browser 实现
  • Browser 测试用例

【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 16:03:55

用Grok Bot智能体团队开发Grok Bot:多智能体协作实践

这次我们来看一个比较有意思的玩法&#xff1a;用 Grok Bot 智能体团队来开发 Grok Bot 本身。这个思路来自 lingxi 的分享&#xff0c;本质上是把多智能体协作机制引入到代理编程场景里。也就是让一个由 Grok Bot 驱动的智能体团队&#xff0c;完成规划、编码、测试、审查、文…

作者头像 李华
网站建设 2026/9/5 16:02:31

MATLAB实现岩土弹塑性本构模型:从Drucker-Prager到修正剑桥模型

简介&#xff1a;本资源是一套面向土木工程、岩土力学及计算力学方向本科生与研究生的弹塑性本构模型MATLAB实现方案&#xff0c;聚焦Drucker-Prager、Cam-Clay及Modified Cam-Clay&#xff08;MCC&#xff09;三类经典模型&#xff0c;解决课程设计、期末大作业及毕业设计中本…

作者头像 李华
网站建设 2026/9/5 16:02:28

岩土弹塑性本构模型MATLAB实现:从Drucker-Prager到修正剑桥模型

简介&#xff1a;本资源是一套面向土木工程、岩土力学及计算力学方向本科生与研究生的弹塑性本构模型MATLAB实现方案&#xff0c;聚焦Drucker-Prager、Cam-Clay及Modified Cam-Clay&#xff08;MCC&#xff09;三类经典模型&#xff0c;解决课程设计、期末大作业及毕业设计中本…

作者头像 李华
网站建设 2026/9/5 16:00:49

提示词、规则、Skill与MCP详解:构建AI工程化协作链路

最近讨论 AI 工程化的时候&#xff0c;总绕不开四个词&#xff1a;提示词、Prompt、规则、Skill、MCP。很多同学会把它们当成同一件事去搜资料&#xff0c;结果越看越乱。有人以为“只要提示词写得好&#xff0c;其他概念都不需要”&#xff0c;也有人以为“MCP 是一种新模型”…

作者头像 李华