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

Connor_Zhang發表於2019-01-10

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 來抓取我們想要的內容吧:

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用來用去還是那麼費勁啊,有沒有什麼別的更簡單的方法啊???當然有的,你可以喝著美味的湯就做完你需要做的事情了。敬請期待下期——BeautifulSoup:美味的湯

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

  好了,這就是今天的內容了,我是Connor,一個從無到有的技術小白。不知道你今天又收穫了多少呢???我們下期再見!

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


系列文章連線:

Python 爬蟲十六式 - 第一式:HTTP協議 >>>
Python 爬蟲十六式 - 第二式:urllib 與 urllib3 >>>
Python 爬蟲十六式 - 第三式:Requests的用法 >>>
Python 爬蟲十六式 - 第五式:BeautifulSoup,美味的湯 >>>
Python 爬蟲十六式 - 第六式:JQuery的假兄弟-pyquery >>>
Python 爬蟲十六式 - 第七式:正則的藝術 >>>
Python 爬蟲十六式 - 第八式:例項解析-全書網 >>>

相關文章