首页 > 其他分享 >lxml.etree 入门

lxml.etree 入门

时间:2022-10-08 19:03:16浏览次数:72  
标签:lxml etree 入门 html print root 节点


作者: Stefan Behnel
这个教学覆盖lxml 处理的主要几个方面,其中的一些功能也许能使你的码农生涯好过一点。

完整的API 请看 ​​http://lxml.de/api/index.html​​ 。

通常像下面这样导入 lxml.etree 模块:

from lxml import

Element 类

这个一个主要的类,大部分函数都通过它来进行。使用Element工厂函数很容易建立起一个xml元素。
访问标签名,用tag属性。

root = etree.Element("root")
print(root.tag) #root

添加子节点的方法之一,append方法:

root.append( etree.Element("child1") )

更有效的方法是SubElement工厂函数,使用如下:

child2 = etree.SubElement(root, "child2")
child3 = etree.SubElement(root, "child3")

这个方法,建立元素,添加子节点一步完成。

使用tostring 方法,可以看到刚才建立的 xml文件全貌。

>>>print(etree.tostring(root, pretty_print=True))
<root>
<child1/>
<child2/>
<child3/>
</root>

节点本身就是列表
节点在努力模拟Python中list的样子:
可以使用索引来获取元素
对于上面建立的xml,

child = root[0]
print(child.tag)
#child1

print(len(root))
#3

root.index(root[1]) # lxml.etree only!
#1

children = list(root)

for child in root:
print(child.tag)
#child1
#child2
#child3

root.insert(0, etree.Element("child0"))
start = root[:1]
end = root[-1:]

print(start[0].tag)
#child0
print(end[0].tag)
#child3

在ElementTree 1.3 and lxml 2.0 以前的版本中,可以使用下面的代码来判断,一个节点是否有子节点。

if root:   # this no longer works!
print("The root element has children")

但这个已经不再支持了。因为有些人认为,节点也是“某种东西”,所以对节点判断,本来就应该是True。即使这个节点没有子节点。 代替方案是用 len(element) 。

print(etree.iselement(root))  # test if it's some kind of Element
True
if len(root): # test if it has children
print("The root element has children")
#The root element has children

在lxml和Python原生的list之间,还要一点不同。请看代码

>>> for child in root:
... print(child.tag)
child0
child1
child2
child3
>>> root[0] = root[-1] # this moves the element in lxml.etree!
>>> for child in root:
...

它把最后一个元素移动到第一个位置了。

>>> l = [0, 1, 2, 3]
>>> l[0] = l[-1]
>>> l
[3, 1, 2, 3]

可是在原生的list中,只是把最后一个对象的引用拷贝到第一个位置 。也就是说同一个对象可以同时出现在不同的地方。这一点在lxml中不一样,他用的是移动,而不是拷贝。

注意在原生的ElementTree中,节点就像list一样可以复制在许多不同的地方,可这样也有一个明显的缺点,就是改变这个节点后,所有引用这个节点的地方都会一个改变,这可能不是你想要的。

Element 总是有一个确切的父节点,可以通过getparent() 方法来查询,这在原生ElementTree中并不支持。

>>> root is root[0].getparent()  # lxml.etree only!
True

既然,在lxml中的节点无法复制都是移动的形式,如果你真的是想复制,那怎么办呢?
请使用copy库的deepcopy方法。

>>> from copy import deepcopy

>>> element = etree.Element("neu")
>>> element.append( deepcopy(root[1]) )

>>> print(element[0].tag)
child1
>>> print([ c.tag for c in root ])
['child3', 'child1', 'child2']

上面这个例子展示的是,用deepcopy复制了root[1]这个元素后,并没有移动它。所有还是能在原来的root中打印出来的。

相邻元素之间的访问

>>> root[0] is root[1].getprevious() # lxml.etree only!
True
>>> root[1] is root[0].getnext() # lxml.etree only!
True

元素像字典一样携带属性。

XML节点支持属性,可以在Element函数中直接创建属性。

>>> root = etree.Element("root", interesting="totally")
>>> etree.tostring(root)
b'<root interesting="totally"/>'

