Python爬虫开发中,xpath速度是比较快的使用较为灵活,是在网页定位元素的较优选择。
虽然文本解析库中正则表达式的性能比Xpath要强,但是企业级爬虫开发里,Xpath比正则要更为常见得多。
对于我的话,“不管是什么魔法、什么妖法,只有有用的都会用。”
而往网上的文章,对于Xpath语句的记录都比较零碎,所以在这里统一整理一下,自己可能常用的Xpath。
运行环境 Runtime environment
1 | 操作系统 : Windows10 |
准备
在python中安装Xpath,在终端输入完成安装。
通常来讲安装是不会出现问题,如果出现了请根据报错搜索解决。
高版本的lxml是没有etree方法的,所以网上的代码不一定有用多数因为这个原因。
pip install lxml
测试用的前端网页代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<html>
<head>
<title>xpath test</title>
</head>
<body>
<div name="q">
<div>
<ul>
<li>时间</li>
<li>地点</li>
<li>任务</li>
</ul>
</div>
<div id='testid' data-h="first">
<h2>这里是个小标题</h2>
<ol>
<li data="one">1</li>
<li data="two">2</li>
<li data="three">3</li>
</ol>
<ul>
<li code="233">233</li>
<li code="666">666</li>
<li code="888">888</li>
</ul>
</div>
<div>
<h3>H3装了好多东西
<a href="http://www.baidu.com">百度一下</a>
<a href="http://www.baidu.com">谷歌一下</a>
<ul>
<li>test1</li>
<li>test2</li>
</ul>
</h3>
</div>
<div id="countList">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
</div>
</div>
</body>
</html>
Xpath 应用
匹配节点下全匹配 .//
- //获取文档中所有匹配的节点,
- .获取当前节点,有的时候我们需要获取当前节点下的所有节点,
- .//一定要结合.使用//,否则都会获取整个文档的匹配结果。
匹配包含某标签/属性的所有的属性值 //
- 如果使用了类似Xpath Helper之类的浏览器插件,善用全匹配,可以有效的缩短插件自动生成的Xpath
1
2
3print(tree.xpath('//@code')) #匹配所有带有code属性的属性值
print(tree.xpath('//li')) #匹配所有li标签
选取多个路径|
- 该符号目的是为了在一个xpath中写多个表达式,用|分开,每个表达式互不干扰。
- 符合匹配表达式的元素都会放到同一个列表里
1
print(tree.xpath('//div[@id="testid"]/h2/text() | //li[@data]/text()'))#多个匹配条件
position定位
- 该符号目的是为了在一个xpath中写多个表达式,用|分开,每个表达式互不干扰。
- 符合匹配表达式的元素都会放到同一个列表里
1
print(tree.xpath('//*[@id="testid"]/ol/li[position()=2]/text()')[0] )
Axes(轴)
对常用的Xpath轴先做简单的整合,再做分别测试。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29XPath 坐标轴:坐标轴用于定义当对当前节点的节点集合。
坐标轴名称 含义
ancestor 选取当前节点的所有先辈元素及根节点。
ancestor-or-self 选取当前节点的所有先辈以及当前节点本身。
ttibute 选取当前节点的所有属性。
child 选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素。
descendant-or-self 选取当前节点的所有后代元素以及当前节点本身。
following 选取文档中当前节点的结束标签之后的所有节点。
following-sibling 选取当前节点之后的所有同级节点。
namespace 选取当前节点的所有命名空间节点。
parent 选取当前节点的父节点。
preceding 选取当前节点的开始标签之前的所有节点。
preceding-sibling 选取当前节点之前的所有同级节点。
self 选取当前节点。
child:选取当前节点的所有子元素1
2
3
4
5
6
7
8#child子节点定位
print(tree.xpath('//div[@id="testid"]/child::ul/li/text()'))
#child::*当前节点的所有子元素
print(tree.xpath('//div[@id="testid"]/child::*'))
#定位某节点下为ol的子节点下的所有节点
print(tree.xpath('//div[@id="testid"]/child::ol/child::*/text()'))
attribute:选取当前节点的所有属性1
2print(tree.xpath('//div/attribute::id'))
print(tree.xpath('//div/attribute::id'))
ancestor:父辈元素 / ancestor-or-self:父辈元素及当前元素
descendant:后代 / descendant-or-self:后代及当前节点本身1
2print(tree.xpath('//div/attribute::id'))
print(tree.xpath('//div/attribute::id'))
following :选取文档中当前节点的结束标签之后的所有节点1
print(tree.xpath('//div[@id="testid"]/following::div[not(@id)]/.//li[1]/text()'))
namespace:选取当前节点的所有命名空间节点1
print(tree.xpath('//div[@id="testid"]/namespace::*'))
parent:选取当前节点的父节点1
print(tree.xpath('//li[@data="one"]/parent::ol/li[last()]/text()'))
preceding:选取文档中当前节点的开始标签之前的所有节点1
2
3
4
5# 记住是标签开始之前,同级前节点及其子节点
print(tree.xpath('//div[@id="testid"]/preceding::div/ul/li[1]/text()')[0])
# 下面这两条可以看到其顺序是靠近testid节点的优先
print(tree.xpath('//div[@id="testid"]/preceding::li[1]/text()')[0])
print(tree.xpath('//div[@id="testid"]/preceding::li[3]/text()')[0])
preceding-sibling:选取当前节点之前的所有同级节点1
2
3
4print(tree.xpath('//div[@id="testid"]/preceding-sibling::div/ul/li[2]/text()')[0])
#这里返回的就是空的
print(tree.xpath('//div[@id="testid"]/preceding-sibling::li'))
self:选取当前节点1
2# 选取带id属性值的div中包含data属性的标签的所有属性值
print(tree.xpath('//div[@id]/self::div[@data]/attribute::*'))