XPath 高级用法与常见问题

一、基础概念回顾

  1. XPath 是用于在 XML/HTML 文档中定位元素的语言。
  2. 基本语法:
    • / 表示从根节点开始查找。
    • // 表示从任意位置查找。
    • @attr 表示选择属性。
    • [条件] 用于筛选节点。
    • text() 提取节点文本。

二、常见问题及注意点

1. 使用位置定位

//*[@id="ratings-and-reviews"]/div[15]
  • [15] 表示取第 15 个 div。

  • 可以用 position() 函数替代:

    div[position()=15 or position()=16]
    

    优点:可以同时选择多个位置的元素,更灵活。

重点:位置是基于同级节点顺序的,如果结构变化可能导致索引错误。


2. 属性筛选

错误写法:

//*[@id="ratings-and-reviews"]/div[15]/div/div[1]/nav/ul/li[1]/a aria-label="Previous"

正确写法:

//*[@id="ratings-and-reviews"]/div[15]/div/div[1]/nav/ul/li[1]/a[@aria-label="Previous"]

重点

  • XPath 属性必须用 [@属性名="值"]
  • 可以与位置、文本条件联合使用。

3. 文本筛选

如果要选出文本为 $0 的节点:

//*[@id="ratings-and-reviews"]/div[15]/div/div[1]/nav/ul/li[1]/a[text()="$0"]
  • /text() 提取直接文本节点。
  • 如果要在条件里判断,可用 text()="$0"string() 方法。

4. 布尔判断与节点存在性

  • 检查节点是否存在:
count(//*[@id="ratings-and-reviews"]/div[15]/div/div[1]/nav/ul/li[1]/a) > 0
  • 检查 li[1] 存在但 a 不存在:
count(//*[@id="ratings-and-reviews"]/div[15]/div/div[1]/nav/ul/li[1]) > 0
and count(//*[@id="ratings-and-reviews"]/div[15]/div/div[1]/nav/ul/li[1]/a) = 0

重点

  • XPath 本身不能直接返回布尔值,需要用 count() 判断。
  • 可在 Python 中根据返回列表长度判断。

5. 使用 | 合并节点

错误示例:

//*[@id="ratings-and-reviews"]/div[position()=15 or position()=16]/div/div[1]/nav/ul/li[last()]/button|a[@aria-label="Next"]
  • 这里 | 优先级低,导致 a[@aria-label="Next"] 被当作全局选择,而不是受前面 div 限制。

正确示例:

//*[@id="ratings-and-reviews"]/div[position()=15 or position()=16]/div/div[1]/nav/ul/li[last()]/*[self::button or self::a[@aria-label="Next"]]

重点

  • 合并多个节点时,| 的优先级可能导致逻辑错误。
  • 用括号或 self:: 明确作用范围。

三、实用技巧总结

  1. 文本筛选:用 text()string(),注意空格。
  2. 位置筛选position() 可以选择多个索引。
  3. 属性筛选:用 [@attr="value"],可以与文本/位置联合。
  4. 布尔判断count() + 条件,适合判断节点存在性。
  5. 多节点合并:用 self:: 或加括号避免 | 优先级问题。
  6. 调试技巧
    • 可以先用 //a//*[@id="ratings-and-reviews"]//a 看有哪些节点,再精确定位。
    • 用 Python 的 lxml 或浏览器控制台测试 XPath 表达式。