作者:Shane
出处:http://bluescorpio.cnblogs.com

lxml takes all the pain out of XML.
Stephan Richter

lxml是Python语言里和XML以及HTML工作的功能最丰富和最容易使用的库。lxml是为libxml2和libxslt库的一个Python化的绑定。它与众不同的地方是它兼顾了这些库的速度和功能完整性,以及纯Python API的简洁性,大部分与熟知的ElementTree API兼容但比之更优越。

安装lxml:

要求:需要Python2.3或更后的版本

使用easy_install工具,以超级用户或管理员的角色run下面的命令:

easy_install lxml

在windows下,最好指定版本号:easy_install lxml==2.2.6

使用lxml进行开发

lxml.etree指南

通常使用lxml.etree的方式

>>> from lxml import etree

Element类,一个Element是ElementTree API的主要容器类,大部分的XML tree功能都是通过这个类来访问的。Elements可以非常容易地通过Element工厂方法来创建。

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

元素的XML tag名字是通过tag属性来访问的

>>> print root.tag # root

Elements是在XML树状结构中组织的,为创建子元素并将它们加到父元素上,可以使用append()方法。

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

我们还有更高效的方法:SubElement工厂方法,它使用和Element工厂方法相同的参数,不过额外需要父节点作第一个参数:

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

可以使用tostring()方法来看得到的XML

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

元素是列表

>>> 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

可以使用insert()方法插入新的子节点:

>>> root.insert(0, etree.Element("child0"))
删除子节点:

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

如果想把一个元素拷贝到不同的地方,需要创建一个独立的deep copy。

>>> 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’]

getparent()返回父节点:
>>> root is root[0].getparent() # lxml.etree only!
True

元素的兄弟或邻居节点是通过next和previous属性来访问的
The siblings (or neighbours) of an element are accessed as next and previous elements:
>>> 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"/>’

可以使用set和get方法访问这些属性:

>>> print root.get("interesting")
totally
>>> root.set("interesting", "somewhat")
>>> print root.get("interesting")
somewhat

也可以使用attrib性质的字典接口

>>> attributes = root.attrib
>>> print(attributes["interesting"])
somewhat
>>> print(attributes.get("hello"))
None
>>> attributes["hello"] = "Guten Tag"
>>> print(attributes.get("hello"))
Guten Tag
>>> print(root.get("hello"))
Guten Tag

元素可以包含文字:

>>> root = etree.Element("root")
>>> root.text = "TEXT"
>>> print(root.text)
TEXT
>>> etree.tostring(root)
’<root>TEXT</root>’

如果XML用在(X)HTML中,文本也可以在不同的元素中显示:
<html><body>Hello<br/>World</body></html>
元素有tail属性,它包含XML 树中元素直接跟的,直到下个元素的文本。

>>> 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>’

使用XPath查找文本

另一个抽取XML树的文本内容是XPath,
>>> 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’]

也可以通过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
You can also find out if it’s normal text content or tail text:
>>> print(texts[0].is_text)
True
>>> print(texts[1].is_text)
False
>>> print(texts[1].is_tail)
True

树的迭代:

Elements提供一个树的迭代器可以迭代访问树的元素。

>>> root = etree.Element("root")
>>> etree.SubElement(root, "child").text = "Child 1"
>>> etree.SubElement(root, "child").text = "Child 2"
>>> etree.SubElement(root, "another").text = "Child 3"
>>> print(etree.tostring(root, pretty_print=True))
<root>
<child>Child 1</child>
<child>Child 2</child>
<another>Child 3</another>
</root>

>>> for element in root.iter():
... print("%s - %s" % (element.tag, element.text))
root – None
child - Child 1
child - Child 2
another - Child 3

如果知道感兴趣的tag,可以把tag的名字传给iter方法,起到过滤作用。

>>> for element in root.iter("child"):
... print("%s - %s" % (element.tag, element.text))
child - Child 1
child - Child 2

默认情况下,迭代器得到一个树的所有节点,包括ProcessingInstructions, Comments and Entity的实例。如果想确认只有Elements对象返回,可以把Element factory作为参数传入。

