XPath
XPath,全称XML Path Language,即XML路径语言,它提供简洁明了的路径选择表达式,用于在 XML 文档中通过元素和属性进行导航。
XPath常用规则
表达式 |
描述 |
nodename |
选取此节点所有子节点 |
/ |
从当前节点选取直接子节点 |
// |
从当前节点选取所有子孙节点 |
. |
选取当前节点 |
.. |
选取当前节点的父节点 |
@ |
选取属性 |
实例HTML文档
<div>
<ul>
<li class="item-0"><a href="link1.html"><span>first item</span></a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-1 item-inactive" name="item"><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></li>
</ul>
</div>
子节点、父节点、文本及属性
- Python通过lxml库,利用XPath进行HTML解析
# 从lxml库导入etree模块
from lxml import etree
# 声明一段HTML文本
text
'''
实例HTNL文档(略)
'''
# 调用HTML类进行初始化,构造XPath解析对象
html = etree.HTML(text)
# 调用tostring()方法输出修正后的HTML代码(bytes类型)
result = etree.tostring(html)
# 调用decode()方法将bytes类型的HTML代码转成str类型
print(result.decode('utf-8'))
f = open('test.html','wt',encoding = 'utf-8')
f.write(result.decode('utf-8'))
f.close()
'''
# 直接读取文本文件进行解析
html = etree.parse('test.html',etree.HTMLParse())
result = etree.tostring(html)
print(result.decode('utf-8'))
'''
- 用//开头的XPath规则来选取所有符合要求的节点
- 通过/或//查找元素的子节点或子孙节点
- 通过..查找元素的父节点
- 用@符号进行属性过滤或获取属性
- 用text()方法获取节点中的文本
from lxml import etree
html = etree.parse('test.html',etree.HTMLParse())
# 选取所有节点
result = html.xpath('//*')
# 选取所有li节点的所有直接a子节点
result = html.xpath('//li/a')
# 选取所有ul节点下所有子孙a节点
result = html.xpath('//ul//a')
# 选中属性href为ink1.html的a节点,再选中取其父节点获取其class属性
result = html.xpath('//a[@href="link1.html"]/../@class')
# 选取class为item-0的li节点
result = html.xpath('//li[@class="item-0"]')
# 选取属性为item-0的li节点,获取其直接子节点a的文本(以列表形式返回)
result = html.xpath('//li[@class="item-0"]/a/text()')
# 获取所有li节点所有直接a子节点的href属性(以列表形式返回)
result = html.xpath('//li/a/@href')
- 通过contains()方法进行属性多值匹配(第一个参数传入属性名称,第二个参数传入属性值)
- 多重属性匹配根据多个属性确定一个节点,需要同时匹配多个属性,可通过and运算符来连接
from lxml import etree
html = etree.parse('test.html',etree.HTMLParse())
'''
<li class="item-1 item-inactive" name="item"><a href="link3.html">third item</a></li>
'''
# 匹配class属性为item-inactive的li节点并获取其直接a子节点的文本
result = html.xpath('//li[contains(@class,"item-inactive")]/a/text()')
# 匹配class属性为为item-inactive、name属性为item的li节点并获取其直接a子节点的文本
result = html.xpath('//li[contain(@class,"item-inactive") and @name="item"]/a/text')
运算符 |
描述 |
or |
或 |
and |
与 |
mod |
计算除法的余数 |
| |
计算两个节点集 |
+ |
加法 |
- |
减法 |
* |
乘法 |
div |
除法 |
= |
等于 |
!= |
不等于 |
< |
小于 |
<= |
小于或等于 |
> |
大于 |
>= |
大于或等于 |
按序选择
- 匹配多个节点可利用中括号传入索引的方法获取特定次序的节点
from lxml import etree
html = etree.parse('test.html',etree.HTMLParse())
# 选取匹配到的第一个li节点
result = html.xpath('//li[1]/a/text')
# 选取匹配到的最后一个li节点
result = html.xpath('//li[last()]/a/text')
# 选取匹配到的位置序号小于3的li节点
result = html.xpath('//li[position()<3]/a/text')
# 选取匹配到的倒数第三个li节点
result = html.xpath('//li[last()-2]/a/text')
节点轴选择
XPath轴可定义相对于当前节点的节点集。
轴 |
描述 |
ancestor |
选取当前节点的所有先辈(父、祖父等) |
ancestor-or-self |
选取当前节点的所有先辈(父、祖父等)以及当前节点本身 |
attribute |
选取当前节点的所有属性 |
child |
选取当前节点的所有子元素 |
descendant |
选取当前节点的所有后代元素(子、孙等) |
descendant-or-self |
选取当前节点的所有后代元素(子、孙等)以及当前节点本身 |
following |
选取文档中当前节点的结束标签之后的所有节点 |
namespace |
选取当前节点的所有命名空间节点 |
parent |
选取当前节点的父节点 |
preceding |
选取文档中当前节点的开始标签之前的所有节点 |
preceding-sibling |
选取当前节点之前的所有同级节点 |
self |
选取当前节点 |
from lxml import etree
html = etree.parse('test.html',etree.HTMLParse())
'''
<li class="item-0"><a href="link1.html"><span>first item</span></a></li>
'''
# 轴后跟两个冒号再跟节点选择器
# 获取第一个li节点的所有祖先节点(html、body、div和ul)
result = html.xpath('//li[1]/ancestor::*')
# 获取第一个li节点的div祖先节点
result = html.xpath('//li[1]/ancestor::div')
# 获取第一个li节点的所有属性值
result = html.xpath('//li[1]/attribute::*')
# 获取第一个li节点href属性为link1.html的a节点
result = html.xpath('//li[1]/child::a[@href="link1.html"]')
# 获取第一个li节点的所有包含span而不包含a的子孙节点
result = html.xpath('//li[1]/descendant::span')
# 获取第一个li节点后的第二个后续节点
result = html.xpath('//li[1]/following::*[2]')
# 获取第一个li节点后的所有同级节点
result = html.xpath('//li[1]/following-sibling::*')