Python爬蟲十六式 - 第四式: 使用Xpath提取網頁內容

Xpath:簡單易用的網頁內容提取工具

學習一時爽,一直學習一直爽 !

  Hello,大家好,我是Connor,一個從無到有的技術小白。上一次我們說到了 requests 的使用方法。到上節課爲止,我們已經學完了所有的 Python 常用的訪問庫。那麼當我們獲取到了訪問的內容之後,我們就應該從網頁上提取我們想要的內容了。所以,今天我們來講網頁內容的常用提取工具之一:Xpath 。相比於 BeautifulSoup 而言,Xpath 更加簡單易上手。

1.Xpath簡介

  Xpath 是一門在 XML 文檔中查找信息的語言。XPath 用於在 XML 文檔中通過元素和屬性進行導航。他是一種路徑語言(XML Path Language),用來確定XML文檔中某部分的位置。

  XPath基於XML的樹狀結構,提供在數據結構樹中找尋節點的能力。起初XPath的提出的初衷是將其作爲一個通用的、介於XPointerXSL間的語法模型。但是XPath很快的被開發者採用來當作小型*查詢語言被廣泛使用。比如說,當你打開一個網頁後按 F12 進行元素檢查。當你想要複製某個元素的路徑的時候,你可以通過右鍵進行 Copy 操作。你會發現裏面有 Copy Xpath 的選項。由此可見 Xpath 使用的廣泛程度。

說了這麼多Xpath使用的怎麼怎麼廣泛,怎麼怎麼好用,我們還是來點實在的,看看在 Python 爬蟲中到底如何使用 Xpath 來抓取我們想要的內容吧:


2. Xpath的安裝

  在前面的教程中,我幾乎從未提過某個庫的安裝,但是爲什麼在這裏我要提出如何安裝呢?原因很簡單,Xpath只是 lxml 庫中的一個模塊,在 Python 很多庫中都提供有 Xpath 的功能,但是最基本的還是 lxml 的這個庫。效率最高。所以,你知道了,想要使用 Xpath 那麼你就需要安裝 lxml 庫:

pip install lxml

3.Xpath的語法

  其實說白了,Xpath 就是從 html 中選取節點。節點是通過沿着路徑或者通過 step 來選取的。下面,我們將通過如下HTML文檔來進行演示:

html_doc ="""
<html>
    <head></head>
    <body>
        <li>
            <a href="/book_16860.html" title="總裁的新鮮小妻">
                <img src="/16860s.jpg">
            </a>
            <img src="/kukuku/images/only.png" class="topss png_bg">
                <img src="abc.png" class="topss png_bg">
            <a href="/book_16860.html">總裁的新鮮小妻子</a>
        </li>
        <li>
            <a href="/book_16861.html" title="鬥神天下">
                <img src="/16861s.jpg">
            </a>
            <img src="/kukuku/images/only.png" class="topss png_bg">
            <img src="def.png" class="topss png_bg">
            <a href="/book_16861.html">鬥神天下</a>
        </li>

    </body>
</html>"""

  首先,大家也都知道我們實際上從網頁上獲取的都是字符串格式。那麼如果我們想要通過 Xpath 來提取我們想要的內容,我們首先要生成 HTML 的 DOM 樹:

from lxml import etree

page = etree.HTML(html_doc)

3.1 路徑查找

  如果我們想要使用路徑查找,那我們首先需要知道 Xpath 的語法。Xpath 的主要語法有如下:

表達式 描述
nodename 選取名爲nodename的子節點
/ 從根節點選取
// 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。
. 選取當前節點
選取當前節點的父節點
@ 選取屬性
  • 查找當前的子節點:
In [1]: page.xpath('head')
Out[1]: [<Element head at 0x7f185bfe5b08>]

  當前的節點位置是在 html,所以直接查詢 head 節點可以查詢出來,li 是html的孫節點,如果查詢 li 將返回空值:

In [2]: page.xpath('li')
Out[2]: []
  • 從根節點進行查找:
In [3]: page.xpath('/html')
Out[3]: [<Element html at 0x11208be88>]

  從根節點進行查找,根節點下只有一個節點 html 節點,所以從根節點查找只能查找到 html,如果查找其它內容將返回空列表:

In [4]: page.xpath('/li')
Out[4]: []
  • 從整個文檔所有節點查找:
In [5]: page.xpath('//li')
Out[5]:
[<Element li at 0x1128c02c8>,
 <Element li at 0x111c74108>,
 <Element li at 0x111fd2288>,
 <Element li at 0x1128da348>]

  從整個文檔進行查找可以查找整個文檔中符合條件的節點,包括孫節點及以下。

  • 選取當前節點的父節點
In [6]: page.xpath('//li')[0].xpath('..')
Out[6]: [<Element body at 0x1128c0ac8>]
  • 選取屬性:
In [7]: page.xpath('//a')[1].xpath('@href')
Out[7]: ['/book_16860.html']

  選取屬性支持任意的標籤屬性,但是要注意如果選取出的節點有多個,需要指定是哪一個節點的屬性。


3.2 節點查找

通過路徑查找到節點以後,就需要從超找到的節點中選取我們需要的內容了。查找節點也有一些語法,如下:

表達式 結果
nodename[index] 選取符合要求的第 index 個元素
nodename[last()] 選取最後一個元素
nodename[position()< num] 選取前 num 個元素
nodename[@attribute] 選取帶有屬性名爲 attribute 的元素
nodename[@attribute=‘value’] 選取帶有屬性名爲 attribute 且 值爲 value 的元素
  • 選取第一個 img 節點的 src 屬性:
