篇文章主要介紹libxml2的安裝和使用,xml文件的主要作用就是配置文件,實際的應(yīng)用在前面的章節(jié)Audio設(shè)備文件解析中有需要對audio_policy_configuration.xml文件解析,google使用的是開源庫libxml2,在源碼目錄/external/libxml2下面,現(xiàn)在就單獨對這個庫進行分析。
在終端中執(zhí)行
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/
通過執(zhí)行
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
已經(jīng)安裝成功。
#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
可以看到執(zhí)行結(jié)果
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打開生成的文件
最后,如果你想學(xué)C/C++可以私信小編“01”獲取素材資料以及開發(fā)工具和聽課權(quán)限哦!
XML是Python中一個強大的XML和HTML處理庫,它是基于libxml2和libxslt庫構(gòu)建的,并提供了一系列方便的API來處理XML和HTML文檔。在本教程中,我們將學(xué)習(xí)如何使用LXML庫來解析、操作和生成XML和HTML文檔。
在使用LXML庫之前,我們需要先安裝它??梢允褂胮ip命令來安裝:
pip install lxml
LXML庫提供了兩種解析器,即ElementTree和SAX解析器。ElementTree解析器將整個XML/HTML文檔解析成一個樹形結(jié)構(gòu),而SAX解析器則是基于事件的解析器,逐個處理文檔中的標(biāo)記。
我們可以使用ElementTree解析器來解析XML/HTML文檔。首先,我們需要使用lxml.etree.parse()函數(shù)來讀取XML/HTML文檔并解析它。
from lxml import etree
# 讀取XML文件并解析
tree=etree.parse("example.xml")
# 獲取根元素
root=tree.getroot()
# 打印根元素的標(biāo)簽和屬性
print("root tag:", root.tag)
print("root attributes:", root.attrib)
# 遍歷樹結(jié)構(gòu)并打印標(biāo)簽和文本內(nèi)容
for element in root.iter():
print("tag:", element.tag, "text:", element.text)
我們可以使用lxml.sax模塊中的saxparser來處理XML/HTML文檔。首先,我們需要定義一個繼承自lxml.sax.ContentHandler類的處理器類,然后使用lxml.sax.parse()函數(shù)來解析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屬性來修改元素的文本內(nèi)容,使用Element對象的set()方法來修改屬性的值。
from lxml import etree
# 讀取XML文件并解析
tree=etree.parse("example.xml")
root=tree.getroot()
# 查找要修改的元素
element_to_modify=root.find(".//element_to_modify")
# 修改元素文本內(nèi)容
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")
# 打印查詢結(jié)果
print("element_to_find:", element_to_find)
print("attribute_to_find:", attribute_to_find)
LXML庫提供了ElementTree對象的tostring()方法來生成XML/HTML文檔。
from lxml import etree
# 創(chuàng)建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的序列化和反序列化等等。
義上講,爬蟲只負責(zé)抓取,也就是下載網(wǎng)頁。而實際上,爬蟲還要負責(zé)從下載的網(wǎng)頁中提取我們想要的數(shù)據(jù),即對非結(jié)構(gòu)化的數(shù)據(jù)(網(wǎng)頁)進行解析提取出結(jié)構(gòu)化的數(shù)據(jù)(有用數(shù)據(jù))。
所以說,網(wǎng)頁下載下來只是第一步,還有重要的一步就是數(shù)據(jù)提取。不同的爬蟲想要的數(shù)據(jù)不一樣,提取的數(shù)據(jù)也就不一樣,但提取方法都是類似的。
最簡單的提取數(shù)據(jù)的方法,就是使用正則表達式,此種方法簡單,提取的邏輯也不能復(fù)雜,不然寫出的正則表達式就晦澀難懂,甚至不能提取復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
最終,老猿經(jīng)過多年的使用經(jīng)驗,選擇了lxml和xpath來解析網(wǎng)頁提取結(jié)構(gòu)化數(shù)據(jù)。順便說一下 BeautifulSoup,它也是一個很棒的解析HTML的工具,可以使用多個解析器,比如Python標(biāo)準(zhǔn)庫的parser,但是速度比較慢,也可以使用lxml作為解析器,但是它的使用方法、API跟lxml不太一樣。使用下來,還是lxml的API更舒服。
lxml 對C語言庫 libxml2和 libxslt進行綁定,提供了Pythonic的API,它有一些主要特點:
總結(jié)為一句話就是,C語言的速度和Python的簡易相結(jié)合的神器。
lxml有兩大部分,分別支持XML和HTML的解析:
lxml.etree可以用來解析RSS feed,它就是一個XML格式的文檔。然而爬蟲抓取的絕大部分都是html網(wǎng)頁,所以,我們這里主要講述lxml.html解析網(wǎng)頁的方法。
我們下載得到的網(wǎng)頁就是一串html字符串,如何把它輸入給lxml.html模塊,從而生成html文檔的樹結(jié)構(gòu)呢?
該模塊提供了幾種不同的方法:
下面我們通過具體示例來說明上面幾個方法的不同。
document_fromstring 的使用方法
In [1]: import lxml.html as lh In [2]: z=lh.document_fromstring('<span>abc</span><span>xyz</span>') # 可以看到,它自動加了根節(jié)點<html> In [3]: z Out[3]: <Element html at 0x7fc410667b88> In [4]: z.tag Out[4]: 'html' # 還加了<body>節(jié)點 In [5]: z.getchildren() Out[5]: [<Element body at 0x7fc4101a3ae8>] # 把字符串的兩個節(jié)點放在了<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) # 可以看到,輸入是兩個節(jié)點(element)時就會報錯 # 如果加上 create_parent 參數(shù),就沒問題了 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 的使用
# 輸入字符串含有一個節(jié)點,則返回包含這一個節(jié)點的列表 In [17]: lh.fragments_fromstring('<div>abc</div>') Out[17]: [<Element div at 0x7fc40a124ea8>] # 輸入字符串含有多個節(jié)點,則返回包含這多個節(jié)點的列表 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輸入的如果是多個節(jié)點,它會給加一個父節(jié)點并返回。但是像html網(wǎng)頁都是從節(jié)點開始的,我們使用fromstring() 和 document_fromstring() 都可以得到完整的網(wǎng)頁結(jié)構(gòu)。
從上面代碼中我們可以看到,那幾個函數(shù)返回的都是HtmlElement對象,也就是說,我們已經(jīng)學(xué)會了如何從html字符串得到HtmlElement的對象,下一節(jié)我們將學(xué)習(xí)如何操作HtmlElement對象,從中提取我們感興趣的數(shù)據(jù)。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。