python網絡爬蟲之LXML與HTMLParser


Python lxml包用於解析html和XML文件,個人覺得比beautifulsoup要更靈活些
Lxml中的路徑表達式如下:

在下面的表格中,我們已列出了一些路徑表達式以及表達式的結果:

路徑表示中還可以選取多個路徑,使用’|’運算符,比如下面的樣子:
//book/title | //book/price 選取 book 元素的所有 title 和 price 元素。
下面就來看下lxml的用法:還是用我們之前用過的網站,代碼如下:
from lxml import etree
def parse_url_xml():
    try:
        req=urllib2.Request('http://www.xunsee.com/article/8c39f5a0-ca54-44d7-86cc-148eee4d6615/index.shtml')
        fd=urllib2.urlopen(req)
        html=etree.HTML(fd.read())
        result=html.xpath('//*[@id="content_1"]/span[7]/a')
        print type(result)
        for r in result:
            print r.text

    except BaseException,e:
        print e
首先使用etree,然后利用etree.HTML()初始化。然后用xpath進行查找。其中xpath中的//*[@id="content_1"]/span[7]/a就是網頁元素的xpath地址

從表達式中可以看到首先找到id屬性為content_1的任意標簽。//*表示不管位置,只管后面的屬性滿足即可。然后往下查找第7個span標簽,找到下面a的標簽。然后的result是一個列表。代表找到的所有的元素。通過遍歷列表打印出內容。運行結果如下:
E:\python2.7.11\python.exe E:/py_prj/test.py
<type 'list'>
7節
從上面可以看出,其實xpath還是很好寫,相對beautifulsoup對元素的定位更加准確。其實如果嫌麻煩,不想寫xpath,還有一個更簡單的方法。在瀏覽器中按F12,在網頁源代碼中找到想定位的元素,然后鼠標右鍵,點擊Copy Xpath就可以得到xpath路徑

下面再多舉幾個例子:比如獲取到最后一個span元素,可以用到下面的例子
result=html.xpath('//*[@id="content_1"]/span[last()]/a')
結果如下:
E:\python2.7.11\python.exe E:/py_prj/test.py
657節
我們還可以精簡剛才用到的//*[@id="content_1"]/span[7]/a
精簡為://*[@href="7.shtml"]表示直接查找屬性為7.shtml的元素
如果想返回多個元素,則可以用下面的方式,表示反悔第7節和第8節
result=html.xpath('//*[@href="7.shtml"] | //*[@href="8.shtml"]')
如果想得到所找節點的屬性值:可以用get的方法
result=html.xpath('//*[@href="7.shtml"] | //*[@href="8.shtml"]')
print type(result)
for r in result:
    print r.get('href')
結果就會顯示節點href屬性的值
E:\python2.7.11\python.exe E:/py_prj/test.py
<type 'list'>
7.shtml
8.shtml

 

下面介紹下HTMLParser的用法:

HTMLParser是python自帶的網頁解析工具,使用很簡單。便於HTML文件的解析
下面我們來看相關代碼:
class Newparser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.flag=False
        self.text=[]
    def handle_starttag(self,tag,attrs):
        if tag == 'span':
            self.flag=True
    def handle_data(self, data):
        if self.flag == True:
            print data
            self.text.append(data)
    def handle_endtag(self, tag):
        if tag == 'span':
            self.flag=False




if __name__=="__main__":
    parser=Newparser()
    try:
        req=urllib2.Request('http://www.xunsee.com/article/8c39f5a0-ca54-44d7-86cc-148eee4d6615/index.shtml')
        fd=urllib2.urlopen(req)
        parser.feed(fd.read())
        print parser.text

    except BaseException,e:
        print e
 
首先定義一個類繼承自HTMLParser.在__init__函數中定義一些自己的參數。
parser.feed(fd.read()) 其中feed函數是類自帶的函數。參數就是網頁的HTML代碼。其中feed相當於一個驅動函數。我們來看下feed函數的原型。下面是feed的實現。可以看到實現了2個功能。其中就是將傳入的網頁代碼賦值給rawdata。然后運行goahead開始進行處理
def feed(self, data):
    r"""Feed data to the parser.

    Call this as often as you want, with as little or as much text
    as you want (may include '\n').
    """
   
self.rawdata = self.rawdata + data
    self.goahead(0)
goahead函數代碼過多,這里就不全部貼出來,具體功能就是遍歷rawdata每行數據。然后根據的不同標識調用不同的函數。關鍵函數如下。可以看到當遇到’<’開始的時候。調用parse_startag,當遇到’</’調用parse_endtag

parse_startag里面實現handle_starttag,parse_endtag里面實現handle_endtag。
代碼中的handle_starttag和handle_endtag是個空函數。只是傳入了當前的tag以及attrs.這就給了我們重寫此函數的機會
def handle_starttag(self, tag, attrs):
    pass
def handle_endtag(self, tag):
    pass
def handle_data(self, data):
    pass
其中hanle_data是處理網頁代碼中的具體數據
 
說了這么多,應該對HTMLParser的實現很清楚了。對每行網頁代碼進行處理。依次判斷是否進入handle_starttag,handle_endtag,handle_data。HTMLParser為我們解析出了每行的tag,attrs以及data。我們通過重寫這些函數提取我們需要的信息。那么回到我們的之前的代碼,這個代碼我們要實現的功能是將<span></span>的字段提取出來。
首先__init__定義了2個參數,flag以及text,flag初始值為False
def __init__(self):
    HTMLParser.__init__(self)
    self.flag=False
    self.text=[]
handle_starttag中實現只要tag=span,那么設置flag為True
def handle_starttag(self,tag,attrs):
    if tag == 'span':
        self.flag=True
handle_data中實現只要flag=True則提取出data數據並保存在text列表里面
def handle_data(self, data):
    if self.flag == True:
        print data
        self.text.append(data)
那么這個提取數據的動作在什么時候結束呢:這就要看handle_endtag了。同樣的在遇到tag=span的時候,則設置flag=False。這樣就不會提取data數據了,直到遇到下一個tag=span的時候。
def handle_endtag(self, tag):
    if tag == 'span':
        self.flag=False
這就是HTMLParser的全部功能。是不是比之前的Beautifulsoup以及lxml都感覺要簡潔明了很多呢。對於不規范的網頁,HTMLParser就比Beautifulsoup和lxml好使。下面列出所有的函數功能:
handle_startendtag  處理開始標簽和結束標簽
handle_starttag     處理開始標簽,比如<xx>
handle_endtag       處理結束標簽,比如</xx>
handle_charref      處理特殊字符串,就是以&#開頭的,一般是內碼表示的字符
handle_entityref    處理一些特殊字符,以&開頭的,比如 &nbsp;
handle_data         處理數據,就是<xx>data</xx>中間的那些數據
handle_comment      處理注釋
handle_decl         處理<!開頭的,比如<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
handle_pi           處理形如<?instruction>的東西
其他的實現都大同小異。從下一章開始將介紹scrapy的用法

 

 
        
 
        

 

 
        
 
        

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM