Python:HTMLParser模塊進行簡單的html解析

    這是從用Python開發開始到現在第二次使用HTMLParser模塊進行html解析了,第一次用的時候,由於是剛剛接觸Python,對其中的一些用法不是很理解,因爲趕進度,雖然照着參考資料也寫出來了,但是其中的原理還是不怎麼了解。第二次用的時候,有一定的經驗了,對Python的理解也更加深刻了,所以第二次用的時候,對HTMLParser模塊的一些用法不像第一次用時那麼茫然。結合鄙人第二次用該模塊的經驗,來講講HTMLParser模塊的基本使用方法,希望對你有幫助。

    HTMLParser是python用來解析html的模塊。它可以分析出html裏面的標籤、數據等等,是一種處理html的簡便途徑。HTMLParser採用的是一種事件驅動的模式,當HTMLParser找到一個特定的標記時,它會去調用一個用戶定義的函數,以此來通知程序處理。它主要的用戶回調函數的命名都是以handler_開頭的,都是HTMLParser的成員函數。當我們使用時,就從HTMLParser派生出新的類,然後重新定義這幾個以handler_開頭的函數即可。這幾個函數包括:

handle_startendtag(tag, attrs)  處理開始標籤和結束標籤

handle_starttag(tag, attrs)     處理開始標籤,比如<xx>

handle_endtag(tag)       處理結束標籤,比如</xx>

handle_charref(name)      處理特殊字符串,就是以&#開頭的,一般是內碼錶示的字符

handle_entityref(name)    處理一些特殊字符,以&開頭的,比如 &nbsp;

handle_data(data)         處理數據,就是<xx>data</xx>中間的那些數據

handle_comment(data)      處理註釋

handle_decl(decl)         處理<!開頭的,比如<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

handle_pi(data)           處理形如<?instruction>的東西


tag是的html標籤,attrs是 (屬性,值)元組(tuple)的列表(list). 

HTMLParser自動將tag和attrs都轉爲小寫。

下面以從中國銀行官網上解析html文件以獲取實時匯率(這就是我第二此用該模塊時的解析任務)爲例,來定義一個HTMLParser派生類。

在構造這個派生類之前,肯定要分析網頁的源碼的,找出你要獲取的那一個值,在此不做介紹。直接上代碼了,要仔細理解

#coding=utf-8
import HTMLParser
import requests
class MyHTMLParser(HTMLParser.HTMLParser):
    """

    """
    def __init__(self):
        HTMLParser.HTMLParser.__init__(self)
        self.result = []#記錄結果
        self.flag = False#標記


    def handle_starttag(self,tag,attrs):
        if tag == "td" and self.flag == False and len(attrs) == 0:
        #attrs(屬性,值)元組(tuple)的列表(list),由於我要獲取的值的html標籤的沒有屬性
        #所以要求它長度0以排除其它有屬性的標籤,縮小獲取結果的範圍。
        #如果有屬性的話,attrs不會爲空,它是元組列表可以用條件語句來判斷
            self.flag = True

    def handle_end(self,tag):
        if tag == "td" and self.flag == True:
            self.flag = False

    def handle_data(self, data):
        if self.flag == True:
            self.result.append(data)

上面代碼不難理解,都是重載HTMLParser類裏的方法。

再接着就是爬取網頁了,獲取數據,代碼如下:

def _filter_string(string):
    """
    除去字符串中的空格,換行等等
    由於網頁源碼中空格、換行符等會使返回的結果中帶有換行符(\t)等,所以在此除去,
    其實也可以得到結果(返回的結果是個列表)後用列表的內建方法除去這些帶有換行符的元素,
    其實這樣用‘+’拼接字符串的效率很低,這個問題我也是剛剛發現,過段時間在研究一下,
    找到了好的方法,再跟大家分享下。
    """
    s = ''
    for one in string:
        if one != '\n' and one != '\r' and one != '\t' and one != ' ':
            s = s + one
    return s
    
def get_rate():
    """
    獲取匯率
    Returns:

    """
    url = "http://srh.bankofchina.com/search/whpj/search.jsp"
    headers = {'user-agent':'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0'}
    usd_data = {
                 'pjname':1316,#美元在中國銀行官網的代碼
                }
    hkd_data = {
                 'pjname':1315,#港幣在中國銀行官網的代碼
                 }
    usd_result = requests.post(url, data=usd_data, headers=headers)
    hkd_result = requests.post(url, data=hkd_data, headers=headers)
    usd_parser = MyHTMLParser()
    hkd_parser = MyHTMLParser()
    usd_text = usd_result.text
    hkd_text = hkd_result.text
    # text = _filter_string(text)
    usd_text = _filter_string(usd_text)
    hkd_text = _filter_string(hkd_text)

    usd_parser.feed(usd_text)
    usd_parser.close()
    # print usd_result.text
    hkd_parser.feed(hkd_text)
    hkd_parser.close()
    usd_start = usd_parser.result.index(u"美元")  # 美元第一個出現的位置是最新值
    usd_rate = usd_parser.result[usd_start + 3]
    usd_rate = float(usd_rate) / 100  # 最新美元匯率
    usd_uptime = usd_parser.result[usd_start + 7]  # 發佈時間
    hkd_start = hkd_parser.result.index(u"港幣")
    hkd_rate = hkd_parser.result[hkd_start + 3]
    hkd_rate = float(hkd_rate) / 100
    hkd_uptime = hkd_parser.result[hkd_start + 7]  # 發佈時間
    return usd_rate, usd_uptime, hkd_rate, hkd_uptime

HTMLParser類的其它一些方法:

HTMLParser.reset()

重置該實例。失去所有未處理的數據。這個在實例化對象時被隱含地調用。

HTMLParser.feed(data)

提供一些文本給解析器。在由完整元素組成的限度內進行處理,不完整的數據被緩衝直到更多的數據提供或者close()被調用。

HTMLParser.close()

強制將所有的緩衝數據按跟在結束標記的數據一樣進行處理。該方法可以通過派生類定義對輸入結尾的額外處理來進行重定義,但是重定義的版本應該總是調用HTMLParser基類方法close()

HTMLParser.getpos()

返回當前行數和位移值。

HTMLParser.get_starttag_text()

返回當前位置最近的開始標籤的內容

這是給公司內部財務人員記賬用的,所以做成了API供調用。隱約感覺上面代碼最後幾行獲取結果的方法不是最佳方法,如果你有更好的方法,歡迎您與我分享,如果我找到了更好的我會及時分享給大家。

當然,如果是個簡單的任務,用HTMLParser模塊抓取一些想要的數據還是綽綽有餘,如果是複雜的任務,有一定要求(比如性能要求)的任務,那就要用第三方庫,比如Beautiful Soup,不過這個庫我沒用過,有時間研究一下,然後再和大家分享一下我的學習習得。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章