>>> root.append(etree.Entity("#234"))
>>> root.append(etree.Comment("some comment"))
>>> for element in root.iter():
... if isinstance(element.tag, basestring):
... print("%s - %s" % (element.tag, element.text))
... else:
... print("SPECIAL: %s - %s" % (element, element.text))
root - None
child - Child 1
child - Child 2
another - Child 3
SPECIAL: ê - ê
SPECIAL: <!--some comment--> - some comment

>>> for element in root.iter(tag=etree.Element):
... print("%s - %s" % (element.tag, element.text))
root - None
child - Child 1
child - Child 2
another - Child 3
>>> for element in root.iter(tag=etree.Entity):
... print(element.text)

序列化:

序列化通常使用tostring()方法来返回一个字符串,或者ElementTree.write()方法来写入一个文件,一个类文件的对象,或者一个URL(通过FTP的PUT或者HTTP的POST)。二者都使用相同的关键字参数比如pretty_print来格式化输出或者encoding来选择一个特定的输出编码而不是简单的ASCII。
>>> root = etree.XML("<root><a><b/></a></root>")
>>> etree.tostring(root)
’<root><a><b/></a></root>’

>>> print etree.tostring(root, xml_declaration=True)
<?xml version=’1.0’ encoding=’ASCII’?>
<root><a><b/></a></root>

>>> print etree.tostring(root, encoding="iso-8859-1")
<?xml version=’1.0’ encoding=’iso-8859-1’?>
<root><a><b/></a></root>

>>> print etree.tostring(root, pretty_print=True)
<root>
<a>
<b/>
</a>
</root>

Note that pretty printing appends a newline at the end.

注意pretty打印在末尾添加一个新行。

从lxml2.0起,serialisation可以做的不止XML序列化,可以序列化到HTML或者通过传递函数关键字来提取文本内容。

>>> root = etree.XML("<html><head/><body><p>Hello<br/>World</p></body></html>")
>>> etree.tostring(root) # default: method = ’xml’
’<html><head/><body><p>Hello<br/>World</p></body></html>’
>>> etree.tostring(root, method="xml") # same as above
’<html><head/><body><p>Hello<br/>World</p></body></html>’
>>> etree.tostring(root, method="html")
’<html><head></head><body><p>Hello<br>World</p></body></html>’

>>> print etree.tostring(root, method="html", pretty_print=True)
<html>
<head></head>
<body><p>Hello<br>World</p></body>
</html>

>>> etree.tostring(root, method="text")
b’HelloWorld’

对XML序列化而言,默认的文本编码是ASCII

>>> br = root.find(".//br")
>>> br.tail = u"W/xf6rld"
>>> etree.tostring(root, method="text") # doctest: +ELLIPSIS
Traceback (most recent call last):
...
UnicodeEncodeError: ’ascii’ codec can’t encode character u’/xf6’ ...
>>>etree.tostring(root, method="text", encoding="UTF-8")
b’HelloW/xc3/xb6rld’

>>> etree.tostring(root, encoding=unicode, method="text")
u’HelloW/xf6rld’

ElementTree类:

一个ElementTree主要是围绕在一个有根节点的树的文档包装类。它提供了很多方法来解析,序列化以及一般的文档处理。一个最大的区别是它作为一个整体文档来序列化。与之相对的是序列化成单个的元素。

>>> tree = etree.parse(StringIO("""/
 <?xml version="1.0"?>
 <!DOCTYPE root SYSTEM "test" [ <!ENTITY tasty "eggs"> ]>
 <root>
 <a>&tasty;</a>
 </root>
 """))
>>> print(tree.docinfo.doctype)
<!DOCTYPE root SYSTEM "test">

>>> # lxml 1.3.4 and later
>>> print(etree.tostring(tree))
<!DOCTYPE root SYSTEM "test" [
<!ENTITY tasty "eggs">
]>
<root>
<a>eggs</a>
</root>

