land, mountain, nature-7082135.jpg

XPath 入门实例

XPath(XML Path Language),即 XML 路径语⾔,它是⼀⻔在 XML ⽂档中查找信息的语⾔。最初是⽤来搜寻 XML ⽂档的,但同样适⽤于 HTML ⽂档的搜索,所以在做爬⾍时完全可以使⽤ XPath 做相应的信息抽取。

1. XPath 概览

XPath 的选择功能⼗分强⼤,它提供了⾮常简洁明了的路径选择表达式。另外还提供了超过 100 个内建函数,⽤于字符串、数值、时间的匹配以及节点、序列的处理等,⼏乎所有想要定位的节点 都可以⽤ XPath 来选择。

2. XPath 常用规则

表达式描述
nodename选取此节点的所有⼦节点
/从当前节点选区直接⼦节点
//从当前节点选取⼦孙节点
.选取当前节点
..选取当前节点的⽗节点
@选取属性

例如://title[@lang=’eng’],表示的就是选择所有名称为 title,同时属性 lang 的值为 eng 的节点。

3. 安装

pip install lxml

4. 实例

from lxml import etree

# 第一种方式:在 python 代码中解析 html 字符串
# ⽂本中最后⼀个 <li> 节点没有闭合,但是 etree 模块可以⾃动修正 HTML ⽂本
text = '''
<div>
    <ul>
        <li class="item-0"><a href="link1.html">first item</a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
        <li class="item-inactive"><a href="link3.html">third item</a></li>
        <li class="item-1"><a href="link4.html">fourth item</a></li>
        <li class="item-0"><a href="link5.html">fifth item</a>
    </ul>
</div>
'''
resp_html = etree.HTML(text)
# 第二种方式:读取 html ⽂件并解析
resp_html = etree.parse('./demo.html', etree.HTMLParser())
result = etree.tostring(resp_html)
result.decode('utf-8')

5. 所有节点

# ⽤以 // 开头的 XPath 规则来选取所有符合要求的节点
text = '''
<div>
    <ul>
        <li class="item-0"><a href="link1.html">first item</a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
        <li class="item-inactive"><a href="link3.html">third item</a></li>
        <li class="item-1"><a href="link4.html">fourth item</a></li>
        <li class="item-0"><a href="link5.html">fifth item</a>
    </ul>
    <ul>
        <li class="item-0"><a href="link1.html">first item</a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
        <li class="item-inactive"><a href="link3.html">third item</a></li>
        <li class="item-1"><a href="link4.html">fourth item</a></li>
        <li class="item-0"><a href="link5.html">fifth item</a>
    </ul>
</div>
'''
resp_html = etree.HTML(text)
resp_html.xpath('//li')

6. 子节点

# 通过 / 或 // 即可查找元素的⼦节点或⼦孙节点,直接选择 li 节点的所有直接 a ⼦节点
resp_html.xpath('//li/a')

7. 父节点

# 通过⼦节点查询⽗节点可以⽤ .. 来实现
resp_html.xpath('//a[@href="link4.html"]/..')
# 另一种实现方式
resp_html.xpath('//a[@href="link4.html"]/parent::*')

8. 属性匹配

# 匹配时可以⽤ @ 符号进⾏属性过滤
resp_html.xpath('//li[@class="item-inactive"]')

9. 文本获取

# 第一种方式
resp_html.xpath('//li[@class="item-inactive"]/a/text()')
# 第二种方式:该方法会获取到补全代码时换⾏产⽣的特殊字符,推荐使⽤第⼀种⽅法可以保证获取的结果是整洁的
resp_html.xpath('//li[@class="item-inactive"]//text()')

10. 属性获取

# @ 符号相当于过滤器可以直接获取节点的属性值
resp_html.xpath('//li[@class="item-inactive"]/a/@href')

11. 属性多值匹配

text = '''
<div>
    <ul>
        <li class="item-0 test"><a href="link1.html">first item</a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
        <li class="item-inactive"><a href="link3.html">third item</a></li>
        <li class="item-1"><a href="link4.html">fourth item</a></li>
        <li class="item-0"><a href="link5.html">fifth item</a>
    </ul>
</div>
'''
resp_html = etree.HTML(text)
# 节点的某个属性可能有多个值
resp_html.xpath('//li[contains(@class, "test")]/a/text()')

12. 多属性匹配

text = '''
<div>
    <ul>
        <li class="item-0 test" name="item"><a href="link1.html">first item</a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
        <li class="item-inactive"><a href="link3.html">third item</a></li>
        <li class="item-1"><a href="link4.html">fourth item</a></li>
        <li class="item-0"><a href="link5.html">fifth item</a>
    </ul>
</div>
'''
resp_html = etree.HTML(text)
# 需要同时匹配节点的多个属性
resp_html.xpath('//li[contains(@class, "test") and @name="item"]/a/text()')

XPath 运算符:

运算符描述实例返回值
orage=18 or age=20age=18:True;age=21:False
andage>18 and age<21age=20:True;age=21:False
mod计算除法的余数5 mod 21
|计算两个节点集//book | //cd返回所有拥有 book 和 cd 元素的节点集
+加法5 + 38
减法5 – 32
*乘法5 * 315
div除法8 div 42
=等于age=19
!=不等于age!=19
<⼩于age<19
<=⼩于等于age<=19
>⼤于age>19
>=⼤于等于age>=19

13. 按序选择

# 匹配结果有多个节点,可以按照中括号内加索引或其他相应语法获得
# 注意:索引值从 1 开始,并非 0
# 获取第一个
resp_html.xpath('//li[1]/a/text()')
# 获取最后一个
resp_html.xpath('//li[last()]/a/text()')
#  获取前两个
resp_html.xpath('//li[position()<3]/a/text()')
# 获取倒数第三个
resp_html.xpath('//li[last()-2]/a/text()')

More function: https://www.w3school.com.cn/xpath/xpath_functions.asp

14. 节点轴选择

# 获取所有祖先节点
resp_html.xpath('//li[1]/ancestor::*')
# 获取 div 祖先节点
resp_html.xpath('//li[1]/ancestor::div')
# 获取当前节点所有属性值
resp_html.xpath('//li[1]/attribute::*')
# 获取 href 属性值为 link1.html 的直接⼦节点
resp_html.xpath('//li[1]/child::a[@href="link1.html"]')
# 获取所有的的⼦孙节点中包含 span 节点但不包含 a 节点
resp_html.xpath('//li[1]/descendant::span')
# 获取当前所有节点之后的第⼆个节点
resp_html.xpath('//li[1]/following::*[2]')
# 获取当前节点之后的所有同级节点
resp_html.xpath('//li[1]/following-sibling::*')

About The Author

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

Scroll to Top