【IT168 技術專稿】對搜索引擎、文件索引、文檔轉換、數據檢索、站點備份或遷移等應用程序來說,經常用到對網頁(即HTML文件)的解析處理。事實上,通過Python語言提供的各種模塊,我們無需借助Web服務器或者Web瀏覽器就能夠解析和處理HTML文檔。本文將詳細介紹如何利用Python抓取和解析網頁。首先,我們介紹一個可以幫助簡化打開位於本地和Web上的HTML文檔的Python模塊,然后,我們論述如何使用Python模塊來迅速解析在HTML文件中的數據,從而處理特定的內容,如鏈接、圖像和Cookie等。最后,我們會給出一個規整HTML文件的格式標簽的例子,通過這個例子您會發現使用python處理HTML文件的內容是非常簡單的一件事情。
一、解析URL
通過Python所帶的urlparse模塊,我們能夠輕松地把URL分解成元件,之后,還能將這些元件重新組裝成一個URL。當我們處理HTML 文檔的時候,這項功能是非常方便的。
parsedTuple = urlparse.urlparse(
" http://www.google.com/search? hl = en & q = urlparse & btnG = Google + Search " ) unparsedURL = urlparse.urlunparse((URLscheme, \
URLlocation, URLpath, '' , '' , '' ))
newURL = urlparse.urljoin(unparsedURL,
" /module-urllib2/request-objects.html " )
函數urlparse(urlstring [, default_scheme [, allow_fragments]])的作用是將URL分解成不同的組成部分,它從urlstring中取得URL,並返回元組 (scheme, netloc, path, parameters, query, fragment)。注意,返回的這個元組非常有用,例如可以用來確定網絡協議(HTTP、FTP等等 )、服務器地址、文件路徑,等等。
函數urlunparse(tuple)的作用是將URL的組件裝配成一個URL,它接收元組(scheme, netloc, path, parameters, query, fragment)后,會重新組成一個具有正確格式的URL,以便供Python的其他HTML解析模塊使用。
函數urljoin(base, url [, allow_fragments]) 的作用是拼接URL,它以第一個參數作為其基地址,然后與第二個參數中的相對地址相結合組成一個絕對URL地址。函數urljoin在通過為URL基地址附加新的文件名的方式來處理同一位置處的若干文件的時候格外有用。需要注意的是,如果基地址並非以字符/結尾的話,那么URL基地址最右邊部分就會被這個相對路徑所替換。比如,URL的基地址為Http://www.testpage.com/pub,URL的相對地址為test.html,那么兩者將合並成http://www.testpage.com/test.html,而非http://www.testpage.com/pub/test.html。如果希望在該路徑中保留末端目錄,應確保URL基地址以字符/結尾。
下面是上面幾個函數的詳細一點的用法舉例:
URLscheme = " http "
URLlocation = " www.python.org "
URLpath = " lib/module-urlparse.html "
modList = ( " urllib " , " urllib2 " , \
" httplib " , " cgilib " )
# 將地址解析成組件 print " 用Google搜索python時地址欄中URL的解析結果 "
parsedTuple = urlparse.urlparse(
" http://www.google.com/search? hl = en & q = python & btnG = Google + Search " ) print parsedTuple
# 將組件反解析成URL print " \反解析python文檔頁面的URL "
unparsedURL = urlparse.urlunparse( \
(URLscheme, URLlocation, URLpath, '' , '' , '' ))
print " \t " + unparsedURL
# 將路徑和新文件組成一個新的URL print " \n利用拼接方式添加更多python文檔頁面的URL "
for mod in modList:
newURL = urlparse.urljoin(unparsedURL, \
" module-%s.html " % (mod))
print " \t " + newURL
# 通過為路徑添加一個子路徑來組成一個新的URL print " \n通過拼接子路徑來生成Python文檔頁面的URL "
newURL = urlparse.urljoin(unparsedURL,
" module-urllib2/request-objects.html " )
print " \t " + newURL
上述代碼的執行結果如下所示:
用Google搜索python時地址欄中URL的解析結果
' hl=en&q=python&btnG=Google+Search ' , '' )
反解析python文檔頁面的URL
http: // www.python.org / lib / module - urlparse.html
利用拼接方式添加更多python文檔頁面的URL
http: // www.python.org / lib / module - urllib.html
http: // www.python.org / lib / module - urllib2.html
http: // www.python.org / lib / module - httplib.html
http: // www.python.org / lib / module - cgilib.html
通過拼接子路徑來生成Python文檔頁面的URL
http: // www.python.org / lib / module - urllib2 / request - objects.html
二、打開HTML文檔
上面介紹了如何解析頁面的URL,現在開始講解如何通過URL打開一個網頁。實際上,Python所帶的urllib和urllib2這兩個模塊為我們提供了從URL打開並獲取數據的功能,當然,這包括HTML文檔。
u = urllib.urlopen(webURL)
u = urllib.urlopen(localURL)
buffer = u.read()
print u.info()
print " 從%s讀取了%d 字節數據.\n " % (u.geturl(),len(buffer) )
若要通過urllib模塊中的urlopen(url [,data])函數打開一個HTML文檔,必須提供該文檔的URL地址,包括文件名。函數urlopen不僅可以打開位於遠程web服務器上的文件,而且可以打開一個本地文件,並返回一個類似文件的對象,我們可以通過該對象從HTML文檔中讀出數據。
一旦打開了HTML文檔,我們就可以像使用常規文件一樣使用read([nbytes])、readline()和readlines()函數來對文件進行讀操作。若要讀取整個HTML文檔的內容的話,您可以使用read()函數,該函數將文件內容作為字符串返回。
打開一個地址之后,您可以使用geturl()函數取得被獲取網頁的真正的URL。這是很有用的,因為urlopen(或使用的opener對象)也許會伴隨一個重定向。獲取的網頁URL也許和要求的網頁URL不一樣。
另一個常用的函數是位於從urlopen返回的類文件對象中的info()函數,這個函數可以返回URL位置有關的元數據,比如內容長度、內容類型,等等。下面通過一個較為詳細的例子來對這些函數進行說明。
webURL = " http://www.python.org "
localURL = " index.html "
# 通過URL打開遠程頁面 u = urllib.urlopen(webURL)
buffer = u.read()
print u.info()
print " 從%s讀取了%d 字節數據.\n " % (u.geturl(),len(buffer) )
# 通過URL打開本地頁面 u = urllib.urlopen(localURL)
buffer = u.read()
print u.info()
print " 從%s讀取了%d 字節數據.\n " % (u.geturl(),len(buffer) )
上面代碼的運行結果如下所示:
Server: Apache / 2.2 . 9 (Debian) DAV / 2 SVN / 1.5 . 1 mod_ssl / 2.2 . 9 OpenSSL / 0.9 .8g mod_wsgi / 2.3 Python / 2.5 . 2
Last - Modified: Thu, 25 Jun 2009 0 9 : 44 : 54 GMT
ETag: " 105800d-46e7-46d29136f7180 "
Accept - Ranges: bytes
Content - Length: 18151
Connection: close
Content - Type: text / html
從http: // www.python.org讀取了18151 字節數據.
Content - Type: text / html
Content - Length: 865
Last - modified: Fri, 26 Jun 2009 10 : 16 : 10 GMT
從index.html讀取了865 字節數據.
三、小結
對搜索引擎、文件索引、文檔轉換、數據檢索、站點備份或遷移等應用程序來說,經常用到對網頁(即HTML文件)的解析處理。事實上,通過Python語言提供的各種模塊,我們無需借助Web服務器或者Web瀏覽器就能夠解析和處理HTML文檔。本文中,我們介紹了一個可以幫助簡化打開位於本地和Web上的HTML文檔的Python模塊。在下篇中,我們將論述如何使用Python模塊來迅速解析在HTML文件中的數據,從而處理特定的內容,如鏈接、圖像和Cookie等。
【IT168 技術專稿】對搜索引擎、文件索引、文檔轉換、數據檢索、站點備份或遷移等應用程序來說,經常用到對網頁(即HTML文件)的解析處理。事實上,通過Python語言提供的各種模塊,我們無需借助Web服務器或者Web瀏覽器就能夠解析和處理HTML文檔。本文上篇中,我們介紹了一個可以幫助簡化打開位於本地和Web上的HTML文檔的Python模塊。在本文中,我們將論述如何使用Python模塊來迅速解析在HTML文件中的數據,從而處理特定的內容,如鏈接、圖像和Cookie等。同時還會介紹如何規范HTML文件的格式標簽。
一、從HTML文檔中提取鏈接
Python語言還有一個非常有用的模塊HTMLParser,該模塊使我們能夠根據HTML文檔中的標簽來簡潔、高效地解析HTML文檔。所以,在處理HTML文檔的時候,HTMLParser是最常用的模塊之一。
import urllib
class parseLinks(HTMLParser.HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == ' a ' :
for name,value in attrs:
if name == ' href ' :
print value
print self.get_starttag_text()
lParser = parseLinks()
lParser.feed(urllib.urlopen( " http://www.python.org/index.html " ).read())
處理HTML文檔的時候,我們常常需要從其中提取出所有的鏈接。使用HTMLParser模塊后,這項任務將變得易如反掌。首先,我們需要定義一個新的HTMLParser類,以覆蓋handle_starttag()方法,我們將使用這個方法來顯示所有標簽的HRef屬性值。
定義好新的HTMLParser類之后,需要創建一個實例來返回HTMLParser對象。然后,就可以使用urllib.urlopen(url)打開HTML文檔並讀取該HTML文件的內容了。
為了解析HTML文件的內容並顯示包含其中的鏈接,可以使用read()函數將數據傳遞給HTMLParser對象。HTMLParser對象的feed函數將接收數據,並通過定義的HTMLParser對象對數據進行相應的解析。需要注意,如果傳給HTMLParser的feed()函數的數據不完整的話,那么不完整的標簽會保存下來,並在下一次調用feed()函數時進行解析。當HTML文件很大,需要分段發送給解析器的時候,這個功能就會有用武之地了。下面是一個具體的例子
import urllib
import sys
# 定義HTML解析器 class parseLinks(HTMLParser.HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == ' a ' :
for name,value in attrs:
if name == ' href ' :
print value
print self.get_starttag_text()
# 創建HTML解析器的實例 lParser = parseLinks()
# 打開HTML文件 lParser.feed(urllib.urlopen( \
" http://www.python.org/index.html " ).read())
lParser.close()
上述代碼的運行結果太長,在此省略,您可以自己運行代碼試試。
二、從HTML文檔中提取圖像
處理HTML文檔的時候,我們常常需要從其中提取出所有的圖像。使用HTMLParser模塊后,這項任務將變得易如反掌。首先,我們需要定義一個新的HTMLParser類,以覆蓋handle_starttag()方法,該方法的作用是查找img標簽,並保存src屬性值所指的文件。
import urllib
def getImage(addr):
u = urllib.urlopen(addr)
data = u.read()
class parseImages(HTMLParser.HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == ' img ' :
for name,value in attrs:
if name == ' src ' :
getImage(urlString + " / " + value)
u = urllib.urlopen(urlString)
lParser.feed(u.read())
定義好新的HTMLParser類之后,需要創建一個實例來返回HTMLParser對象。然后,就可以使用urllib.urlopen(url)打開HTML文檔並讀取該HTML文件的內容了。
為了解析HTML文件的內容並顯示包含其中的圖像,可以使用feed(data)函數將數據發送至HTMLParser對象。HTMLParser對象的feed函數將接收數據,並通過定義的HTMLParser對象對數據進行相應的解析。下面是一個具體的示例:
import urllib
import sys
urlString = " http://www.python.org "
# 把圖像文件保存至硬盤 def getImage(addr):
u = urllib.urlopen(addr)
data = u.read()
splitPath = addr.split( ' / ' )
fName = splitPath.pop()
print " Saving %s " % fName
f = open(fName, ' wb ' )
f.write(data)
f.close()
# 定義HTML解析器 class parseImages(HTMLParser.HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == ' img ' :
for name,value in attrs:
if name == ' src ' :
getImage(urlString + " / " + value)
# 創建HTML解析器的實例 lParser = parseImages()
# 打開HTML文件 u = urllib.urlopen(urlString)
print " Opening URL\n==================== "
print u.info()
# 把HTML文件傳給解析器 lParser.feed(u.read())
lParser.close()
上述代碼的運行結果如下所示:
====================
Date: Fri, 26 Jun 2009 10 : 54 : 49 GMT
Server: Apache / 2.2 . 9 (Debian) DAV / 2 SVN / 1.5 . 1 mod_ssl / 2.2 . 9 OpenSSL / 0.9 .8g mod_wsgi / 2.3 Python / 2.5 . 2
Last - Modified: Thu, 25 Jun 2009 0 9 : 44 : 54 GMT
ETag: " 105800d-46e7-46d29136f7180 "
Accept - Ranges: bytes
Content - Length: 18151
Connection: close
Content - Type: text / html
Saving python - logo.gif
Saving trans.gif
Saving trans.gif
Saving afnic.fr.png
三、從HTML文檔中提取文本
處理HTML文檔的時候,我們常常需要從其中提取出所有的文本。使用HTMLParser模塊后,這項任務將變得非常簡單了。首先,我們需要定義一個新的HTMLParser類,以覆蓋handle_data()方法,該方法是用來解析並文本數據的。
import urllib
class parseText(HTMLParser.HTMLParser):
def handle_data(self, data):
if data != ' \n ' :
urlText.append(data)
lParser = parseText()
lParser.feed(urllib.urlopen( \
http: // docs.python.org / lib / module - HTMLParser.html).read())
定義好新的HTMLParser類之后,需要創建一個實例來返回HTMLParser對象。然后,就可以使用urllib.urlopen(url)打開HTML文檔並讀取該HTML文件的內容了。
為了解析HTML文件的內容並顯示包含其中的文本,我們可以使用feed(data)函數將數據傳遞給HTMLParser對象。HTMLParser對象的feed函數將接收數據,並通過定義的HTMLParser對象對數據進行相應的解析。要注意的是,如果傳給HTMLParser的feed()函數的數據不完整的話,那么不完整的標簽會保存下來,並在下一次調用feed()函數時進行解析。當HTML文件很大,需要分段發送給解析器的時候,這個功能就會有用武之地了。下面是一個具體的代碼示例:
import urllib
urlText = []
# 定義HTML解析器 class parseText(HTMLParser.HTMLParser):
def handle_data(self, data):
if data != ' \n ' :
urlText.append(data)
# 創建HTML解析器的實例 lParser = parseText()
# 把HTML文件傳給解析器 lParser.feed(urllib.urlopen( \
“http: // docs.python.org / lib / module - HTMLParser.html” \
).read())
lParser.close()
for item in urlText:
print item
上面代碼的運行輸出過長,在此略過。
四、從HTML文檔中提取Cookies
很多時候,我們都需要處理Cookie,幸運的是Python語言的cookielib模塊為我們提供了許多自動處理在HTML中的HTTP Cookie的類。當處理要求為客戶端設置Cookie的HTML文檔的時候,這些類對我們非常有用。
import cookielib
from urllib2 import urlopen, Request
cJar = cookielib.LWPCookieJar()
opener = urllib2.build_opener( \
urllib2.HTTPCookieProcessor(cJar))
urllib2.install_opener(opener)
r = Request(testURL)
h = urlopen(r)
for ind, cookie in enumerate(cJar):
print " %d - %s " % (ind, cookie)
cJar.save(cookieFile)
為了從HTML文檔提取cookies,首先得使用cookielib模塊的LWPCookieJar()函數創建一個cookie jar的實例。LWPCookieJar()函數將返回一個對象,該對象可以從硬盤加載Cookie,同時還能向硬盤存放Cookie。
接下來,使用urllib2模塊的build_opener([handler, . . .])函數創建一個opener對象,當HTML文件打開時該對象將處理cookies。函數build_opener可以接收零個或多個處理程序(這些程序將按照它們被指定的順序連接在一起)作為參數並返回一個。
注意,如果想讓urlopen()使用opener對象來打開HTML文件的話,可以調用install_opener(opener)函數,並將opener對象傳給它。否則,請使用opener對象的open(url)函數來打開HTML文件。
一旦已經創建並安裝了opener對象,就可以使用urllib2模塊中的Request(url)函數來創建一個Request對象,然后就能使用urlopen(Request)函數來打開HTML文件了。
打開HTML頁面后,該頁面的所有Cookie將被存放到LWPCookieJar對象中,之后,您可以使用LWPCookieJar對象的save(filename)函數了。
import urllib2
import cookielib
from urllib2 import urlopen, Request
cookieFile = " cookies.dat "
testURL = ' http://maps.google.com/ '
# 為cookie jar 創建實例 cJar = cookielib.LWPCookieJar()
# 創建HTTPCookieProcessor的opener對象 opener = urllib2.build_opener( \
urllib2.HTTPCookieProcessor(cJar))
# 安裝HTTPCookieProcessor的opener urllib2.install_opener(opener)
# 創建一個Request對象 r = Request(testURL)
# 打開HTML文件 h = urlopen(r)
print " 頁面的頭部\n====================== "
print h.info()
print " 頁面的Cookies\n====================== "
for ind, cookie in enumerate(cJar):
print " %d - %s " % (ind, cookie)
# 保存cookies cJar.save(cookieFile)
上述代碼的運行結果如下所示:
======================
Cache - Control: private
Content - Type: text / html; charset = ISO - 8859 - 1
Set - Cookie: PREF = ID = 5d9692b55f029733:NW = 1 :TM = 1246015608 :LM = 1246015608 :S = frfx -- b3xt73TaEA; expires = Sun, 26 - Jun - 2011 11 : 26 : 48 GMT; path =/ ; domain = .google.com
Date: Fri, 26 Jun 2009 11 : 26 : 48 GMT
Server: mfe
Expires: Fri, 26 Jun 2009 11 : 26 : 48 GMT
Transfer - Encoding: chunked
Connection: close
頁面的Cookies
======================
0 -
五、為HTML文檔中的屬性值添加引號
前面我們討論了如果根據HTML解析器中的某種處理程序來解析HTML文件,可是有時候我們卻需要使用所有的處理程序來處理HTML文檔。值得慶幸的是,使用HTMLParser模塊解析HTML文件的所有要素並不比處理鏈接或者圖像難多少。
import urllib
class parseAttrs(HTMLParser.HTMLParser):
def handle_starttag(self, tag, attrs):
. . .
attrParser = parseAttrs()
attrParser.init_parser()
attrParser.feed(urllib.urlopen( " test2.html " ).read())
這里,我們將討論如何使用HTMLParser模塊來解析HTML文件,從而為“裸奔”的屬性值加上引號。首先,我們要定義一個新的HTMLParser類,以覆蓋下面所有的處理程序來為屬性值添加引號。
handle_charref(name)
handle_endtag(tag)
handle_entityref(ref)
handle_data(text)
handle_comment(text)
handle_pi(text)
handle_decl(text)
handle_startendtag(tag, attrs)
我們還需要在parser類中定義一個函數來初始化用於存儲解析好的數據的變量,同時還要定義另外一個函數來返回解析好的數據。
定義好新的HTMLParser類之后,需要創建一個實例來返回HTMLParser對象。使用我們創建的init函數初始化該解析器,這樣,我們就可以使用urllib.urlopen(url)打開HTML文檔並讀取該HTML文件的內容了。
為了解析HTML文件的內容並給屬性值添加引號,可以使用feed(data)函數將數據傳遞給HTMLParser對象。HTMLParser對象的feed函數將接收數據,並通過定義的HTMLParser對象對數據進行相應的解析。下面是一個具體的示例代碼:
import urllib
import sys
# 定義HTML解析器 class parseAttrs(HTMLParser.HTMLParser):
def init_parser (self):
self.pieces = []
def handle_starttag(self, tag, attrs):
fixedAttrs = ""
# for name,value in attrs: for name, value in attrs:
fixedAttrs += " %s=\"%s\" " % (name, value)
self.pieces.append( " <%s %s> " % (tag, fixedAttrs))
def handle_charref(self, name):
self.pieces.append( " &#%s; " % (name))
def handle_endtag(self, tag):
self.pieces.append( "" % (tag))
def handle_entityref(self, ref):
self.pieces.append( " &%s " % (ref))
def handle_data(self, text):
self.pieces.append(text)
def handle_comment(self, text):
self.pieces.append( "" % (text))
def handle_pi(self, text):
self.pieces.append( "" % (text))
def handle_decl(self, text):
self.pieces.append( "" % (text))
def parsed (self):
return "" .join(self.pieces)
# 創建HTML解析器的實例 attrParser = parseAttrs()
# 初始化解析器數據 attrParser.init_parser()
# 把HTML文件傳給解析器 attrParser.feed(urllib.urlopen( " test2.html " ).read())
# 顯示原來的文件內容 print " 原來的文件\n======================== "
print open( " test2.html " ).read()
# 顯示解析后的文件 print " 解析后的文件\n======================== "
print attrParser.parsed()
attrParser.close()
我們還需要建立一個測試文件,名為test2.html,該文件內容可以從上述代碼的運行結果看到,具體如下所示:
解析后的文件 ======================== < html > < head > < meta content = " text/html; charset=utf-8 " http - equiv = " content-type " ></ meta > < title > Web頁面 </ title > </ head > < body > < h1 > Web頁面清單 </ h1 > < a href = " http://www.python.org " > Python網站 </ a > < a href = " test.html " > 本地頁面 </ a > < img src = " test.jpg " > </ body > </ html >
六、小結
對搜索引擎、文件索引、文檔轉換、數據檢索、站點備份或遷移等應用程序來說,經常用到對網頁(即HTML文件)的解析處理。事實上,通過Python語言提供的各種模塊,我們無需借助Web服務器或者Web瀏覽器就能夠解析和處理HTML文檔。本文將詳細介紹了如何使用Python模塊來迅速解析在HTML文件中的數據,從而處理特定的內容,如鏈接、圖像和Cookie等。同時,我們還給出了一個規范HTML文件的格式標簽的例子,希望本文對您會有所幫助。