>>> # lxml 1.3.4 and later
>>> print(etree.tostring(etree.ElementTree(tree.getroot())))
<!DOCTYPE root SYSTEM "test" [
<!ENTITY tasty "eggs">
]>
<root>
<a>eggs</a>
</root>

>>> # ElementTree and lxml <= 1.3.3
>>> print(etree.tostring(tree.getroot()))
<root>
<a>eggs</a>
</root>

从字符串和文件中解析:

fromstring()是解析字符串最容易的方法

>>> some_xml_data = "<root>data</root>"
>>> root = etree.fromstring(some_xml_data)
>>> print root.tag
root
>>> etree.tostring(root)
’<root>data</root>’

XML()方法和fromstring()方法类似,但它主要用来把XML文字写入源文件。
>>> root = etree.XML("<root>data</root>")
>>> print root.tag
root
>>> etree.tostring(root)
’<root>data</root>’

parse()方法用来从文件或者类文件对象中解析
>>> some_file_like = StringIO.StringIO("<root>data</root>")
>>> tree = etree.parse(some_file_like)
>>> etree.tostring(tree)
’<root>data</root>’

注意parse()返回的是一个ElementTree对象,而不是字符串解析方法的Element对象。

>>> root = tree.getroot()
>>> print root.tag
root
>>> etree.tostring(root)
’<root>data</root>’

解析器对象:lxml.etree在默认情况下使用带默认配置的标准解析器,如果想配置解析器,可以创建自己的实例。

>>> parser = etree.XMLParser(remove_blank_text=True) # lxml.etree only!

本例在解析的时候创建了一个移除tags之间的空的文本的解析器,这可以减少tree的大小以及避免不定的tail,如果你知道空白内容对你来说是没有任何意义的话。

>>> root = etree.XML("<root> <a/> <b> </b> </root>", parser)
>>> etree.tostring(root)
b’<root><a/><b> </b></root>’
>>> for element in root.iter("*"):
... if element.text is not None and not element.text.strip():
... element.text = None
>>> etree.tostring(root)
b’<root><a/><b/></root>’

递增解析:

lxml.etree提供了两种方法来实现递增的逐步的解析。一个方法是通过类文件对象,它重复调用read() 方法。
>>> class DataSource:
... data = [ b"<roo", b"t><", b"a/", b"><", b"/root>" ]
... def read(self, requested_size):
... try:
... return self.data.pop(0)
... except IndexError:
... return b’’
>>> tree = etree.parse(DataSource())
>>> etree.tostring(tree)
b’<root><a/></root>’

第二个方法是通过feed解析器接口,由feed(data) 和 close() 方法提供

>>> parser = etree.XMLParser()
>>> parser.feed("<roo")
>>> parser.feed("t><")
>>> parser.feed("a/")
>>> parser.feed("><")
>>> parser.feed("/root>")

>>> root = parser.close()
>>> etree.tostring(root)
’<root><a/></root>’

在调用close() 方法(或者当有exception发生的时候),可以通过调用feed() 方法重新使用parser:
>>> parser.feed("<root/>")
>>> root = parser.close()
>>> etree.tostring(root)
b’<root/>’

