写抓取脚本时想取列表项,照着页面结构写了按 class 等号匹配的表达式,结果一条都抓不到。打开源码一看,那个 class 是 item active,多了个状态词。这类问题在 XPath 里特别常见,因为 class 是一串用空格分开的词,不是单个值。

等号是整串比对

用等号要求这一串正好相等,多一个空格、多一个词都不算。优势是准,结构固定的后台页面可以这么写。缺点是前端一加状态类就失效,改一次页面就要改一次脚本,维护成本高。

contains 好写但会误伤

contains 只判断是否包含子串,能匹配 item active,也能匹配 item-wrap 和 itemList。想要列表项却抓到一堆不相干的节点,多半是这个原因。元素少的时候看不出来,翻到第二页就乱了。

稳妥写法是前后补空格

在 class 前后各补一个空格,再按带空格的词去匹配,就不会误伤。normalize-space 顺手把多余空格压掉,前端多打两个空格也不怕。

//div[contains(concat(' ', normalize-space(@class), ' '), ' item ')]

多个类同时要求时,用 and 连两个条件,或者写两次 contains。真要图省事,CSS 选择器点 item 更短,lxml 的 cssselect 和 Scrapy 都支持,语义还和浏览器一致。

  • 路径别从根节点写死,页面一加包装层就断。
  • class 里带数字后缀的,考虑用 starts-with 而不是全匹配。
  • 抓之前先在浏览器控制台验证表达式,能省很多调试时间。
  • 遇到单引号嵌套,记得把外层引号换成另一种写法。

取舍看场景:结构稳定的内部页面用等号最省事,公开网站用补空格那版最抗改版。写之前先看一眼真实源码里的 class,别照着自己想象拼。