lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高
XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言,它最初是用来搜寻XML文档的,但是它同样适用于HTML文档的搜索
XPath的选择功能十分强大,它提供了非常简明的路径选择表达式,另外,它还提供了超过100个内建函数,用于字符串、数值、时间的匹配以及节点、序列的处理等,几乎所有我们想要定位的节点,都可以用XPath来选择
XPath的常用规则
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从当前节点,选取直接子节点 |
// | 从当前节点,选取所有子孙节点 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
* | 通配符,选择所有元素节点与元素名 |
@* | 选取所有属性 |
[@attrib] | 选取具有给定属性的所有元素 |
[@attrib='value'] | 选取给定属性具有给定值的所有元素 |
[tag] | 选取所有具有指定元素的直接子节点 |
[tag='text'] | 选取所有具有指定元素并且文本内容是text节点 |
构建etree实例
首先需要引入etree
from lxml import etree
etree.HTML()
解析字符串格式的HTML文档对象,将传进去的字符串转变成_Element对象。
-- text:HTML文档的字符串格式parse()
读取HTML文件进行解析,将其转变成_Element对象。
-- source:文件路径
-- parser:该方法默认使用的是“XML”解析器,所以如果碰到不规范的html文件时就会解析错误,需要将此参数设置为etree.HTMLParser()etree.tostring()
将_Element对象转换成字符串。
注意:
- etree.tostring()方法返回的是bytes类型,需要调用decode方法将其改变编码类型。
- 解析html代码时,会自动修正,添加缺少的标签。
XPath语法实例
- 选中所有节点
# 选中所有的节点
html = etree.parse("./test.html", etree.HTMLParser())
results = html.xpath("//*")
print(results)
# 选中所有的li节点
results = html.xpath("//li")
print(results)
print(results[0])
- 选中子节点
# 选中直接子节点
html = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li/a")
print(result)
# 选取所有子孙节点
result = html.xpath("//ul//a")
print(result)
- 选取父亲节点
html = etree.parse("./test.html",etree.HTMLParser())
# 选中属性href='link4.html'的a标签的父亲
result = html.xpath("//a[@href='link4.html']/..")
print(result)
# 选中属性href='link4.html'的a标签的父亲的class属性
result = html.xpath("//a[@href='link4.html']/../@class")
print(result)
# 使用parent:: 选中父亲
result = html.xpath("//a[@href='link4.html']/parent::*/@class")
print(result)
- 按属性选取节点
html = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li[@class='item-0']")
print(result)
- 获取节点文本内容
需要调用text()函数
html = etree.parse("./test.html", etree.HTMLParser())
print(etree.tostring(html).decode("utf-8"))
# 使用/仅获取自身的文本内容
result = html.xpath("//li[@class='item-0']/text()")
print(result) # 输出:['\r\n\t']
# 使用//获取自己以及子孙的文本内容
result = html.xpath("//li[@class='item-0']//text()")
print(result) # 输出:['first item', 'fifth item', '\r\n\t']
- 获取节点属性的值
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li/a/@href")
print(result)
- 多值属性匹配
需要使用contains()函数
text = '''
<li class="li li-first"><a href="link1.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath("//li[@class='li']/a/text()")
print(result) # 输出 []
result = html.xpath("//li[contains(@class,'li')]/a/text()")
print(result) # 输出:['first item']
- 多属性匹配
text = '''
<li class="li li-first" name="item"><a href="link1.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath("//li[contains(@class,'li') and @name='item']/a/text()")
print(result)
and 是xpath中的运算符。常见的运算符如下:
运算符 | 描述 | 实例 |
---|---|---|
or | 或 | age=19 or age=20 |
and | 与 | age >19 and age <21 |
mod | 取余数 | 5 mod 2 |
计算两个节点集 | //book | //cd :返回所有拥有book和cd元素的节点集 | |
+ | 加法 | 6 + 4 |
- | 减法 | 6 - 4 |
* | 乘法 | 6 * 3 |
div | 除法 | 6 div 3 |
= | 等于 | age=19 |
!= | 不等于 | age !=19 |
< | 小于 | age <19 |
<= | 小于或等于 | age <= 19 |
> | 大于 | age >19 |
>= | 大于或等于 | age >= 19 |
- 按顺序选取节点
html = etree.parse("./test.html",etree.HTMLParser())
# 选取第一个节点
result = html.xpath("//li[1]/a/text()")
print(result)
# 选取最后一个节点
result = html.xpath("//li[last()]/a/text()")
print(result)
# 选取前两个节点
result = html.xpath('//li[position() < 3]/a/text()')
print(result)
# 选取倒数第三个节点
result = html.xpath("//li[last()-2]/a/text()")
print(result)
- 按节点轴选取元素
text = '''
<div>
<ul>
<li class="item-0" name="first-li"><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-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>
'''
html = etree.HTML(text)
# 选中指定元素所有的祖先
result = html.xpath("//li[1]/ancestor::*")
print(result)
# 选中祖先中的div
result = html.xpath("//li[1]/ancestor::div")
print(result)
# 获取所有的属性值
result = html.xpath("//li[1]/attribute::*")
print(result)
# 找到直接子节点中满足条件的元素
result = html.xpath("//li[1]/child::a[@href='link1.html']")
print(result)
# 找到所有的后代元素
result = html.xpath("//li[1]/descendant::*")
print(result)
# 找到后代元素中的span
result = html.xpath("//li[1]/descendant::span")
print(result)
# 获取该节点后面的兄弟节点以及这些兄弟节点的子孙节点
result = html.xpath("//li[1]/following::*")
print(result)
# 获取该节点后面的兄弟节点以及这些兄弟节点的子孙节点中的第一个节点
result = html.xpath("//li[1]/following::*[1]")
print(result)
# 获取该节点后面的所有兄弟节点
result = html.xpath("//li[1]/following-sibling::*")
print(result)