kp-008

XPath 与选择器进阶

核心 ≈ 25 分钟 XPathCSS选择器parsellxml定位

前置知识

本文基于模型知识整理,建议核对官方文档(见 参考资料)。

一句话定义

XPath 是以路径表达式在 XML/HTML 树上定位节点的语言,具备条件过滤、函数计算与轴导航能力,是 CSS 选择器覆盖不了复杂场景时的进阶武器。

为什么重要

「取『价格』文本里含 ¥ 的那个元素」「按 class 前缀匹配」「向上找父容器再取兄弟字段」——这些 CSS 选择器做不到或很别扭的操作,XPath 一句搞定。Scrapy 的解析器 parsel 同时支持两者,XPath 是框架时代的通用语。

前置知识

kp-003、kp-007。

核心概念

  • 路径轴://(任意后代)、/(直接子级)、..(父级)、following-sibling / preceding-sibling。
  • 谓词:[n](第 n 个,从 1 开始)、[@attr='v']、[last()]。
  • 常用函数:contains()、starts-with()、text()、normalize-space()。
  • parsel:Scrapy 团队的独立选择器库,.css() 与 .xpath() 可混用接力。

原理与机制

表达式速查与 CSS 对照:

//article[@class="product_pod"]        ≙ article.product_pod      单元定位
//article//h3/a/@title                 ≙ article h3 a             取属性
//p[contains(@class,"price")]          ≙ p[class*="price"]        模糊匹配
//div[.//span[@class="stock"]]         ≙(CSS 难以表达)          按子孙条件筛容器
//h2/../ul/li[1]                       ≙(CSS 无法向上)          向上取兄弟

parsel 接力(提取函数返回 SelectorList,可继续 .xpath()/.css()):

from parsel import Selector

sel = Selector(html=html)
for pod in sel.xpath('//article[@class="product_pod"]'):
    title = pod.xpath('.//h3/a/@title').get()        # 相对路径必须以 . 开头
    price = pod.xpath('.//p[contains(@class,"price")]/text()').get()
    print(title, price)

高频坑:相对定位忘写 .。 pod.xpath('//h3/a') 里的 // 是从全文根开始找,会重复命中全页所有节点;单元内必须写 .//h3/a。

实例或案例

某列表页价格元素 class 是动态哈希(price_3f2a):CSS 的 [class*="price"] 可用但易误伤(reprice_x 也命中);XPath 的 //span[starts-with(@class,"price_")] 更精准。经验法则:前缀匹配用 starts-with,包含匹配再考虑 contains。

常见误区

  • 误区一:把 [1] 当成从 0 开始。 XPath 下标从 1 开始;//li[1] 是每个父节点下的第一个 li,不是全文档第一个(全文档第一是 (//li)[1])。
  • 误区二:text() 总返回单值。 它返回节点列表,常因标签内有换行出现多个值;规范做法是 normalize-space() 或取 .get()。
  • 误区三:能用 CSS 就别学 XPath。 反之:复杂条件与向上导航只有 XPath 能表达,值得投入。

自测题

  1. .//a 与 //a 在循环体内的区别?

答:.//a 在当前节点内相对查找;//a 从文档根全局查找,循环里会重复命中。

  1. 如何定位「包含 class 含 stock 的子孙 span 的 div」?

答://div[.//span[contains(@class,"stock")]]。

  1. XPath 谓词下标从几开始?//li[1] 与 (//li)[1] 差异?

答:从 1 开始;前者是每个父容器各自的第一个 li,后者是全文档第一个 li 节点。

与其他知识点的关系

kp-018 的 Scrapy Spider 内部用的就是 parsel;kp-012 渲染后的 DOM 同样可用 XPath 定位。

延伸阅读

MDN「XPath:Introduction」;parsel 官方文档(含 CSS/XPath 混用示例)。

相关知识点

学习进度