Puppeteer AutofillData:浏览器自动填充数据载荷类型与 ElementHandle.autofill 实现全解
【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer
本文围绕 Puppeteer 的AutofillData类型展开:这是ElementHandle.autofill()方法接收的唯一数据载荷类型,用于驱动浏览器原生的自动填充(Autofill)能力。读完本文,你将完整掌握该类型两种变体(信用卡、地址)的字段定义与互斥约束、AutofillAddressField枚举支持的全部地址字段名,以及 CDP/BiDi 两种协议下Autofill.trigger的底层调用链,并拿到可直接运行的表单填充实战示例。
一、AutofillData 类型定义
AutofillData是定义在 packages/puppeteer-core/src/api/ElementHandle.ts 中的公开类型(@public),官方 API 文档见 docs/api/puppeteer.autofilldata.md。其完整签名如下:
export type AutofillData = | { creditCard: { number: string; name: string; expiryMonth: string; expiryYear: string; cvc: string; }; address?: never; } | { address: { fields: Array<{ name: AutofillAddressField | (string & Record<never, never>); value: string; }>; }; creditCard?: never; };从源码结构看,这是一个判别联合类型(discriminated union):一次autofill()调用只能走两个分支之一,要么传creditCard,要么传address,二者不可同时出现。
1.1 类型层面的互斥约束:?: never
两个分支中都出现了address?: never/creditCard?: never这种写法。这是 TypeScript 中实现“互斥可选字段”的惯用手法:
- 当对象带有
creditCard时,address属性要么不出现,要么其值必须是never——实际上就是不允许出现; - 反之,传了
address就不允许再带creditCard。
这样 TypeScript 编译器能在编译期直接拒绝{creditCard: {...}, address: {...}}这类同时包含两者的错误写法,把“一次填充只能选择一种数据源”这一协议约束固化到了类型系统里。
1.2 creditCard 变体:Autofill.CreditCard
creditCard分支对应 Chrome DevTools Protocol 中的Autofill.CreditCard结构(源码注释中的参考链接见 api/ElementHandle.ts),五个字段全部为必填字符串:
| 字段 | 类型 | 含义 |
|---|---|---|
number | string | 银行卡号,如'4444444444444444' |
name | string | 卡上姓名,如'John Smith' |
expiryMonth | string | 到期月份,如'01' |
expiryYear | string | 到期年份,如'2030' |
cvc | string | 安全码,如'123' |
注意月份、年份、CVC 都是string而非number,这与底层协议的数据格式一致,填写时应保持字符串形态(例如'01'而不是1)。
1.3 address 变体:Autofill.Address
address分支对应 CDP 的Autofill.Address结构,载荷是一个fields数组,每个元素为{name, value}二元组:
name:地址字段类型标识,取值为AutofillAddressField枚举成员,类型上通过AutofillAddressField | (string & Record<never, never>)保留了传入任意字符串的扩展能力(Chromium 的field_types.cc中定义了比枚举更完整的字段列表,见 源码注释),同时 IDE 仍会对枚举成员提供自动补全;value:该字段要填入的值。
二、AutofillAddressField:支持的地址字段名枚举
AutofillAddressField是一个const enum,定义在 api/ElementHandle.ts,API 文档见 docs/api/puppeteer.autofilladdressfield.md。完整枚举成员及字符串取值如下:
| 枚举成员 | 字符串取值 | 语义 |
|---|---|---|
NameFirst | "NAME_FIRST" | 名字(Given name) |
NameMiddle | "NAME_MIDDLE" | 中间名 |
NameLast | "NAME_LAST" | 姓氏 |
NameFull | "NAME_FULL" | 全名 |
EmailAddress | "EMAIL_ADDRESS" | 电子邮箱 |
PhoneHomeNumber | "PHONE_HOME_NUMBER" | 号码(不含城市区号) |
PhoneHomeCityAndNumber | "PHONE_HOME_CITY_AND_NUMBER" | 城市区号 + 号码 |
PhoneHomeWholeNumber | "PHONE_HOME_WHOLE_NUMBER" | 完整电话号码 |
AddressHomeLine1 | "ADDRESS_HOME_LINE1" | 地址行 1 |
AddressHomeLine2 | "ADDRESS_HOME_LINE2" | 地址行 2 |
AddressHomeStreetAddress | "ADDRESS_HOME_STREET_ADDRESS" | 街道地址 |
AddressHomeCity | "ADDRESS_HOME_CITY" | 城市 |
AddressHomeState | "ADDRESS_HOME_STATE" | 州/省 |
AddressHomeZip | "ADDRESS_HOME_ZIP" | 邮编 |
AddressHomeCountry | "ADDRESS_HOME_COUNTRY" | 国家/地区 |
由于是const enum,编译后枚举成员会被内联为字符串字面量,测试代码中既可以写AutofillAddressField.NameFull,也可以直接写'NAME_FULL'(name字段的联合类型允许纯字符串)。
三、autofill 的底层实现:从 JS 调用到 Autofill.trigger
AutofillData的消费方是ElementHandle上的抽象方法autofill(data: AutofillData): Promise<void>,声明于 api/ElementHandle.ts。其 JSDoc 明确说明了用途与限制:
If the element is a form input, you can use
ElementHandle.autofillto test if the form is compatible with the browser's autofill implementation. Throws an error if the form cannot be autofilled.Currently, Puppeteer supports auto-filling credit card information only and in Chrome in the new headless and headful modes only.
即:目标元素必须是表单输入;若该表单无法被浏览器自动填充(例如字段缺少autocomplete属性、布局不符合浏览器识别规则),调用会抛出错误。适用范围上,Chrome 新版 headless 与 headful 模式是文档注释声明的支持范围。
3.1 CDP 实现路径
CDP 连接下的具体实现见 cdp/ElementHandle.ts,调用链共三步:
- 发送
DOM.describeNode(以 JS 句柄的objectId为入参),拿到元素在浏览器内部的backendNodeId,即 CDP 意义上的fieldId; - 从当前
ElementHandle绑定帧上取frameId; - 发送
Autofill.trigger,载荷为:
await this.client.send('Autofill.trigger', { fieldId, // DOM.BackendNodeId frameId, // 触发填充所在的帧 ID card: data.creditCard, // AutofillData 的 creditCard 分支 address: data.address, // AutofillData 的 address 分支 });值得注意的是,card与address两个键是原样透传的:由于AutofillData的互斥约束,同一时刻必有一个为undefined,另一个携带数据,因此无需额外分支判断,与 CDPAutofill.trigger协议参数一一对应。填充动作由浏览器自身的 Autofill 引擎执行,Puppeteer 只负责把“哪一格(fieldId)+ 哪个帧(frameId)+ 什么数据”交给浏览器。
3.2 BiDi 实现路径
在 WebDriver BiDi 连接下,bidi/ElementHandle.ts 提供了同构实现:同样先经DOM.describeNode解析backendNodeId,再向frame.client发送Autofill.trigger,字段映射与 CDP 路径完全一致。两条实现路径保证了无论通过哪种协议连接浏览器,AutofillData的语义和行为都不变。
四、实战:信用卡与地址两种填充场景
仓库自带完整的端到端测试,位于 test/src/autofill.test.ts,配套测试页面为 test/assets/credit-card.html 与 test/assets/address.html,是最贴近真实用法的最小示例。
4.1 填充信用卡表单
测试页面 credit-card.html 是一个典型信用卡表单:姓名框#name、卡号框name="card_number"、月份框name="ccmonth"、年份框name="ccyear"。测试代码:
const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/credit-card.html'); using name = await page.waitForSelector('#name'); await name!.autofill({ creditCard: { number: '4444444444444444', name: 'John Smith', expiryMonth: '01', expiryYear: '2030', cvc: '123', }, }); // 断言所有 input 的值 expect( await page.evaluate(() => [...document.querySelectorAll('input')] .map(el => el.value) .join(','), ), ).toBe('John Smith,4444444444444444,01,2030,Submit');这里#name只是表单中任意一个可识别的输入框,浏览器 Autofill 引擎会基于字段的name/autocomplete等线索推断整个信用卡表单结构,把卡号、姓名、月份、年份一次性写入对应格子。断言结果证明四个输入框全部被正确填充。
4.2 填充地址表单
地址测试页面 address.html 中的输入框显式声明了autocomplete属性(name、street-address、address-level2、postal-code),这正是浏览器 Autofill 识别字段的依据。测试代码:
await page.goto(server.PREFIX + '/address.html'); using name = await page.waitForSelector('#name'); await name!.autofill({ address: { fields: [ {name: 'NAME_FULL', value: 'Jane Doe'}, {name: 'ADDRESS_HOME_STREET_ADDRESS', value: '123 Main St'}, {name: 'ADDRESS_HOME_CITY', value: 'Anytown'}, {name: 'ADDRESS_HOME_ZIP', value: '12345'}, ], }, }); // 断言结果为 'Jane Doe,123 Main St,Anytown,12345,Submit'这里fields数组中的name直接使用了第二节表格中的字符串取值;AutofillAddressField枚举同样可用。
4.3 使用要点小结
- 调用入口是
page.waitForSelector()/page.$()等返回的ElementHandle,而非Page对象本身; - 元素必须落在可被浏览器 Autofill 识别的表单内,否则按 JSDoc 约定会抛错,可在脚本中据此校验表单的 Autofill 兼容性;
- 一次调用只能选择
creditCard或address之一(类型系统强制); - 环境适用性以 api/ElementHandle.ts 中的注释 为准:Chrome(新版 headless 与 headful)是文档注释声明的支持范围,Firefox 与旧版 headless 不在其中。
五、参考资料索引
- 类型官方文档:docs/api/puppeteer.autofilldata.md
- 地址字段枚举文档:docs/api/puppeteer.autofilladdressfield.md
- 类型与枚举源码:packages/puppeteer-core/src/api/ElementHandle.ts
- CDP 实现:packages/puppeteer-core/src/cdp/ElementHandle.ts
- BiDi 实现:packages/puppeteer-core/src/bidi/ElementHandle.ts
- 端到端测试:test/src/autofill.test.ts
- 测试页面:test/assets/credit-card.html、test/assets/address.html
【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考