Python之lxml的更多相关文章

  1. Windows下Python安装lxml

    1.下载easy_install的安装包,下载地址:https://pypi.Python.org/pypi/setuptools 我是Windows7,所以直接下载Windows(Simplify) ...

  2. 【python】lxml中多个xml采用相同节点时出现的问题

    今天突然发现了一个lxml的坑. 假设我们有一个节点 <id>123</id> 有两个父节点都要用上述节点,则必须把上面的节点写两遍!用同一个会出错! 出错例子: #!/usr ...

  3. 【python】lxml

    来源:http://lxml.de/tutorial.html lxml是python中处理xml的一个非常强大的库,可以非常方便的解析和生成xml文件.下面的内容翻译了链接中的一部分 1.生成空xm ...

  4. 【python】lxml查找属性为指定值的节点

    假设有如下xml在/home/abc.xml位置 <A> <B id=" name="apple"/> <B id=" name= ...

  5. 在MacOS下Python安装lxml报错xmlversion.h not found 报错的解决方案

    最近在看一个自动化测试框架的问题,需要用到Lxml库,下载lxml总是报错. 1,使用pip安装lxml pip install lxml 2,然后报错了,报错内容是: In file include ...

  6. Python使用lxml模块和Requests模块抓取HTML页面的教程

    Web抓取Web站点使用HTML描述,这意味着每个web页面是一个结构化的文档.有时从中 获取数据同时保持它的结构是有用的.web站点不总是以容易处理的格式, 如 csv 或者 json 提供它们的数 ...

  7. Python 安装 lxml 插件

    1.下载 lxml 地址:https://pypi.python.org/pypi/lxml/3.8.0#downloads 我用的是python 3.6,我下载了  lxml-3.8.0-cp36- ...

  8. windows下使用pip安装python模块lxml

    pip install lxml 1 1 会有如下问题:  结果一路解决下去,解决了一个坑还是有一个坑,遂放弃,查找有没有别的解决办法. 亲测使用wheel+pip可以成功安装lxml! wheel本 ...

  9. 【Python】Python加lxml实现图片解析下载功能

    1.下载网页:OpenHtml.py import urllib.request from urllib.parse import quote class HtmlLoader(object): de ...

随机推荐

  1. ORM和Core

    .net  core中有哪些被抛弃的类 1.DataTable DataRow SqlDataAdapter DataRow DataColumn DataColumn 虽然这些类不是我ORM核心功能 ...

  2. Hibernate的Criteria用法

    在hibernate的Session里面使用createCriteria可以创建一个Criteria实例帮助我们进行条件查询,不用自己串hql语句,很方便. 用法很简单,首先传Class实例创建Cri ...

  3. IC卡、M1卡、CPU卡、SAM卡、PSAM卡的联系与区别

    一. 技术方面(非接触式IC卡)  1. 逻辑加密卡又叫存储卡,卡内的集成电路具有加密逻辑和EEPROM(电可擦除可编程只读存储器).  2. CPU卡又叫智能卡,卡内的集成电路包括中央处理器(CPU ...

  4. Unity3d GUI弹窗

    ArrayList w_position = new ArrayList(); void OnGUI() { if (GUILayout.Button("Open")) { if ...

  5. mysql 存储过程 动态sql例子

    proc:BEGIN ; ; ; ) DEFAULT ''; ) DEFAULT ''; ) DEFAULT '';#插入日志的表,一个活动一张表 #将局部变量转换成会话变量 #动态sql语言只接受会 ...

  6. mysql允许远程IP访问

    默认情况下Linux内的mysql数据库mysql,user表内的用户权限只是对localhost即本机才能登陆.需要更改权限: mysql> Grant all privileges on * ...

  7. [置顶] 通过实例学习Struts2 (1)

    前言 一直用Struts1 , 现在新的项目要转向Struts2了, 先研究学习一下,做点技术储备. 我一直认为计算机软件行业是一个实践性非常强的行业,书读了多少都不管用, 一定要卷起袖子,亲自动手, ...

  8. android 开发代码被黑客破译有那么容易吗?

    很多程序员辛辛苦苦开发出的android开发代码,很容易就被黑客翻译了. Google似乎也发现了这个问题,从SDK2.3开始我们可以看到在android-sdk-windows\tools\下面多了 ...

  9. 使用SuperWebSocket 构建实时 Web 应用

    Web 应用的信息交互过程通常是客户端通过浏览器发出一个请求,服务器端接收和审核完请求后进行处理并返回结果给客户端,然后客户端浏览器将信息呈现出来,这种机制对于信息变化不是特别频繁的应用尚能相安无事, ...

  10. DOM缘起

    DOM是现在按W3C标准的浏览器均实现的标准.HTML.CSS.DOM共同在结构.表现.交互上共同支撑起一个页面.当然,必须以用户为中心.平稳退化.逐渐增强.DOM的操作是通过JS来实现的.JS最初在 ...