使用lxml抓取網頁
現在越來越多的網站提供了API。早前,我們之前已經談論過XML-RPC和REST。即使網站服務正以指數方式增長,但仍然有一些網站提供的信息很松散。特別是政府的網站。如果你對這些網站上的內容著迷,你唯一的選擇就是抓取網頁。
什么是抓取網頁?
抓取網頁是一種用編程模仿人類瀏覽網站的技術。為了能在你的程序里能夠抓取網頁,你需要的工具:
- 向網站發出HTTP請求
- 解析HTTP的響應信息并且提取內容
用urllib生成HTTP請求,一個標準的Python類模塊。一旦你通過網站獲得原始的HTML,就需要一種效率的方式去提取內容。
許多程序員談論到從文本文件中提取信息的時候,很快就會想到用正則表達式。
但是,有一個更好的處理工具。lxml登場,使用類似lxml的工具,你可以把一個HTML文件轉換為XML文件。畢竟,一個XHTML文件屬于XML文件的一種。就我們知道的網站作者很少關心HTML文件的規范。大部分的網站有不完整的HTML語言。我們必須要處理它們。
但嘿,lxml可以很好的處理。甚至如果你應用在一個不完整的HTML文件,lxml的HTML解析器可以轉換成有效的XML文件。但是,在網站抓取時,正則表達式仍然有用。你可以結合著lxml使用正則表達式,特別是當你處理文本節點的時候。
在開始之前你應該知道什么?
- XML
- Xpath
- 一點點的Python
W3Schools.com 在這些科目上都有很好的教程,可以去XML tutorial和Xpath tutorial去提高你的知識。
讓我們寫一個python腳本來練習新學習到的技能。
印度政府有一個列舉一些榮譽國會成員的網頁。這次練習的目標就是抓取這個網頁并且提取榮譽國會成員的名字。
練習的網頁地址是:http://164.100.47.132/LssNew/Members/Alphabaticallist.aspx
拋開紛亂,讓我們開始編碼:
import urllib from lxml import etree import StringIO
我們可以用urllib模塊、lxml、etree抓取網頁,并且有了必須得解析對象
result = urllib.urlopen("http://164.100.47.132/LssNew/Members/Alphabaticallist.aspx") html = result.read()
在這一點上,我們有了原始的HTML
parser = etree.HTMLParser() tree = etree.parse(StringIO.StringIO(html), parser)
我們創建HTML解析器對象,然后把解析器傳遞給etree。換句話說,我們告訴etree解析先前的HMLT解析對象。我們也可以使用StringIO.StringIO把文件傳遞給字符串對象\
現在,看一下文件的源代碼
我們想要的信息在id為” ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1”的表格里
讓我們開始構建XPath表達式,為了向里挖掘我們關心部分的數據
//table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']
以上的XPath表達式需要id抓取表格節點
“ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1”位于文件
第一行,<tr>,雖然包含表格頭部但不是必要的,讓我們抓取表格元素中除了第一行所有的行
/table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]在每個行里,國會成員的名字在第二個單元格<td>中。
過濾XPath表達式,只返回每一行的第二個單元格
//table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]/td[position()=2]
進入我們的目標節點單元,國會成員的名字被包含在<a>標簽里
重新定義XPath表達式,抓起文本節點
//table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]/td[position()=2]/a/child::text()
應用XPath表達式在我們的樹上,
xpath = "http://table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]/td[position()=2]/a/child::text()" filtered_html = tree.xpath(xpath)這就是所有我們抓取國會成員名字的代碼
filtered_html 變量是一個python列表。列表中的元素國會成員的名字
自己親自嘗試,并查看結果
print filtered_html
實例輸出如下:
['Aaroon Rasheed,Shri J.M.', 'Abdul Rahman,Shri ', 'Abdullah,Dr. Farooq', 'Acharia,Shri Basudeb', ...]
當你讀到這個文檔,如果這個網頁已經被移動或者它的內容已改變。請參考attached HTML document.
全部的腳本發表在了gist
歡迎標記和搜索這篇文章
附件 Size
members-of-the-parliment.html 455.22 KB