属性即是无序的键值对,所以用字典可以方便的处理。

>>> print(root.get("interesting"))
totally

>>> print(root.get("hello"))
None
>>> root.set("hello", "Huhu")
>>> print(root.get("hello"))
Huhu

>>> etree.tostring(root)
b'<root interesting="totally" hello="Huhu"/>'

>>> sorted(root.keys())
['hello', 'interesting']

>>> for name, value in sorted(root.items()):
... print('%s = %r' % (name, value))
hello = 'Huhu'
interesting = 'totally'

如果你想获取字典这样的结构,就用attrib属性获取。

>>> attributes = root.attrib

>>> print(attributes["interesting"])
totally
>>> print(attributes.get("no-such-attribute"))
None

>>> attributes["hello"] = "Guten Tag"
>>> print(attributes["hello"])
Guten Tag
>>> print(root.get("hello"))
Guten Tag

attrib 是Element中支持类似字典的对象, 这意味着任何对节点的改变会反映到attrib属性,反之亦然。
只要节点的一个属性在使用中,XML就在内存中活跃着。为了得到一个独立的属性的快照,不要依赖xml tree,用copy复制一个。

>>> d = dict(root.attrib)
>>> sorted(d.items())
[('hello', 'Guten Tag'), ('interesting', 'totally')]

在节点中包含文本

在节点中可以携带文字,

>>> root = etree.Element("root")
>>> root.text = "TEXT"

>>> print(root.text)
TEXT

>>> etree.tostring(root)
b'<root>TEXT</root>'

在许多XML文档中,这是文本能存放的唯一地方,文本被包裹在节点的标签中。
然而,像XHTML这样的,文本也可能出现在不同的节点之间,或者在节点的右边。

<html><body>Hello<br/>World</body></html>

像这个例子,​​<br>​​ 这个标签被文本包围。 节点为了支持这个特性,使用了tail属性。 它包含的文本直接跟在节点后面,并且在下一个节点之前。下面是例子:

>>> html = etree.Element("html")
>>> body = etree.SubElement(html, "body")
>>> body.text = "TEXT"

>>> etree.tostring(html)
b'<html><body>TEXT</body></html>'

>>> br = etree.SubElement(body, "br")
>>> etree.tostring(html)
b'<html><body>TEXT<br/></body></html>'

>>> br.tail = "TAIL"
>>> etree.tostring(html)
b'<html><body>TEXT<br/>TAIL</body></html>'

灵活使用 .text 和 .tail 这两个属性,就可以满足任何文本插入的需要。这样,API就不需要专门的文本节点了。
然而,当你序列化一个xml时,可能并不想要tail的文本,这时,你只需要在用tostring方法时, 注意指定with_tail的值为False即可,下面是示例代码:

>>> etree.tostring(br)
b'<br/>TAIL'
>>> etree.tostring(br, with_tail=False) # lxml.etree only!
b'<br/>'

下面有个强大的功能,如果你只想要xml中间的文本,而不要任何的标签。这个有个方法可以快速搞定。
还是tostring方法,传入method关键字为 text 即可。

>>> etree.tostring(html, method="text")
b'TEXTTAIL'

比如要把word中的文本读出来,又不需要大堆的标签时。这个就派上用场了。

另一个提取文本的方法是 XPath ,并且还能把提取的文本,放入一个list中间。

>>> print(html.xpath("string()")) # lxml.etree only!
TEXTTAIL
>>> print(html.xpath("//text()")) # lxml.etree only!
['TEXT', 'TAIL']

如果你要经常用这个功能, 还可以把它封装成一个函数

>>> build_text_list = etree.XPath("//text()") # lxml.etree only!
>>> print(build_text_list(html))
['TEXT', 'TAIL']

通过XPath返回的对象有些聪明,它能够知道自己的来源。你可以通过getparent()方法,来知道它来自哪个节点。就像你通过节点直接查看那样。

>>> texts = build_text_list(html)
>>> print(texts[0])
TEXT
>>> parent = texts[0].getparent()
>>> print(parent.tag)
body

>>> print(texts[1])
TAIL
>>> print(texts[1].getparent().tag)
br

你还可以知道,这个文本是普通文本,还是tail文本。

>>> print(texts[0].is_text)
True
>>> print(texts[1].is_text)
False
>>> print(texts[1].is_tail)
True

While this works for the results of the text() function, lxml will not tell you the origin of a string value that was constructed by the XPath functions string() or concat():

当使用text()函数来获取文本时, 是可以获取parent的关系的。但是如果是用string()和concat方法,就不能获取这样的特性了。示例代码

#!/usr/local/python2.7/bin/python
#encoding=UTF-8


from lxml import etree

html = etree.Element("html")
html.text= 'abc'
html.tail= 'xyz'

ch1 =etree.SubElement(html, "child1")
ch1.text="child1"

print etree.tostring(html,pretty_print=True)

#string方法,无法获取getparent的信息
t = html.xpath("string()") # lxml.etree only!
print t.getparent()

#下面可以获取getparent的信息
t2 = html.xpath("//text()") # lxml.etree only!
print t2
for a in t2:
print

未完


标签:lxml,etree,入门,html,print,root,节点
From: https://blog.51cto.com/u_15815563/5738481

相关文章

  • 零基础如何学习入门Java编程
    如何学习在以前大部分人学习都是先去找本书,先看看,再试,要是不懂了在去网上去查,再在继续啃着书本。但现在向书学习和在网上学习这掌握的效果是不同的,要学会用适合自己的学习方......
  • Sourcetree 创建远程分支
    这里介绍下Sourcetree软件如何创建远程分支,这里只介绍在原来的项目的基础上创建远程分支工具/原料Sourcetree方法/步骤 打开Sourcetree然后打开......
  • 【百年会员】大数据从入门到入职|Hadoop|Spark|Flink|FlinkSQL|FlinkCDC|Clickhouse|
    ​关心的问题写在最前面:1.两位数学习正版大数据课程是不是骗子?本课程大部分由《实战大数据(Hadoop+Spark+Flink)》作者本人录制,前期为了做口碑,做销量,两位数可以学习全部课......
  • GooFlow入门使用
    这是用于Web端构建流程图的在线流程设计器,提供js版,Vue版,React版本,但是其为闭源项目。引入相关包<!--引入.css--><linkrel="stylesheet"type="text/css"href=".......
  • Codeforces补入门题
    CodeforcesRound#620(Div.2)LongestPalindrome题意给定n个长度为m的字符串,使用其中尽可能多的字符串构成一个回文串输出回文串长度及该回文串(顺序可以乱)分析由于......
  • gdb入门教程大全(清晰明了)
    gdb介绍gdb只是众多调试器中的一个,但是它是用得最多的,所以有必要了解一下。gdb和gcc一样,都属于gnu开源家族工具链,所以gdb对gcc编译后的程序的调试支持最好。学习一个工具,当......
  • #DAYU200#Ability入门
    坚果老师Ability入门Ability在英文中是能力的意思,在这里是指应用所具备能力的抽象,同时是应用程序的重要组成部分。一个应用可以包含一个或多个FA/PA,其中,FA有UI界面,提供与......
  • Beats 入门实战(1)--简介
    Beats是轻量级(资源高效,无依赖性,小型)和开放源代码日志发送程序的集合,这些日志发送程序充当安装在基础结构中不同服务器上的代理,用于收集日志或指标;本文主要介绍Beats的理......
  • spring boot集成redis基础入门
    redis支持持久化数据,不仅支持key-value类型的数据,还拥有list,set,zset,hash等数据结构的存储。可以进行master-slave模式的数据备份更多redis相关文档请查看redis官方文......
  • JavaWeb/JavaEE开发入门(概述-总纲)
    作为初学者的浅知薄见,漫谈概览.欢迎指正和交流.1.从SE到Web到EE开发刚入门Java开发的时候,即使对于计算机网络有所了解,但是对于从围绕JDK展开学习的JavaSE的过程......