CSS Selector 与 XPath 怎么写?HTML 元素、属性和文本节点测试指南
对比 CSS Selector 与 XPath 的定位能力,结合商品列表示例讲解类名、属性、层级、文本节点、稳定路径、安全预览和自动化维护。
打开配套工具 →前端调试、网页自动化和结构化数据提取都要先准确定位 DOM。CSS Selector 简洁,和浏览器样式规则、querySelectorAll() 一致;XPath 能选择属性、文本节点、祖先和复杂关系。二者没有绝对优劣,关键是选择最稳定、最容易维护的表达方式。
可以使用 CSS Selector / XPath 在线测试器 在浏览器本地粘贴 HTML。工具会显示命中数量、节点类型、文本、源码、CSS 路径和 XPath,并在隔离预览中高亮对应元素。
CSS Selector 适合哪些查询
假设商品结构是:
<article class="product featured" data-sku="SEAL-001">
<h2>海豹马克杯</h2>
<p class="price" data-currency="CNY">¥89</p>
<a href="/products/seal-cup">查看详情</a>
</article>常见查询包括:
.product /* 所有商品 */
.product > h2 /* 商品直属标题 */
.product:not(.sold-out) /* 排除售罄 */
[data-sku="SEAL-001"] /* 精确属性值 */
.product a[href] /* 带链接的 a 元素 */MDN querySelectorAll 文档说明它返回静态 NodeList。选择器必须是合法 CSS;id 或属性值含空格、冒号、引号等特殊字符时,需要使用正确转义,不能简单拼接用户输入。
子代空格和 > 不同。.product h2 会查找任意深度后代,.product > h2 只匹配直属子元素。页面改版增加包装层后,后者可能失效;前者虽然宽松,也可能误中嵌套推荐区。选择前应先明确结构约束。
XPath 怎样选择属性与文本节点
XPath 的常见形式是:
//article[contains(concat(' ', normalize-space(@class), ' '), ' product ')]
//article/@data-sku
//article//p[@class='price']/text()
count(//article[contains(@class, 'product')])// 表示任意后代,@data-sku 直接返回属性节点,text() 返回文本节点。count() 则返回数字,而不是节点集合。测试器会把数字、字符串和布尔结果显示为“标量”,这时没有可高亮元素是正常的。
MDN Document.evaluate 文档列出了 XPathResult 类型。使用迭代器读取节点时,如果在遍历过程中修改文档,迭代器可能失效;自动化脚本应先收集结果,再执行 DOM 修改。
XPath 里 contains(@class, 'product') 可能误中 product-old。严格判断类名时,应把空白规范化后在前后补空格,如示例中的 concat() 写法。若目标有稳定 data-* 属性,直接按属性值定位更清楚。
自动生成的完整路径为什么不够稳定
工具可以给出类似下面的路径:
html > body > main > article:nth-of-type(2) > h2/html/body[1]/main[1]/article[2]/h2[1]它们准确描述当前快照,但在列表前插入一个商品、增加包装层或调整排序后就会变化。因此完整路径适合检查和临时定位,不适合作为长期自动化的唯一依据。
稳定性通常按以下顺序考虑:
- 专门的
data-testid、data-qa或业务唯一 ID。 - 语义明确且长期存在的 id、name、role、aria-label。
- 业务属性,例如 SKU、订单号和固定链接模式。
- 稳定类名与局部结构组合。
nth-child、nth-of-type和绝对层级路径。
不要依赖构建工具生成的哈希类名,也不要只按按钮显示文本定位多语言页面。自动化测试应由产品代码提供稳定钩子,而不是让测试脚本猜 UI。
为什么文本匹配经常出现空白问题
HTML 文本可能被多个节点拆开:
<button>立即 <strong>购买</strong></button>CSS Selector 只能选择元素,不能直接按文本内容筛选。选中 button 后读取 textContent 会得到包含空白的组合文本。XPath 可以用 normalize-space():
//button[normalize-space(.)='立即 购买']真实页面还可能包含不可见字符、换行、非断行空格和动态价格。调试时应同时查看节点文本与 outerHTML,避免只看视觉截图。
粘贴陌生 HTML 时怎样保证安全
HTML 片段可能包含 script、iframe、表单、事件属性、远程图片和 CSS URL。直接写入当前页面会执行脚本或访问外部资源,甚至带出当前站点信息。
安全预览至少应做到:
- 解析为独立 Document,不注入主页面 DOM。
- 移除 script、iframe、object、embed 和事件属性。
- 清除 src、srcset、href、action 等联网属性。
- 使用没有
allow-scripts、allow-same-origin的 sandbox iframe。 - 添加限制网络、表单和嵌套页面的 Content Security Policy。
本工具按这个原则生成预览副本。选择器仍针对原始结构运行,因此清理动作不会改变匹配结果;被移除的危险节点可能出现在结果清单,但不会在预览执行。
排查“为什么匹配不到”的顺序
- 确认粘贴的是最终 HTML,而不是需要 JavaScript 运行后才生成内容的初始源码。
- 检查模式是否选成 CSS 或 XPath,二者语法不能混用。
- 从宽到窄测试:先查标签,再加类名、容器和属性。
- 检查大小写、命名空间、转义字符和引号。
- XPath 先测试
//tag,再逐步增加谓词。 - 命中过多时增加稳定容器或业务属性,不要立即使用很长的绝对路径。
- 把选择器放回目标浏览器、自动化框架或采集程序再验证一次。
选择器测试器能够证明表达式对当前 HTML 快照有效,但不能保证网页未来结构不变。长期使用时,要保留代表性样本、设置命中数量断言,并在页面发布后运行回归检查。