之前在爬蟲系列文的第 5 篇我們說明過用 BeautifulSoup 來解析 HTML,不過要是你對 xpath 很熟悉的話可以試試看使用 lxml,速度會快很多。
特色
BeautifulSoup:
- 是用 python 寫的,基於 DOM 會載入整個文檔,解析整個 DOM 樹,因此時間和內存開銷都會大很多。
lxml:
- 是 c 語言實現的,是局部尋找,所以只要有 xpath 路徑就行了
- 也可以使用
'//*[@id="J_Title"]/h3'
這種帶星號的短 xpath 來尋找(如果玩過 selenium 應該很熟悉 xpath) - 具有自動修正 HTML 代碼的功能,少了對應的 tag 輸出時它會幫你加上
install
$ pip install lxml
實現
簡單範例
BeautifulSoup
from bs4 import BeautifulSoup soup = BeautifulSoup(html,'html.parser',from_encoding='utf-8') links = soup.find_all("h4") for link in links: print link
lxml
from lxml import etree selector = etree.HTML(html) links = selector.xpath('//h4/a/text()') for link in links: print link
階層搜尋
beautifulsoup 的
find
會找出 html 中所有的對象,但是只能一次使用一個對象,當最後找到的結果只有一個可直接輸出href = article.find('div', class_='txt').find('p', class_='tit blue').find('span').find('em').find('a').get('href')
lxml 可以直接使用階層關係來尋找,xpath 方法的返回結果都是一個 list,所以當最後找到的結果只有一個時就要加上
[0]
來輸出href = article.xpath('./div[@class="txt"]//p[@class="tit blue"]/span/em/a/@href')[0]
lxml 應用
示範檔 hello.html
<div> <ul> <li class="item-0"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div>
獲取所有的
<li>
標籤from lxml import etree html = etree.parse('hello.html') print type(html) result = html.xpath('//li') print result print len(result) print type(result) print type(result[0])
運行結果
<type 'lxml.etree._ElementTree'> [<Element li at 0x1014e0e18>, <Element li at 0x1014e0ef0>, <Element li at 0x1014e0f38>, <Element li at 0x1014e0f80>, <Element li at 0x1014e0fc8>] 5 <type 'list'> <type 'lxml.etree._Element'>
獲取
<li>
標籤的所有 classresult = html.xpath('//li/@class') print result
運行結果
['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
獲取
<li>
標籤下 href 為 link1.html 的<a>
標籤result = html.xpath('//li/a[@href="link1.html"]') print result
運行結果
[<Element a at 0x10ffaae18>]
獲取
<li>
標籤下的所有<span>
標籤# 不能用'//li/span',因為/ 是用來獲取子元素的,而<span> 並不是<li> 的子元素,所以,要用雙斜杠 result = html.xpath('//li//span') print result
運行結果
[<Element span at 0x10d698e18>]
獲取最後一個
<li>
的<a> 的 href
result = html.xpath('//li[last()]/a/@href') print result
運行結果
['link5.html']
獲取倒數第二個元素的內容
result = html.xpath('//li[last()-1]/a') print result[0].text
運行結果
fourth item
獲取 class 為
bold
的標籤名result = html.xpath('//*[@class="bold"]') print result[0].tag
運行結果
span