xpath是定位dom元素非常直观的方法之一,在爬虫中的使用尤其常见。
绝对路径和xpath
关于html的dom树这里就不赘述了,相信根节点,子节点,兄弟节点这些概念大家也都听的很多。
在一棵dom树里面,想定位某个元素有绝对路径和xpath的区分。如下图所示,选择了一个img
标签以后点击右键,可以选择是复制xpath还是完整的路径
如果是绝对路径结果是这样的
/html/body/div[3]/div[2]/div/div[1]/div[1]/div[2]/div/div/ul[2]/li[1]/div[1]/a/img
从根节点开始一级一级往下,一直到img
元素,每一层都被罗列了出来。真正在程序中这样子获取元素会非常麻烦,也没有必要。
如果是xpath结果是这样的
//*[@id="content"]/div/div[1]/div[1]/div[2]/div/div/ul[2]/li[1]/div[1]/a/img
虽然还是不够简洁,但是已经能看出比完整路径要好一点了。
当然,默认的xpath还是不够言简意赅一目了然,大多数时候我们还是需要通过xpath语法去构建自己的xpath来定位元素。
浏览器自带的xpath工具
浏览器已经为我们准备好了xpath验证工具,这样我们就可以一边修改一边验证,在网页中确认可以定位到元素了再放进我们的程序里。
这里以chrome为例,有两种方法可以验证我们写的xpath。
在开发者模式中,首先是可以通过在Element页签使用Ctrl+f打开搜索框,在里面通过xpath来查找元素
如上图所示,通过xpath找到了两个alt属性为项塔兰的img元素。
然后可以进入console,通过$x()
语法来验证
网页可能自带很多错误信息,console中可以通过
clear()
进行清除
如上图所示,找到了3个alt属性为鸳鸯六七四的img元素,点击其中任意一个找到的元素都会自动跳转到element的对应位置。
xpath语法
下面开始正式进入xpath的语法说明。
常用符号
xpath基本就是下列常用符号的组合和级联
符号 | 说明 | 举例 |
---|---|---|
/ | 表示从root开始查找,或者表示子节点 | /html/body/div |
// | 表示从任意层级开始查找 | //div |
* | 通配符,表示任意元素 | |
@ | 获取属性 | //img[@alt=‘xxx’] |
. | 当前层级或当前节点 | |
… | 上一层级或父节点 | //div/…/img |
定位元素
xpath的常用格式如下,通过不断级联向更深层次去定位,其中路径如果省略默认就是root
路径(/或者//)元素名称[@属性名=xxx]
例如//img[@alt='鸳鸯六七四']
就表示从任意层级开始查找,需要找的元素是img,需要满足的条件是alt属性值为"鸳鸯六七四"。
需要注意的是根据属性值来定位,属性值必须加上引号,单引号或者双引号都行。
除了利用属性值来定位,还可以通过是否具有某属性来定位。
//img[@alt]
上面的表达式表示从任意层级开始查找,找到含有alt属性的img元素,范围就比上面宽了很多。
如果不确定元素名称就可以用通配符来代替
//*[@id='content']
上面的表达式表示从任意层级开始查找,找到id为content的那个元素。
有的元素的属性很长,或者包含多个值,例如<ul class='list-col list-col5 list-express slide-item clone'></ul>
这时候用//ul[@class='list-express']
是无法定位该元素的,必须要么用完整的值,要么像下面这样获取部分值
//ul[contains(@class,'list-express')]
当然除了通过属性,还可以通过文字内容进行定位。text()
和string()
都表示元素包含的文字内容,区别是前者不能包括子元素,后者则是所有子元素的文字内容之和。
例如下面这个就可以识别出<img><a>鸳鸯六七四</a></img>
//*[string()='鸳鸯六七四']
但是下面这个就只能识别出<img>鸳鸯六七四</img>
//*[text()='鸳鸯六七四']
既然是文字就有可能有一大段,所以可以对文字进行部分匹配
//a[contains(string(),'鸳鸯')]
//a[starts-with(string(),'鸳鸯')]
上面两种分别是包含“鸳鸯”两个字的和以“鸳鸯”两个字开头的文字内容。
多重定位
当然通常不会是直接就能一步到位找到想要的那个元素,而要么是先找到容易定位的上层元素,又或者是找到了很多同类型的元素需要去进行筛选。这时候只需要将前面找到的xpath元素做为root级联下一个xpath规则即可。
//div[@class='info']//a[starts-with(string(),'鸳鸯')]
上面这个表达式表示首先找到符合条件的div元素,然后在该元素内部任意层次查找符合条件的a元素
//div[@class='info']/a[starts-with(string(),'鸳鸯')]
将双斜线换成单斜线,就是从div元素内部的下一层级查找a元素。
这种级联关系可以一直持续,直到找到最终元素为止,下面是几种特殊情况。
同级元素,需要借助..
符号
//div[@class='info']/../div[@class='cover']
索引位置查找,可以用中括号加数字。注意这里分为两类,同类元素在同一元素下和不在同一元素下。
(//ul[contains(@class,'list-express')])[2]
上面是不在同一元素下的情况,查找到的多个ul在不同的层次,所以要对前面整个内容加上小括号表示整体。
(//ul[contains(@class,'list-express')])[2]/li[2]
如果继续在ul下面查找li,这些li都在同一个ul元素下,所以可以直接用中括号加数字。
不管哪种方式都要注意,xpath的索引是从1开始,不是0!
如果不确定是第几个元素,可以用一些关键字来辅助,例如最后一个元素
(//ul[contains(@class,'list-express')])[2]/li[last()]
或者倒数第二个元素
(//ul[contains(@class,'list-express')])[2]/li[last()-1]
多条件组合
还可以通过逻辑运算符号and
,or
来进行多条件组合定位
//span[contains(@class,'allstar') and contains(@class,'star-img')]
//span[contains(@class,'allstar') or contains(@class,'star-img')]
获取属性或文字
定位到了元素,最终目的还是获取元素的属性值或者是文字内容。
用text()
获取文字内容
//span[@class='average-rating']/text()
用@
获取属性值
//img/@src
需要注意的是,查找出来的文字内容还是xpath对象,并不是字符串。
xpath在爬虫中的使用
下面以获取京东商城商品图片为例来进行演示,演示环境为python3,使用scrapy框架。
图片的dom信息如下图所示
整个列表在一个div下,然后每个item有一个div用来存放img信息。
首先通过class名字可以唯一定位到整个列表
itemList = response.xpath('//div[@class="search_prolist_item"]')
之后通过for循环获取单个item中的img信息
for node in itemList:
item = JdItem()
item['img_url'] = node.xpath('.//div[@class="search_prolist_cover"]/img[@class="photo"]/@src').extract()[0]
...
...
这里首先定位到包裹img的div,然后是img,最后获取img的src属性。注意提取出来的src文字还是xpath对象,需要使用extract()
方法来转为python的字符串,而且还需要注意,即使只找到了单个元素,scrapy的xpath对象还是会返回一个list,需要取出元素再使用。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。