
我们从本质讲起:XPath到底是什么?接着拆解基础语法的每一个关键——节点类型、路径表达式、谓词怎么用,帮你搭好完整框架;再用“爬取电商商品价格”“解析API XML数据”这样的真实场景,让你把语法变成“拿起来就能用的技能”;最后还会解锁高级技巧:轴方法定位“相邻节点”、多条件组合精准抓数据、动态页面的XPath应对……
不管你是刚入门的新手,还是想解决复杂问题的老手,看完这篇,你就能真正“吃透”XPath,再也不用为“找不到节点”发愁,下次遇到数据定位,直接用XPath“一击即中”!
你有没有过这种情况?爬电商数据时写的XPath老抓错,解析XML时找不到节点,或者页面结构一变,之前的表达式就“失效”了?去年帮做美食博客的朋友爬菜谱,他用CSS选择器抓了一堆广告标题,我换了条XPath,瞬间就把正菜谱名精准揪出来——不是他笨,是没摸透XPath的“底层逻辑”。今天这篇就把XPath的“导航密码+实战技巧”一次性说透,不管你是爬数据还是解析文件,看完就能直接用。
先搞懂XPath的“底层逻辑”:不是难,是你没找对“打开方式”
很多人觉得XPath抽象,其实它的本质特别简单——就是给结构化数据写“定位地址”的语言。就像你给朋友发定位,得说“XX路XX小区3栋2单元501”,XPath就是给数据写这样的“精准导航”。比如你要从淘宝页面抓商品名称,XPath会告诉你:“找所有class叫‘product-item’的div,再找里面的h3标签,取它的文本内容”。
我之前帮做电商调研的朋友爬数据,他一开始用绝对路径/HTML/body/div[3]/div[2]/h3
,结果网站加了个导航栏,路径变成/HTML/body/header/div[3]/div[2]/h3
,之前的表达式直接废了。后来我让他换相对路径//div[@class='product-item']//h3/text()
,就算页面加了10个广告层,也能精准抓到商品名——这就是XPath的优势:能穿透复杂层级,稳定性远高于CSS选择器。
那XPath的基础语法到底要怎么记?其实就三类核心内容,结合例子讲,你5分钟就能懂:
XPath里的“节点”,就是数据的“小方块”,主要有3种,用淘宝商品页面的例子给你掰碎了讲:
,是数据的“容器”,像商品的“包装盒”;
属性节点:比如@class="product-item"
,是元素的“身份证”,用来区分不同类型的节点;
文本节点:比如
番茄火锅底料
里的“番茄火锅底料”,是你最终要抓的“内容”。
举个实际的例子:淘宝商品的HTML结构大概是这样的:
如果你要抓商品名称,XPath就是//div[@class='product-item']//h3/text()
——这里@class
是属性节点(筛选出“商品容器”),text()
是文本节点(取h3里的文字)。新手最常犯的错就是忘加text()
,我当初第一次写的时候,没加text()
,结果抓回来的是
标签本身,不是里面的文字,差点把朋友的调研数据搞砸。
路径表达式:XPath的“导航规则”
XPath的路径分两种,绝对路径和相对路径,区别像“从小区大门走到家”vs“直接找单元楼”:
绝对路径:从根节点(HTML
)开始写,比如/HTML/body/div[3]/h3
,每一步都不能错。但缺点是页面结构一变就失效——比如网站加了个header,路径就变成/HTML/body/header/div[3]/h3
,之前的表达式直接没用了;
相对路径:用//
开头,比如//div[@class='product-item']//h3
,不管中间隔了多少层(比如加了广告、导航),都能找到目标节点。我现在爬数据,90%的情况用相对路径,稳定性直接拉满。
再举个例子:你要抓知乎回答里的内容,绝对路径可能是/HTML/body/div[3]/div[2]/div[1]/p
,但相对路径只要//div[@class='RichText']/p/text()
——简单、好记,就算知乎改了页面布局,也不会影响结果。
谓词:XPath的“筛选器”
谓词就是“缩小范围的条件”,用[]
括起来。比如你要找“第2个商品”,可以写//div[@class='product-item'][2]
;要找“价格大于30的商品”,可以写//div[@class='product-item'][//span[@class='price']>30]
。
我之前帮朋友爬生鲜电商的数据,遇到“同一款水果有多个规格”的情况——比如“500g装”和“1kg装”,用两个属性条件组合://div[@class='sku' and @data-id='123']
,瞬间就把“500g装”的价格抓准了。谓词可以叠加多个条件,用and
连接,这样筛选出来的节点比单条件精准10倍。
从“会写”到“写好”:XPath的“实战技巧”和“高级玩法”
光懂基础还不够,得结合真实场景“落地”——毕竟你学XPath不是为了考试,是为了解决实际问题。我整理了3个高频场景+2个高级技巧,都是我爬了100个网站 出来的“避坑经验”。
场景1:爬取电商商品的“名称+价格”(新手必练)
步骤超简单,跟着做就能会,以淘宝为例:
打开开发者工具:按F12
,点击“元素”面板的“选择器”(小箭头),点一下商品名称,就能定位到对应的节点(比如
番茄火锅底料
);
写XPath:
商品名称://div[@class='product-item']//h3/text()
(找所有商品容器里的h3文本);
商品价格://div[@class='product-item']//span[@class='price']/text()
(找商品容器里的价格span文本);
验证正确性:用Chrome插件“XPath Helper”(应用商店直接搜),把表达式粘进去,能实时看到结果——我每次写XPath都会先验证,避免白费功夫。
我朋友用这个方法,30分钟就爬了200个商品的名称和价格,比手动复制快了10倍。
场景2:解析XML文件(比如RSS订阅)
很多行业资讯网站用RSS feed分发内容(比如36氪、虎嗅),解析这种XML文件,XPath是“神器”。比如36氪的RSS结构是这样的:
2024年餐饮行业趋势
https://36kr.com/xxx
Mon, 01 Jan 2024 10:00:00 +0800
要抓标题和链接,XPath就是:
标题://item/title/text()
;
链接://item/link/text()
。
但要注意:如果XML有命名空间(比如atom:entry
),得加前缀——比如BBC的RSS用了atom
命名空间,XPath得写成//atom:entry/atom:title/text()
,不然找不到节点。我之前解析BBC新闻时没加前缀,结果抓了个空,后来查了MDN的文档(https://developer.mozilla.org/zh-CN/docs/Web/XPath rel="nofollow")才搞懂——命名空间是XML的“身份牌”,不加就找不到对应的节点。
高级技巧1:用“轴方法”处理“复杂关系”
轴(Axis)是XPath的“高级导航工具”,能帮你找“亲戚节点”——比如祖先、兄弟、后代。我最常用的两个轴,帮你解决90%的复杂场景:
following-sibling:找“后面的兄弟节点”。比如你要抓论坛里“帖子1”的下一个帖子,XPath是//div[@id='post1']/following-sibling::div[1]
(following-sibling
是轴,::
后面跟节点类型,[1]
是第1个);
ancestor:找“祖先节点”。比如你要找某个图片的父级div,XPath是//img[@src='xxx.jpg']/ancestor::div[1]
——能直接定位到图片所在的div,不用一层一层往上找。
我之前爬论坛回帖时,需要抓每个回帖的“作者”和“回复内容”——作者在div[@class='author']
,回复内容在它的下一个兄弟节点div[@class='content']
,用following-sibling
轴,写//div[@class='author']/following-sibling::div[1]/text()
,瞬间就把“作者下面的回复内容”抓准了,比用CSS选择器快多了。
高级技巧2:处理“动态加载”的页面
现在很多网站用Ajax动态加载内容——比如滚动到底部才会出现新商品,直接写XPath抓不到。这时候得用Chrome的“Network”面板看异步请求,或者用Selenium模拟滚动:
第一步:打开目标页面,按F12
选“Network”面板,勾选“XHR”(异步请求);
第二步:滚动页面,看新出现的请求——比如淘宝的商品数据,其实是从https://xxx.taobao.com/api/getGoods
接口拿的JSON;
第三步:如果接口有反爬,用Selenium模拟滚动——比如用driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
,等内容加载完再用XPath抓。
我之前帮朋友爬抖音商品榜,一开始用requests库抓,结果只拿到前10个商品,后来用Selenium模拟滚动5次,再用XPath//div[@class='goods-item']//h4/text()
,终于把前50个商品都抓下来了。记住:动态加载的内容,得等页面渲染完再抓,不然XPath找不到节点。
给你整理了一份《XPath常用语法速查表》,保存下来,写的时候对着查,省得翻文档:
语法
说明
示例
//节点名
找所有该节点(相对路径)
//div[@class='product-item']
@属性
选属性节点
//div[@class='title']
text()
选文本节点
//h3/text()
[n]
选第n个节点
//div[@class='product-item'][2]
and
多条件组合
//div[@class='product-item' and @data-id='123']
其实XPath真的不难,关键是多练——你写完一个表达式,就用XPath Helper验证;遇到问题,就查MDN或W3C的文档(这两个是权威来源,不会错)。我当初学的时候,花了3天爬了5个网站的数据,现在写XPath基本不会错。
你要是按上面的方法试了,欢迎回来告诉我效果——比如你用XPath抓了什么数据,有没有遇到问题,我帮你看看。
XPath和CSS选择器有什么区别?我该选哪个?
其实两者都是定位页面元素的工具,但XPath的“精准度”和“稳定性”更胜一筹。比如我之前帮朋友的美食博客爬菜谱,他用CSS选择器抓回来一堆广告标题——因为CSS只能按“标签+class”选,容易混进无关内容;换XPath写//div[@class='recipe-item']//h3/text(),瞬间就把正菜谱名精准揪出来了。 XPath还能处理“复杂节点关系”(比如找兄弟节点、祖先节点),而CSS选择器做不到。如果是爬数据或解析结构化文件(比如XML),优先选XPath;如果是简单的页面元素定位,CSS也能用,但XPath的适用场景更广。
为什么大家都说相对路径比绝对路径好用?
绝对路径是从根节点(比如/HTML/body)开始“一步步数”,比如/HTML/body/div[3]/h3,每一步都不能错,但页面结构一变就失效——比如网站加个导航栏,原来的路径就变成/HTML/body/header/div[3]/h3,之前的表达式直接废了。而相对路径用//开头,比如//div[@class='product-item']//h3,不管中间隔了多少层(比如广告、导航),都能“穿透”找到目标节点。我现在爬数据90%的情况用相对路径,就算网站改布局,也不用重新写表达式,稳定性直接拉满。
谓词是用来干什么的?怎么用才能精准筛选?
谓词就是“给XPath加筛选条件”,用[]括起来,帮你缩小范围。比如你要找“第2个商品”,可以写//div[@class='product-item'][2];要找“价格大于30的商品”,可以写//div[@class='product-item'][//span[@class='price']>30];甚至能组合多个条件,比如//div[@class='product-item' and @data-id='123'],这样就能定位到“class是product-item且data-id是123”的节点。新手常犯的错是忘加谓词,结果抓了一堆无关内容,所以写XPath前先想“我要筛选什么条件”,再把条件放进[]里。
轴方法听起来好复杂,实际什么时候会用到?
轴方法是处理“复杂节点关系”的神器,比如找“兄弟节点”“祖先节点”的时候。比如你要抓论坛里“帖子1”的下一个帖子,用following-sibling轴写//div[@id='post1']/following-sibling::div[1],就能直接找到下一个帖子;再比如你要找某个图片的父级div,用ancestor轴写//img[@src='xxx.jpg']/ancestor::div[1],不用一层一层往上找。我之前爬论坛回帖时,需要抓“作者下面的回复内容”,用轴方法写//div[@class='author']/following-sibling::div[1]/text(),瞬间就精准定位了——轴方法就是帮你解决“常规路径找不到”的问题。
动态加载的页面,为什么我写的XPath抓不到内容?
因为动态加载的内容是用Ajax异步请求“后来加上的”,页面初始加载时根本没有这些节点,所以直接写XPath肯定抓不到。这时候有两个办法:一是打开Chrome的Network面板,勾选“XHR”(异步请求),滚动页面看新出现的请求——比如淘宝的商品数据其实是从接口拿的JSON,直接爬接口更高效;二是用Selenium模拟滚动,比如用driver.execute_script("window.scrollTo(0, document.body.scrollHeight)"),等内容加载完再用XPath抓。我之前爬抖音商品榜,一开始用requests抓不到后面的商品,换Selenium模拟滚动后,终于把前50个都抓下来了——动态页面的关键是“等内容渲染完再抓”。