ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Puppeteer 如何用文本、ARIA、XPath 选择器与 Shadow DOM 组合定位元素

2026/9/9 23:33:26 拓冰建站 浏览量
Puppeteer 如何用文本、ARIA、XPath 选择器与 Shadow DOM 组合定位元素 Puppeteer 如何用文本、ARIA、XPath 选择器与 Shadow DOM 组合定位元素【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer写 Puppeteer 自动化脚本时经常会碰到 CSS 选择器搞不定的场景页面没有稳定的 class 名称、目标按钮只能靠可访问性语义role name来识别、元素藏在 Shadow DOM 内部。Puppeteer 所有接受选择器的 API 默认都接受 CSS 选择器但除此之外项目文档 docs/guides/page-interactions.md 还定义了一套以-p厂商前缀扩展的伪元素选择器语法可以用 XPath、文本、ARIA 属性查找元素并通过两个深组合符跨 Shadow DOM 查询——全部不需要执行额外的 JavaScript。准备安装并打开页面按 安装文档 安装后运行脚本如果包管理器拦截了安装脚本导致Could not find Chrome (ver. ...)报错需要手动执行npx puppeteer browsers installimport puppeteer from puppeteer; const browser await puppeteer.launch(); const page await browser.newPage(); await page.goto(YOUR_SITE); // 替换为你要自动化的目标站点 await browser.close();下面的所有定位写法都基于已打开的page对象。三种非 CSS 选择器语法XPath::-p-xpath(...)括号内直接写 XPath 表达式底层使用浏览器原生的Document.evaluate执行查询// 将 //h2 作为 XPath 表达式执行。 const element await page.waitForSelector(::-p-xpath(//h2));文本::-p-text(...)文本选择器选取包含给定文本的最小元素——即含有该文本的最深层元素而不选它的父元素父元素在技术上同样包含这段文本。文档明确说明它在打开状态的shadow root 内同样有效// 点击 div 元素内部、inner text 为 Checkout 的按钮。 await page.locator(div ::-p-text(Checkout)).click();注意转义规则搜索文本中如果包含 CSS 选择器语法字符如(、)需要反斜杠转义如果包含引号则用引号包裹参数并对引号本身转义// 文本为 Checkout (2 items) await page.locator(:scope ::-p-text(Checkout \\(2 items\\))).click(); // 文本为 He said: Hello await page.locator(:scope ::-p-text(He said: \\Hello\\)).click();ARIA::-p-aria(...)ARIA 选择器基于计算后的可访问名称和 role 查找元素。这些标签来自浏览器内部对 accessibility tree 的表示因此aria-labelledby等 ARIA 关系会在查询前被解析。当你不想依赖任何特定 DOM 结构或 DOM 属性时这类选择器最稳await page.locator(::-p-aria(Submit)).click(); await page.locator(::-p-aria([nameClick me][rolebutton])).click();如果写 ARIA 选择器前想先确认页面上实际存在的可访问名称和 role可以用page.accessibility.snapshot()获取整棵 accessibility tree 打印查看见 Accessibility.snapshot()。跨 Shadow DOM 定位与CSS 选择器无法进入 Shadow DOMPuppeteer 为此在 CSS 选择器语法中增加了两个组合符deep descendant对应 CSS 的后代组合符空格选择父元素内部任意深度的匹配元素。例如my-custom-element button选中my-custom-elementshadow hostshadow DOM 内的所有 button。deep child对应 CSS 的子代组合符只选父元素直接shadow root 内的匹配元素。// 两个选择器等价选中所有 shadow root 内匹配的 div。 await page.locator(pierce/div).click(); // 用 deep combinator 写同一查询。 await page.locator( div).click();文档推荐使用 deep combinator 而不是pierce/因为前者在组合不同选择器时更灵活。注意一条明确限制deep combinator 只对 CSS 选择器的第一层生效、且只作用于 open shadow root例如:is(div a)这种写法不工作。pierce/则只能在 前缀语法 中使用。与 CSS 组合并执行动作上述语法都可以和 CSS 选择器自由拼接这是本文的核心用法——外层用 CSS 缩小范围内层用自定义伪元素精确命中// CSS 部分div 文本部分Checkout组合。 await page.locator(div ::-p-text(Checkout)).click(); // 自定义选择器与 CSS 组合下节会说明 react-component 来自自定义 query handler。 await page.locator(.side-bar ::-p-react-component(MyComponent)).click();执行动作推荐用Locator它是文档推荐的选择并操作元素的方式会自动等待元素进入 DOM 且处于可操作状态。以点击为例Locator 在执行前自动检查元素在视口内ensures the element is in the viewport等待元素变为可见或隐藏等待元素变为可用enabled等待元素在连续两帧动画中 bounding box 保持稳定。超时默认继承页面的 timeout 设置也可以按 locator 单独设置超过时限仍找不到元素或不满足前置条件时会抛出TimeoutError// 3 秒后超时。 await page.locator(button).setTimeout(3000).click();如果不需要 Locator 的等待行为可以用更底层的 API。三者的区别API行为返回page.waitForSelector()等待选择器出现在页面已存在则立即返回超时抛出ElementHandle需要手动dispose()防止内存泄漏page.$()不等待立即查询第一个匹配元素的ElementHandle无匹配时解析为nullpage.$$()/page.$eval()/page.$$eval()不等待查询全部匹配 / 在匹配元素上执行函数全部ElementHandle或函数执行结果waitForSelector的visible和hidden选项默认都是falsetimeout默认 30000 毫秒传0禁用。文档同时说明page.click(selector)、page.type(selector)、page.hover(selector)这些页面级 API 出于向后兼容就是用waitForSelector实现的所以同样的选择器语法也适用于它们。结果验证定位是否正确按所用 API 判断Locator动作成功执行说明前置条件存在、可见、可用、稳定全部满足动作在超时时未执行并抛出TimeoutError说明元素未找到或前置条件不满足——检查方向是选择器本身而不是加 sleep。waitForSelector成功解析到非空ElementHandle即表示选择器已命中 DOM等待hidden: true且未找到时解析为null而不是报错。拿到 handle 用完后调用await element.dispose()。page.$()返回null表示当前时刻没有匹配元素。可选分支前缀语法与自定义选择器文档保留了旧的前缀语法${非CSS选择器名}/${选择器}但明确标注这是 legacy 写法且每次只能执行一个非 CSS 选择器不支持组合// 等价于 ::-p-text(My text)。 await page.locator(text/My text).click(); // 等价于 ::-p-xpath(//h2)。 await page.locator(xpath///h2).click(); // 等价于 ::-p-aria(My label)。 await page.locator(aria/My label).click();如果内置语法仍不够可以通过Puppeteer.registerCustomQueryHandler注册自定义伪元素。文档给出的示例基于[id]查询实现了一个react-component伪元素Puppeteer.registerCustomQueryHandler(react-component, { queryOne: (elementOrDocument, selector) { // 示例逻辑委托给 querySelector回调运行在页面上下文中。 return elementOrDocument.querySelector([id${CSS.escape(selector)}]); }, queryAll: (elementOrDocument, selector) { return elementOrDocument.querySelectorAll([id${CSS.escape(selector)}]); }, });注册后即可像内置语法一样写::-p-react-component(MyComponent)并与其他选择器组合使用。文档同时提醒依赖框架内部 API如 Vue 的__vnode存在风险这些内部实现随时可能变化。使用边界deep combinator/只对选择器第一层生效且只作用于 open shadow rootclosed shadow root 无法通过选择器进入。需要跨多个 shadow 层组合不同选择器时用 deep combinatorpierce/仅在旧前缀语法中可用。前缀语法text/、xpath/、aria/不能与其他选择器拼接组合场景一律用::-p-xxx伪元素写法。文本选择器的转义只针对搜索文本中的 CSS 语法字符和引号规则见上文示例不要自行扩展其他转义。定位写法本身没有更多分支选定-p伪元素或 deep combinator 语法后直接替换脚本中对应的选择器字符串用 Locator 的自动等待与超时机制确认命中即可。【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考