简介
HTML解析工具、HTML页面生成工具。
安装
pip install lxml
文档查询
Element类
可以直观的理解为XML的节点
Element 是 ElementTree API 的主要容器对象。大多数 XML 树功能可通过此类进行访问
Element类(参考代码)
XML增删改
from lxml import etree
""" 节点创建 """
root = etree.Element("root")
""" 节点创建+属性创建 """
root = etree.Element("root", dataName="自定义属性")
""" 属性 """
root.get("dataName") # 获取指定属性
sorted(root.keys()) # 获取所有属性
attributes = root.attrib
attributes["dataName"] = "修改的属性" # 修改属性值
""" 节点内容创建 """
root.text = "这是一段内容"
""" 节点名称 """
root.tag
""" 子节点创建 """
child2 = etree.SubElement(root, "child2")
child3 = etree.SubElement(root, "child3")
""" 序列化已创建的XML """
htmlText = etree.tostring(root, pretty_print=True)
print(htmlText)
""" 访问元素 """
child = root[0] # 索引方式获取
child.tag
len(root) # 统计子节点数量
root.index(root[1]) # 获取节点的索引位置
list(root) # 转化为列表
""" 插入元素 """
root.insert(0, etree.Element("child0")) # 创建的节点插入到,索引为0的位置
""" 节点跳转 """
root[0].getparent() # 父节点
root[0] is root[1].getprevious() # 上一个节点
root[1] is root[0].getnext() # 下一个节点
""" 删除 """
root.remove(root[0])
toString序列化
from lxml import etree
root = etree.XML('<root><a><b/></a></root>')
''' 【默认输出】 '''
etree.tostring(root)
# >>> b'<root><a><b/></a></root>'
''' 【XML格式】 '''
print(etree.tostring(root, xml_declaration=True))
# >>> b"<?xml version='1.0' encoding='ASCII'?>\n<root><a><b/></a></root>"
''' 【编码】 '''
print(etree.tostring(root, encoding='iso-8859-1'))
''' 【漂亮打印】 '''
print(etree.tostring(root, pretty_print=True))
''' 【提取内容】 '''
root = etree.XML('<html><head/><body><p>Hello<br/>World</p></body></html>')
etree.tostring(root, method='text')
# >>> b'HelloWorld'
HTML构造
from lxml import etree
root = etree.Element("p", data="txt")
root.text = "Hello,World!"
print(root.text) # >>> Hello,World!
print(etree.tostring(root)) # >>> b'<p data="txt">Hello,World!</p>'
html = etree.Element("html")
body = etree.SubElement(html, "body") # 添加节点
body.text = "Text"
print(etree.tostring(html)) # b'<html><body>Text</body></html>'
ElementTree类
ElementTree 主要是围绕树的文档包装器,带有根节点。
大部分方法与Element类相同。
ElementTree类(参考代码)
HTML构造器
E-factory 提供了一种简单而紧凑的语法,用于生成 XML 和 HTML格式。
from lxml.builder import E
from lxml import etree
def CLASS(*args): # class is a reserved word in Python
return {"class": " ".join(args)}
html = page = E.html( # create an Element called "html"
E.head(E.title("This is a sample document")),
E.body(
E.h1("Hello!", CLASS("title")),
E.p("This is a paragraph with ", E.b("bold"), " text in it!"),
E.p(
"This is another paragraph, with a",
"\n ",
E.a("link", href="http://www.python.org"),
".",
),
E.p("Here are some reserved characters: <spam&egg>."),
etree.XML("<p>And finally an embedded XHTML fragment.</p>"),
),
)
print(etree.tostring(page, pretty_print=True))
# >>>
'''
<html>
<head>
<title>This is a sample document</title>
</head>
<body>
<h1 class="title">Hello!</h1>
<p>This is a paragraph with <b>bold</b> text in it!</p>
<p>This is another paragraph, with a
<a href="http://www.python.org">link</a>.</p>
<p>Here are some reserved characters: <spam&egg>.</p>
<p>And finally an embedded XHTML fragment.</p>
</body>
</html>
'''
字符串和文件解析
常用解析函数
etree.XMLParser | 创建解析器 【删除空文本】 etree.XMLParser(remove_blank_text=True) |
etree.fromstring | 解析字符串 |
etree.XML | 解析XML对象 |
etree.HTML | 解析HTML对象 |
etree.parse | 解析文件类型对象 【提示】 parse() 返回一个 ElementTree 对象,而不是一个 Element 对象 |
Xpath
Xpath路径
- element.xpath(path) 指定在某个element,指定使用
- etree.xpath(path) 包装在一个函数,频繁使用
Xpath(参数列表)
Xpath元素路径 | |
iterfind() | 遍历与路径匹配的所有元素 表达 |
findall() | 返回匹配元素的列表 |
find() | 有效地只返回第一个匹配项 |
findtext() | 返回第一个匹配项的 .text 内容 |
Xpath提取内容 | |
string() | 返回字符串 |
text() | 返回列表 |
Xpath常用规则 | |
nodename | 选取此节点的所有子节点 【例子】 bookstore(选取 bookstore 元素的所有子节点。) |
/ | 从当前节点选取直接子节点 【例子】 /bookstore(选取根元素 bookstore。) bookstore/book (选取属于 bookstore 的子元素的所有 book 元素。) |
// | 从当前节点选取子孙节点 【例子】 //book(选取所有 book 子元素,不限位置) |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 【例子】 //@lang(选取名为 lang 的所有属性。) |
* | 通配符 【例子】 /bookstore/*(选取 bookstore 元素的所有子元素。) //*(选取文档中的所有元素。) |
@* | 选取所有属性 【例子】 //title[@*](选取所有带有属性的 title 元素。) |
[@attrib] | 选取具有给定属性的所有元素 |
[@attrib='value'] | 选取给定属性具有给定值的所有属性 |
[tag] | 选取所有具有指定元素的直接子节点 |
[tag='text'] | 选取所有具有指定元素并且文本内容是text节点 |
Xpath运算符 | |||
运算符 | 描述 | 实例 | 返回值 |
or | 或 | age=19 or age=20 | 如果age等于19或者等于20则返回true反正返回false |
and | 与 | age>19 and age<21 | 如果age等于20则返回true,否则返回false |
mod | 取余 | 5 mod 2 | 1 |
| | 取两个节点的集合 | //book | //cd | 返回所有拥有book和cd元素的节点集合 |
+ | 加 | 6+4 | 10 |
- | 减 | 6-4 | 2 |
* | 乘 | 6*4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | age=19 | true |
!= | 不等于 | age!=19 | true |
< | 小于 | age<19 | true |
<= | 小于或等于 | age<=19 | true |
> | 大于 | age>19 | true |
>= | 大于或等于 | age>=19 | true |
Xpath常用函数 | |
contains(string1,string2) | 如果 string1 包含 string2,则返回 true,否则返回 false。 例子:contains(@classs,”classame“) 结果:true |
name() | 返回当前节点的名称或指定节点集中的第一个节点。 |
position() | 返回当前正在被处理的节点的 index 位置。 例子://book[position()<=3] 结果:选择前三个 book 元素 |
last() | 返回在被处理的节点列表中的项目数目 例子://book[last()] 结果:选择最后一个 book 元素 |
更多函数了解 | https://www.w3school.com.cn/xpath/xpath_functions.asp |
Xpath节点 | |
ancestor | 选取当前节点的所有先辈(父、祖父等)。 【例子】 ancestor::book 选择当前节点的所有 book 先辈。 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 【例子】 ancestor-or-self::book 选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点) |
attribute | 选取当前节点的所有属性。 【例子】 attribute::lang 选取当前节点的 lang 属性。 attribute::* 选取当前节点的所有属性。 |
child | 选取当前节点的所有子元素。 【例子】 child::book 选取所有属于当前节点的子元素的 book 节点。 child::* 选取当前节点的所有子元素。 child::text() 选取当前节点的所有文本子节点。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 【例子】 descendant::book 选取当前节点的所有 book 后代。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
namespace | 选取当前节点的所有命名空间节点。 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
self | 选取当前节点。 |
Xpath谓语 | |
表达式 | 结果 |
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()<3] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang='eng'] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
Xpath更多获取 | |
路径表达式 | 结果 |
//book/title | //book/price | 选取 book 元素的所有 title 和 price 元素。 |
//title | //price | 选取文档中的所有 title 和 price 元素。 |
/bookstore/book/title | //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |
Xpath(参考代码)
HTML文件解析
from lxml import etree
xp = etree.parse("123.html", etree.HTMLParser()) # HTMLParser 指定解析器
#'//td[@class='xxx']/text()' # 获取td 指定类型下的内容
htm = xp.xpath("//*") # 获取所有//下的所有节点
print(htm)
HTML解码输出
from lxml import etree
e_text = """
<div>
<ul>
<li class='item-0'><a href='link1.html'>第一个</a></li>
<li class='item-1'><a href='link2.html'>second item</a></li>
<li class='item-0'><a href='link5.html'>a属性</a>
</ul>
</div>
"""
html = etree.HTML(e_text) # 解析HTML
result = etree.tostring(html).decode("utf-8") # 将字符串序列化为html
print(result) # 输出HTML内容
获取内容(创建功能函数获取内容)
# ======解析HTML文件======#
from lxml import etree
e_text = """
<div>
<ul>
<li class='item-0'><a href='link1.html'>第一个</a></li>
<li class='item-1'><a href='link2.html'>second item</a></li>
<li class='item-0'><a href='link5.html'>a属性</a>
</ul>
</div>
"""
text = e_text
text = etree.HTML(text)
''' 方式一(获取内容)'''
st1 = text.xpath("string()")
st1 = [x.strip() for x in st1.split("\n") if x.strip() != ""]
print(st1) # >>> ['第一个', 'second item', 'a属性']
''' 方式二(获取内容)'''
content = text.xpath("//text()")
st2 = [x.strip() for x in content if x.strip() != ""]
print(st2) # >>> ['第一个', 'second item', 'a属性']
# 获取所属节点
parent = content[0].getparent()
print(parent.tag) # >>> div
获取内容(HTML解析器获取内容)
from lxml import etree
html = """
<html>
<head>
<title>网页标题</title>
</head>
<body>
<h1>欢迎使用lxml</h1>
<p>这是一个示例文档</p>
</body>
</html>
"""
# 创建解析器
parser = etree.HTMLParser()
tree = etree.fromstring(html, parser)
# 获取标题
title = tree.findtext('.//title')
print(title) # >>> 网页标题
元素路径(综合例子)
from lxml import etree
root = etree.XML("<root><a x='123'>aText<b/><c/><b/></a></root>")
''' 获取内容 '''
print(root.find(".//b").tag) # >>> b
[ b.tag for b in root.iterfind(".//b") ] # >>> ['b', 'b']
print(root.findall(".//a[@x]")[0].tag) # >>> a
''' 获取元素路径 '''
tree = etree.ElementTree(root)
a = root[0]
print(tree.getelementpath(a[0])) # >>> a/b[1]
print(tree.getelementpath(a[1])) # >>> a/c
tree.find(tree.getelementpath(a[2])) == a[2] # >>> True
元素路径(进阶搜索)
''' 加入函数或运算符,筛选获取的内容 '''
from lxml import etree
text1="""
<div>
<ul>
<li class="aaa" name="item"><a href="link1.html">第一个</a></li>
<li class="aaa" name="item"><a href="link1.html">第二个</a></li>
<li class="aaa" name="item"><a href="link1.html">第三个</a></li>
<li class="aaa" name="item"><a href="link1.html">第四个</a></li>
</ul>
</div>
"""
html=etree.HTML(text1,etree.HTMLParser())
r0=html.xpath('//li[contains(@class,"aaa")]/a/text()')
# >>> ['第一个', '第二个', '第三个', '第四个']
r1=html.xpath('//li[2][contains(@class,"aaa")]/a/text()')
# >>> ["第二个"]
r2=html.xpath('//li[last()][contains(@class,"aaa")]/a/text()')
# >>> ["第四个"]
r3=html.xpath('//li[position()>2 and position()<4][contains(@class,"aaa")]/a/text()')
# >>> ["第三个"]
r4=html.xpath('//li[last()-2][contains(@class,"aaa")]/a/text()')
# >>> ["第二个"]
获取节点
from lxml import etree
text1 = """
<div>
<ul>
<li class="aaa" name="item"><a href="link1.html">第一个</a></li>
<li class="aaa" name="item"><a href="link1.html">第二个</a></li>
<li class="aaa" name="item"><a href="link1.html">第三个</a></li>
<li class="aaa" name="item"><a href="link1.html">第四个</a></li>
</ul>
</div>
"""
html = etree.HTML(text1, etree.HTMLParser())
''' 获取所有祖先节点 '''
r0 = html.xpath("//li[1]/ancestor::*")
r0 = [x.tag for x in r0] # >>> ['html', 'body', 'div', 'ul']
''' 获取div祖先节点 '''
r1 = html.xpath("//li[1]/ancestor::div")
r1 = [x.tag for x in r1] # >>> ['div']
''' 获取所有属性值 '''
r2 = html.xpath("//li[1]/attribute::*")
''' 获取所有直接子节点 '''
r3 = html.xpath("//li[1]/child::*")
r3 = [x.tag for x in r3] # >>> ['aaa', 'item']
''' 获取所有子孙节点的a节点 '''
r4 = html.xpath("//li[1]/descendant::a")
r4 = [x.tag for x in r4] # >>> ['a']
''' 获取当前子节之后的所有节点 '''
r5 = html.xpath("//li[1]/following::*")
r5 = [x.tag for x in r5] # >>> ['a']
''' 获取当前节点的所有同级节点 '''
r6 = html.xpath("//li[1]/following-sibling::*")
r6 = [x.tag for x in r6] # >>> ['li', 'a', 'li', 'a', 'li', 'a']
其它API
lxml.html
基于 lxml 的 HTML 解析器, 但为 HTML 元素提供了一个特殊的 Element API,以及 用于常见 HTML 处理任务的实用程序数量。
适用于快速生成HTML页面
lxml.html(参考代码)
创建HTML
import lxml.html
from lxml.html import builder as E
html = E.HTML(
E.HEAD(
E.LINK(rel="stylesheet", href="great.css", type="text/css"),
E.TITLE("Best Page Ever"),
),
E.BODY(
E.H1(E.CLASS("heading"), "Top News"),
E.P("start...", style="font-size: 200%"),
"###########",
E.P("end...", id="txt", data_value="1", style="font-size:16px;"),
lxml.html.fromstring("<p>xxxxxxxxxx</p>"),
),
)
print(lxml.html.tostring(html))
# >>>
"""
<html>
<head>
<link rel="stylesheet" href="great.css" type="text/css" />
<title>Best Page Ever</title>
</head>
<body>
<h1 class="heading">Top News</h1>
<p style="font-size: 200%">start...</p>
###########
<p id="txt" data_value="1" style="font-size: 16px">end...</p>
<p>xxxxxxxxxx</p>
</body>
</html>
"""