优先选XPath:当需按文本内容、父/兄弟关系定位,或使用函数(如count、contains)及轴(如following-sibling)时;否则CSS更简洁易维护。

用 xpath 还是 CSS 选择器 解析 HTML,取决于你要抓的数据结构、目标站点的稳定性,以及你是否需要处理属性、文本、兄弟节点等复杂定位——不是语法越短越好,而是哪一种在当前场景下更稳、更易维护。
什么时候必须用 xpath
CSS 选择器写起来快、可读性强,且在 立即学习“Python免费学习笔记(深入)”; 别在同一个项目里随意切换解析方式——尤其当 HTML 结构稍有变动时,CSS 和 xpath 对空格、换行、注释的敏感度不同,容易出现「一个能取到,另一个返回空」的情况。调试时先用浏览器开发者工具验证表达式有效性。 html = ' price_text = tree.xpath('//span[@class="price"]/text()')[0].strip() price_elem = tree.cssselect('span.price')
price_text_css = price_elem[0].text.strip() if price_elem else None 真正麻烦的从来不是写对一句 xpath 或 CSS,而是当页面改版、class 动态生成、文本被零宽字符干扰、或者 xpath 是唯一能直接按「文本内容」或「父/兄弟关系」精准定位的方案。比如页面里没有 class 或 id,只有“第 3 个 后面紧跟的 ”,CSS 就无能为力。
//td[text()="订单号"]/following-sibling::td[1] —— 定位指定文本后的相邻单元格//div[contains(@class, "price")]/text()[last()] —— 提取 class 含 price 的 div 中最后一段纯文本(绕过子标签)count(//ul/li) 或 string-length(//h1) —— 需要计算或字符串操作时,只能靠 xpath 函数什么时候优先选
CSS 选择器
BeautifulSoup(配合 lxml 或 html.parser)和 PyQuery 中支持良好。但注意:它不支持轴(如 following-sibling)、函数(如 contains()),也不能匹配文本节点本身。
div.product > h2.title —— 子元素关系清晰时,比 //div[@class="product"]/h2[@class="title"] 更简洁a[href^="https://example.com"] —— 属性前缀匹配,lxml 的 CSS 支持,但原生 BeautifulSoup(非 lxml)不支持伪类如 :nth-of-type(2)
input#search[name="q"][type="text"] —— 多属性叠加定位,直观且不易出错
lxml 下两者性能与兼容性差异lxml 对 xpath 和 CSS 都支持,但底层实现不同:xpath 编译后执行,CSS 会被转换成等价 xpath 再执行。实测中,简单 CSS 选择器(如 div.class)和对应 xpath(如 //div[@class="class"])性能几乎一致;但含函数或轴的 xpath 无法被 CSS 替代,强行改写会导致逻辑错误或漏数据。
etree.HTML(html).xpath(...) 时,确保字符串是合法 xpath 表达式,@ 不可省略([@id] ≠ [id])etree.HTML(html).cssselect(...) 仅在 lxml ≥ 4.0+ 可用,旧版本需用 cssutils 或退回到 BeautifulSouplxml.etree.XPathEvalError,大概率是引号嵌套错误或用了 CSS 语法(如 div:nth-child(2))当 xpath 用常见混用陷阱与调试建议
$x('//span[@class="price"]') 测试 xpath;$$('span.price') 测试 CSSlen(result) 比直接看 result[0].text 更安全,避免 IndexError
requests + lxml 拿不到,得换 selenium 或 playwright,此时 xpath 在自动化工具中仍是主流定位方式from lxml import etree
✅ 推荐:xpath 精准取 price 文本(无视前后空白)
⚠️ 注意:cssselect 返回的是 Element 对象列表,需再调 .text
里藏了真实数据时,你怎么快速判断该换哪种方式、要不要加 normalize-space()、甚至该不该放弃 HTML 解析直接正则捞——这些没法靠语法速查表解决,得靠多看源码、多试边界 case。











