[Python爬蟲] 02-09. lxml 解析 HTML 程式碼

 · 4 mins read

之前在爬蟲系列文的第 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> 標籤的所有 class

      result = html.xpath('//li/@class')
      print result
    

    運行結果

      ['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
    


  • 獲取 <li> 標籤下 hreflink1.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
    



ref