lxml基本用法總結
lxml庫結合libxml2快速強大的特性,使用xpath語法來進行檔案格式解析,與Beautiful相比,效率更高。
0x01 安裝
可以利用pip安裝lxml:
pip install lxml
在windows系統中安裝時,可能會出現如下錯誤:
提示如下:
error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat). Get it from http://aka.ms/vcpython27
需要安裝Microsoft Visual C++ 9.0,對應的是visual studio 2008版本。其實我們可以用一種更簡單的方式來解決這個問題。
(1)首先升級下pip:
python -m pip install -U pip
(2)安裝wheel
pip install wheel
(3)下載lxml對應python版本的wheel檔案:下載地址
其中cp27表示版本就是Python2.7,最後執行安裝:
lxml安裝完畢。
0x02 節點與屬性
Element類是lxml的一個基礎類,大部分XML都是通過Element儲存的。可以通過Element方法建立:
>>> from lxml import etree
>>> root=etree.Element('root' );
>>> print root.tag
root
為root節點新增子節點:
>>> child1=etree.SubElement(root,'child1')
>>> print root
<Element root at 0x2246760>
>>> print etree.tostring(root)
<root><child1/></root>
XML Element的屬性格式為Python的dict。可以通過get/set方法進行設定或獲取操作:
>>> root.set('id','123')
>>> id=root.get('id')
>>> id
'123'
遍歷全部屬性:
>>> for value,name in root.items():
... print value,'\t',name
...
id 123
0x03 文字操作
Element的text屬性可以訪問標籤的文字:
>>> print etree.tostring(root)
<root id="123">root<child1 name="kikay">ttt</child1></root>
>>> root.text
'root'
>>> child1.text
'ttt'
>>>
XML的標籤是成對出現的,但是對於HTML而言,可能存在
這樣的單一標籤,可以通過tail來讀取文字:
>>> etree.tostring(root)
'<root id="123">root<child1 name="kikay">ttt</child1><br/>br_test</root>'
>>> root.tail
>>> br.tail
'br_test'
tail返回的是當前標籤到下一次出現標籤時的文字內容。
(2)xpath方式
>>> etree.tostring(root)
'<root><child1>child1 test</child1><child2>child2 test</child2></root>123'
#方法1:過濾標籤,返回全部文字
>>> root.xpath('string()')
'child1 testchild2 test'
#方法2:以標籤為間隔,返回list
>>> root.xpath('//text()')
['child1 test', 'child2 test', '123']
方法2中的list元素都攜帶了標籤的資訊,可以通過如下方式獲取:
>>> lists=root.xpath('//text()')
>>> lists
['child1 test', 'child2 test', '123']
>>> lists[0].getparent()
<Element child1 at 0x2203c60>
>>> lists[0].getparent().tag
'child1'
>>> lists[1].getparent().tag
'child2'
>>> lists[2].getparent().tag
'root'
還可以通過is_text和is_tail判斷標籤型別:
>>> lists[2].is_text
False
>>> lists[2].is_tail
True
0x04 文字輸入與輸出
lxml提供如下方式輸入文字:
fromstring():解析字串
HTML():解析HTML物件
XML():解析XML物件
parse():解析檔案型別物件
輸出就是前面講的tostring()方法:
>>> root = etree.XML('<root><a><b/></a></root>')
>>> etree.tostring(root)
'<root><a><b/></a></root>'
>>> etree.tostring(root,xml_declaration=True)
"<?xml version='1.0' encoding='ASCII'?>\n<root><a><b/></a></root>"
>>> etree.tostring(root,xml_declaration=True,encoding='utf-8')
"<?xml version='1.0' encoding='utf-8'?>\n<root><a><b/></a></root>"
0x05 標籤搜尋
可以使用find、findall或者xpath來搜尋Element包含的標籤物件。區別如下:
find():返回第一個匹配物件,並且xpath語法只能使用相對路徑(以’.//’開頭);
findall():返回一個標籤物件的列表,並且xpath語法只能使用相對路徑(以’.//’開頭);
xpath():返回一個標籤物件的列表,並且xpath語法的相對路徑和絕對路徑。
>>> root = etree.XML("<root><a x='123'>aText<b/><c/><b/></a></root>")
>>> x=root.find('.//a[@x]')
>>> x
<Element a at 0x2242c10>
>>> x.text
'aText'
>>> x.tag
'a'
>>> x2=root.findall('.//a[@x]')
>>> x2
[<Element a at 0x2242c10>]
>>> type(x2)
<type 'list'>
>>> x3=root.xpath('//a[@x]')
>>> type(x3)
<type 'list'>
>>> x3
[<Element a at 0x2242c10>]
此外,lxml還支援css語法的選擇方式,對於熟悉JQuery選擇器的開發者是一個很好的補充(需要安裝pip install cssselect
):
>>> root = etree.XML("<root><a class='_123'>aText<b id='b1'/><c/><b/></a></root>")
>>> a1=root.cssselect('._123')
>>> a1[0].tag
'a'
>>> root = etree.XML("<root><a class='c123'>aText<b id='b1'/><c/><b/></a></root>")
>>> a1=root.cssselect('a')
>>> a1[0].text
'aText'
>>> a2=root.cssselect('.c123')
>>> a2[0].text
'aText'
>>> b=root.cssselect('#b1')
>>> b[0].tag
'b'
0x06 解析HTML
lxml可以通過etree.HTML()來載入一個HTML頁面:
#coding:utf-8
from lxml import etree
import requests
from chardet import detect
url='http://tool.chinaz.com/'
resp=requests.get(url,timeout=50)
html=resp.content
#識別編碼
cder=detect(html)
html=html.decode(cder.get('encoding'))
tree=etree.HTML(html)
#列印全部a標籤
hrefs=tree.xpath('//a')
for href in hrefs:
print href.get('href'),'\t',href.text
如果HTML頁面中的script和style變遷之間的內容影響解析頁面,可以將其清洗掉:
from lxml.html.clean import Cleaner
clear=Cleaner(style=True,scripts=True,page_structure=False,safe_attrs_only=False)
print clear.clean_html(html)
此外,可以藉助瀏覽器來幫我們生成xpath語法:
下面是提取豆瓣讀書主頁圖書資訊的例子:
#coding:utf-8
from lxml import etree
import requests
from chardet import detect
url='https://book.douban.com/'
resp=requests.get(url,timeout=15)
ecoding=detect(resp.content).get('encoding')
html=resp.content.decode(ecoding)
tree=etree.HTML(html)
for book in tree.xpath('//div[@class="info"]'):
title=book.xpath('.//a[@title]')[0].text.strip()
author=book.xpath('.//div[@class="author"]')[0].text.strip()
print u'《',title,u'》','\t','--',author
結果:
《 這世界偷偷愛著你 》 -- 輝姑娘
《 我與世界只差一個你 》 -- 張皓宸
《 好好學習 》 -- 成甲
《 生育對話錄 》 -- 宋涵
《 被誤診的藝術史 》 -- 董悠悠
《 多拉•布呂代 》 -- [法] 帕特里克•莫迪亞諾
《 我們的後人類未來 》 -- [美] 弗朗西斯•福山