In [1]: page.xpath('//li[1]/a[1]/img[1]/@src')
Out[1]: ['/16860s.jpg']

  **注意:當你在選取一個節點的屬性的時候,有一點需要注意。通過[index]選取出的節點是每一個符合條件的第[index]個符合條件的元素。**但是這麼說比較抽象,我們舉個例子。例如:

In [2]: page.xpath('//li[1]') 選取所有符合 li 節點的第一個節點
Out[2]: [<Element li at 0x7fb517327ac8>]

  通過上面的例子我們貌似看不出什麼,那我們再看下面的這個例子:

In [3]: page.xpath('//li//img[1]')
Out[3]: [<Element img at 0x7f0c26328b08>, 
         <Element img at 0x7f0c26328a88>, 
         <Element img at 0x7f0c26328bc8>, 
         <Element img at 0x7f0c26328c08>]

  你可以看到,我們選取出了4個 img 節點。原因很簡單,看下面的代碼和解釋就能明白了:

<html>
	<head></head>
	<body>
        <li>
            <a href="/book_16860.html" title="總裁的新鮮小妻">
                (一)<img src="/16860s.jpg">
            </a>
            (二)<img src="/kukuku/images/only.png" class="topss png_bg">
            (三)<img src="abc.png" class="topss png_bg">
            <a href="/book_16860.html">總裁的新鮮小妻子</a>
        </li>
        <li>
        	<a href="/book_16861.html" title="鬥神天下">
                (四)<img src="/16861s.jpg">
            </a>
            (五)<img src="/kukuku/images/only.png" class="topss png_bg">
            (六)<img src="def.png" class="topss png_bg">
            <a href="/book_16861.html">鬥神天下</a>
        </li>

    </body>
</html>
  1. (一)是第一個 <li> 節點的 <a> 節點裏的第一個 <img> 節點。其路徑爲 <li>/<a>/<img>
  2. (二)是第一個 <li> 節點的 <img> 節點裏的第一個 <img> 節點。其路徑爲 <li>/<img>
  3. (三)之所以沒有被選中,是因爲它是 <li> 標籤下的第二個 <img> 標籤
  4. (四)(五)(六)同理
  • 選取第二個元素開始的所有節點:
In [4]: page.xpath('//img[position()>1]')
Out[4]: [<Element img at 0x7f78ba63dac8>, <Element img at 0x7f78ba63da48>]
  • 選取帶有指定屬性與指定值的節點:
In [5]: page.xpath('//a[@title="鬥神天下"]')
Out[5]: [<Element a at 0x7fdd0844fa48>]

3.3 未知節點

  當我們匹配時會出現路徑不確定的情況,這個時候我們就要涉及到匹配未知節點。匹配未知節點也有對應的語法,如下:

通配符 描述
* 匹配任何元素節點
@* 匹配任何屬性節點

匹配任何屬性節點:

In [1]: page.xpath('//li/a/*')
Out[1]: [<Element img at 0x7f83af768b08>,
         <Element img at 0x7f83af768a88>,
         <Element img at 0x7f83af768bc8>,
         <Element img at 0x7f83af768c08>]

匹配任何元素節點:

In [2]: page.xpath('//li/a[@*]')
Out[2]: [<Element a at 0x7ff2dcf69b08>,
         <Element a at 0x7ff2dcf69a88>,
         <Element a at 0x7ff2dcf69bc8>,
         <Element a at 0x7ff2dcf69c08>]

3.4 獲取節點中的文本

  通過 屬性方法可以獲取屬性內的內容,但是位於節點之間的內容無法獲取到,這個時候就可以通過 text()string() 方法來獲得其中的文本:

通過 text() 獲取某個節點中的文本:

In [1]: page.xpath('//li/a[3]/text()')
Out[1]: ['總裁的新鮮小妻子', '鬥神天下']

  可以看到,通過 text() 屬性可以很輕鬆的獲取標籤之間的文本。

通過 string() 獲取某個節點中的文本:

In [1]: page.xpath('string(//li[1]/a[3])')
Out[1]: '總裁的新鮮小妻子'

3.5 選取多個路徑

  有的時候我們需要同時查找多個條件,這個時候你可以通過在路徑表達式中使用管道符("|"),選取若干個路徑:

In [1]: page.xpath('//li[1]/img[2]/@src | //li[1]/a[3]/text()')
Out[1]: ['/kukuku/images/second.png', '總裁的新鮮小妻子']

  同時選取多個路徑並不會生成一個新的列表,只有一個列表,所以你要考慮好如何提取你的返回結果。一般情況下還是不建議使用多條件來進行查找,因爲多種提取結果混在一個列表不利於提取,即便可以提取,但也會增加計算量,降低程序性能。所以,儘量不要使用這種方法。


  以上就是所有的 Xpath 有關的內容啦,可能並不比別人講的細,但是已經足夠你做爬蟲使用了。其實我也希望能夠講的更加細緻一點,奈何我是一個正則黨,我個人不太喜歡使用Xpath,如果你真的想要深入瞭解Xpth的話,推薦你到 W3C Xpath教程 >>> 去看看它們是怎麼用的。

  好了,這就是今天的內容了,我是Connor,一個從無到有的技術小白。我們下期再見!

學習一時爽,一直學習一直爽 !

  下期預告:Xpath用來用去還是那麼費勁啊,有沒有什麼別的更簡單的方法啊???當然有的,你可以喝着美味的湯就做完你需要做的事情了。敬請期待下期——BeautifulSoup:美味的湯

系列文章連接:

Python 爬蟲十六式 - 第一式:HTTP協議 >>>
Python 爬蟲十六式 - 第二式:urllib 與 urllib3 >>>
Python 爬蟲十六式 - 第三式:Requests的用法 >>>

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