篇文章主要介绍libxml2的安装和使用,xml文件的主要作用就是配置文件,实际的应用在前面的章节Audio设备文件解析中有需要对audio_policy_configuration.xml文件解析,google使用的是开源库libxml2,在源码目录/external/libxml2下面,现在就单独对这个库进行分析。
在终端中执行
wang@wang:~/test$ sudo apt-get install libxml2-dev
wang@wang:~/test$ sudo apt-get install libxml2
可以通过
wang@wang:~/test$ dpkg -s libxml2-dev
查看安装状况。
Package: libxml2-dev Status: install ok installed Priority: optional Section: libdevel Installed-Size: 2862 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> Architecture: amd64 Multi-Arch: same Source: libxml2 Version: 2.9.1+dfsg1-3ubuntu4.12 Depends: libxml2 (=2.9.1+dfsg1-3ubuntu4.12) Suggests: pkg-config Description: Development files for the GNOME XML library XML is a metalanguage to let you design your own markup language. A regular markup language defines a way to describe information in a certain class of documents (eg HTML). XML lets you define your own customized markup languages for many classes of document. It can do this because it's written in SGML, the international standard metalanguage for markup languages. . Install this package if you wish to develop your own programs using the GNOME XML library. Homepage: http://xmlsoft.org/
通过执行
wang@wang:~/test$ dpkg -L libxml2-dev
查看安装位置
/usr/include/libxml2 /usr/include/libxml2/libxml /usr/include/libxml2/libxml/xpointer.h /usr/include/libxml2/libxml/catalog.h /usr/include/libxml2/libxml/xmlreader.h /usr/include/libxml2/libxml/xmlexports.h
已经安装成功。
#include<stdio.h> #include<libxml/parser.h> #include<libxml/tree.h> int main(int argc, char **argv) { //Define document pointer xmlDocPtr doc=xmlNewDoc(BAD_CAST"1.0"); //Define node pointer xmlNodePtr root_node=xmlNewNode(NULL,BAD_CAST"root"); //Set the root element of the document xmlDocSetRootElement(doc,root_node); //Create child nodes directly in the root node xmlNewTextChild(root_node,NULL,BAD_CAST"newnode1",BAD_CAST"newnode1 content"); xmlNewTextChild(root_node,NULL,BAD_CAST"newnode2",BAD_CAST"newnode2 content"); //Create a new node xmlNodePtr node=xmlNewNode(NULL,BAD_CAST"node2"); //Create a new text node xmlNodePtr content=xmlNewText(BAD_CAST"NODE CONTENT"); //Add a new node to parent xmlAddChild(root_node,node); xmlAddChild(node,content); //Create a new property carried by a node xmlNewProp(node,BAD_CAST"attribute",BAD_CAST"yes"); //Create a son and grandson node element node=xmlNewNode(NULL,BAD_CAST"son"); xmlAddChild(root_node,node); xmlNodePtr grandson=xmlNewNode(NULL,BAD_CAST"grandson"); xmlAddChild(node,grandson); xmlAddChild(grandson,xmlNewText(BAD_CAST"THis is a grandson node")); //Dump an XML document to a file int nRel=xmlSaveFile("CreatedXmlDemo.xml",doc); if(nRel !=-1) { //Free up all the structures used by a document,tree included xmlFreeDoc(doc); } return 0; }
编译
wang@wang:~/test$ gcc -I/usr/include/libxml2 CreateXmlFile.c -o CreateXmlFile -lxml2
可以看到执行结果
wang@wang:~/test$ gcc -I/usr/include/libxml2 CreateXmlFile.c -o CreateXmlFile -lxml2 wang@wang:~/test$ ./CreateXmlFile wang@wang:~/test& ls CreatedXmlDemo.xml CreateXmlFile
使用html打开生成的文件
最后,如果你想学C/C++可以私信小编“01”获取素材资料以及开发工具和听课权限哦!
XML是Python中一个强大的XML和HTML处理库,它是基于libxml2和libxslt库构建的,并提供了一系列方便的API来处理XML和HTML文档。在本教程中,我们将学习如何使用LXML库来解析、操作和生成XML和HTML文档。
在使用LXML库之前,我们需要先安装它。可以使用pip命令来安装:
pip install lxml
LXML库提供了两种解析器,即ElementTree和SAX解析器。ElementTree解析器将整个XML/HTML文档解析成一个树形结构,而SAX解析器则是基于事件的解析器,逐个处理文档中的标记。
我们可以使用ElementTree解析器来解析XML/HTML文档。首先,我们需要使用lxml.etree.parse()函数来读取XML/HTML文档并解析它。
from lxml import etree
# 读取XML文件并解析
tree=etree.parse("example.xml")
# 获取根元素
root=tree.getroot()
# 打印根元素的标签和属性
print("root tag:", root.tag)
print("root attributes:", root.attrib)
# 遍历树结构并打印标签和文本内容
for element in root.iter():
print("tag:", element.tag, "text:", element.text)
我们可以使用lxml.sax模块中的saxparser来处理XML/HTML文档。首先,我们需要定义一个继承自lxml.sax.ContentHandler类的处理器类,然后使用lxml.sax.parse()函数来解析XML/HTML文档并将其传递给处理器类。
from lxml import etree, sax
# 定义处理器类
class MyHandler(sax.ContentHandler):
def __init__(self):
super().__init__()
def startElement(self, name, attrs):
print("start element:", name)
for attr in attrs.items():
print("attribute:", attr)
def endElement(self, name):
print("end element:", name)
def characters(self, content):
print("characters:", content)
# 解析XML文件
parser=sax.make_parser()
parser.setContentHandler(MyHandler())
parser.parse("example.xml")
LXML库提供了一系列方便的API来操作XML和HTML文档。我们可以使用这些API来添加、删除、修改和查询文档中的元素和属性。
我们可以使用Element对象的append()方法来添加子元素,使用Element对象的set()方法来添加属性。
from lxml import etree
# 读取XML文件并解析
tree=etree.parse("example.xml")
root=tree.getroot()
# 添加子元素
new_element=etree.Element("new_element")
root.append(new_element)
# 添加属性
new_element.set("attr1", "value1")
new_element.set("attr2", "value2")
# 保存修改后的文档
tree.write("example.xml", encoding="utf-8")
我们可以使用Element对象的remove()方法来删除元素,使用Element对象的attrib.pop()方法来删除属性。
from lxml import etree
# 读取XML文件并解析
tree=etree.parse("example.xml")
root=tree.getroot()
# 查找要删除的元素
element_to_delete=root.find(".//element_to_delete")
# 删除元素
root.remove(element_to_delete)
# 删除属性
root.attrib.pop("attr_to_delete")
# 保存修改后的文档
tree.write("example.xml", encoding="utf-8")
我们可以使用Element对象的find()方法和Element对象的text属性来修改元素的文本内容,使用Element对象的set()方法来修改属性的值。
from lxml import etree
# 读取XML文件并解析
tree=etree.parse("example.xml")
root=tree.getroot()
# 查找要修改的元素
element_to_modify=root.find(".//element_to_modify")
# 修改元素文本内容
element_to_modify.text="new text content"
# 修改属性值
element_to_modify.set("attr_to_modify", "new attribute value")
# 保存修改后的文档
tree.write("example.xml", encoding="utf-8")
我们可以使用Element对象的find()方法和Element对象的attrib属性来查询元素和属性。
from lxml import etree
# 读取XML文件并解析
tree=etree.parse("example.xml")
root=tree.getroot()
# 查询元素
element_to_find=root.find(".//element_to_find")
# 查询属性
attribute_to_find=root.attrib.get("attribute_to_find")
# 打印查询结果
print("element_to_find:", element_to_find)
print("attribute_to_find:", attribute_to_find)
LXML库提供了ElementTree对象的tostring()方法来生成XML/HTML文档。
from lxml import etree
# 创建XML文档
root=etree.Element("root")
child1=etree.SubElement(root, "child1")
child2=etree.SubElement(root, "child2")
child1.text="text content"
child2.set("attr1", "value1")
child2.set("attr2", "value2")
# 生成XML文档
xml_string=etree.tostring(root, pretty_print=True, encoding="utf-8")
# 保存XML文档
with open("example.xml", "wb") as f:
f.write(xml_string)
本教程介绍了LXML库的基本使用方法,包括解析XML/HTML文档、操作XML/HTML文档和生成XML/HTML文档。LXML库还提供了很多其他功能,例如XPath表达式的高级用法、CSS选择器的支持、XML/HTML的序列化和反序列化等等。
义上讲,爬虫只负责抓取,也就是下载网页。而实际上,爬虫还要负责从下载的网页中提取我们想要的数据,即对非结构化的数据(网页)进行解析提取出结构化的数据(有用数据)。
所以说,网页下载下来只是第一步,还有重要的一步就是数据提取。不同的爬虫想要的数据不一样,提取的数据也就不一样,但提取方法都是类似的。
最简单的提取数据的方法,就是使用正则表达式,此种方法简单,提取的逻辑也不能复杂,不然写出的正则表达式就晦涩难懂,甚至不能提取复杂的数据结构。
最终,老猿经过多年的使用经验,选择了lxml和xpath来解析网页提取结构化数据。顺便说一下 BeautifulSoup,它也是一个很棒的解析HTML的工具,可以使用多个解析器,比如Python标准库的parser,但是速度比较慢,也可以使用lxml作为解析器,但是它的使用方法、API跟lxml不太一样。使用下来,还是lxml的API更舒服。
lxml 对C语言库 libxml2和 libxslt进行绑定,提供了Pythonic的API,它有一些主要特点:
总结为一句话就是,C语言的速度和Python的简易相结合的神器。
lxml有两大部分,分别支持XML和HTML的解析:
lxml.etree可以用来解析RSS feed,它就是一个XML格式的文档。然而爬虫抓取的绝大部分都是html网页,所以,我们这里主要讲述lxml.html解析网页的方法。
我们下载得到的网页就是一串html字符串,如何把它输入给lxml.html模块,从而生成html文档的树结构呢?
该模块提供了几种不同的方法:
下面我们通过具体示例来说明上面几个方法的不同。
document_fromstring 的使用方法
In [1]: import lxml.html as lh In [2]: z=lh.document_fromstring('<span>abc</span><span>xyz</span>') # 可以看到,它自动加了根节点<html> In [3]: z Out[3]: <Element html at 0x7fc410667b88> In [4]: z.tag Out[4]: 'html' # 还加了<body>节点 In [5]: z.getchildren() Out[5]: [<Element body at 0x7fc4101a3ae8>] # 把字符串的两个节点放在了<body>里面 In [6]: z.getchildren()[0].getchildren() Out[6]: [<Element span at 0x7fc410092bd8>, <Element span at 0x7fc410667c28>]
fragment_fromstring 的使用
In [11]: z=lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’) --------------------------------------------------------------------------- ParserError Traceback (most recent call last) <ipython-input-11-a11f9a0f71d1> in <module>() ----> 1 z=lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’) ~/.virtualenvs/py3.6/lib/python3.6/site-packages/lxml/html/__init__.py in fragment_fromstring(html, create_parent, base_url, parser, **kw) 850 raise etree.ParserError( 851 “Multiple elements found (%s)” --> 852 % ‘, ‘.join([_element_name(e) for e in elements])) 853 el=elements[0] 854 if el.tail and el.tail.strip(): ParserError: Multiple elements found (div, div) # 可以看到,输入是两个节点(element)时就会报错 # 如果加上 create_parent 参数,就没问题了 In [12]: z=lh.fragment_fromstring('<div>abc</div><div>xyz</div>', create_parent='p') In [13]: z.tag Out[13]: 'p' In [14]: z.getchildren() Out[14]: [<Element div at 0x7fc40a41a818>, <Element div at 0x7fc40a41aea8>]
fragments_fromstring 的使用
# 输入字符串含有一个节点,则返回包含这一个节点的列表 In [17]: lh.fragments_fromstring('<div>abc</div>') Out[17]: [<Element div at 0x7fc40a124ea8>] # 输入字符串含有多个节点,则返回包含这多个节点的列表 In [18]: lh.fragments_fromstring('<div>abc</div><div>xyz</div>') Out[18]: [<Element div at 0x7fc40a124b88>, <Element div at 0x7fc40a124f98>]
fromstring 的使用
In [27]: z=lh.fromstring('<div>abc</div><div>xyz</div>') In [28]: z Out[28]: <Element div at 0x7fc40a0eb368> In [29]: z.getchildren() Out[29]: [<Element div at 0x7fc410135548>, <Element div at 0x7fc40a0eb2c8>] In [30]: type(z) Out[30]: lxml.html.HtmlElement
这里,fromstring输入的如果是多个节点,它会给加一个父节点并返回。但是像html网页都是从节点开始的,我们使用fromstring() 和 document_fromstring() 都可以得到完整的网页结构。
从上面代码中我们可以看到,那几个函数返回的都是HtmlElement对象,也就是说,我们已经学会了如何从html字符串得到HtmlElement的对象,下一节我们将学习如何操作HtmlElement对象,从中提取我们感兴趣的数据。
*请认真填写需求信息,我们会在24小时内与您取得联系。