python爬蟲:XPath語法和使用示例

python爬蟲:XPath語法和使用示例

XPath(XML Path Language)是一門在XML文檔中查找資訊的語言,可以用來在XML文檔中對元素和屬性進行遍歷。

選取節點

XPath使用路徑表達式來選取XML文檔中的節點或者節點集。這些路徑表達式和我們在常規的電腦文件系統中看到的表達式非常相似。

常用路徑表達式:

表達式 描述
nodename 選取此節點的所有子節點。
/ 從根節點選取。
// 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。
. 選取當前節點。
.. 選取當前父節點。
@ 選取屬性。
text() 選取文本內容。

實例

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

路徑表達式 結果
bookstore 選取bookstore元素
/bookstore 選取根元素bookstore。注釋:假如路徑起始於(/),則此路徑始終代表到某元素的絕對路徑。
bookstore/book 選取屬於bookstore的子元素的所有book元素。
//book 選取所有book子元素,而不管他們在文檔中的位置。
bookstore//book 選擇屬於bookstore元素的後代的所有book元素,而不管它們位於bookstore之下的什麼位置。
//book/title/@lang 選擇所有的book下面的title中的lang屬性的值。
//book/title/text() 選擇所有的book下面的title的文本。

查找特定的節點

路徑表達式 結果
//title[@lang] 選取所有擁有名為lang的屬性的title元素。
//title[@lang=”eng”] 選取lang屬性值為eng的所有title元素。
/bookstore/book[1] 選取屬於bookstore子元素的第一個book元素。
/bookstore/book[last()] 選取屬於bookstore子元素的最後一個book元素。
/bookstore/book[position()>1] 選擇bookstore下面的book元素,從第二個開始選擇。
//book/title[text()=’Harry Potter’] 選擇所有book下的title元素,僅僅選擇文本為Harry Potter的title元素。
/bookstore/book[price>35.00]/title 選取bookstore元素中的book元素的所有title元素,且其中的price元素的值需大於35.00。

注意點:在xpath中,第一個元素的位置是1,最後一個元素的位置是last(),倒數第二個是last()-1。

選取未知節點

XPath通配符可用來選取未知的XML元素。

通配符 描述
* 匹配任何元素節點。
@* 匹配任何屬性的節點。
node() 匹配任何類型的節點。

實例

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

路徑表達式 結果
//bookstore/* 選取bookstore元素的所有子元素。
//* 選取文檔中的所有元素。
//title[@*] 選取所有帶屬性的title元素。

選取若干路徑

通過在路徑表達式中使用”|”運算符,您可以選取若干個路徑。

實例

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

路徑表達式 結果
//book/title | //book/price 選取book元素的所有title和price元素。
//title | //price 選取文檔中的所有title和price元素。
/bookstore/book/title | //price 選取屬於bookstore元素的book元素的所有title元素,以及文檔中所有的price元素。

使用技巧

在一般的爬蟲實戰中,XPath路徑可以通過Google瀏覽器或火狐瀏覽器中複製得到,如下圖:

但是對於新手可以多多嘗試自己寫XPath路徑,因為有時候複製獲取的XPath路徑過長,而自己寫的更簡潔寫。

例子:

import requests
from lxml import etree

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'
}
url = '//www.qiushibaike.com/text/'
res = requests.get(url, headers=headers)
selector = etree.HTML(res.text)
id = selector.xpath('//div[@class="article block untagged mb15 typs_long"]/div[1]/a[2]/h2/text()')
print(''.join(id).strip())

# 注意:通過/text()可以獲取標籤中的文字資訊。
# 結果為:璃白°

幾種解析方式的性能對比

爬取方法 性能 使用難度
正則表達式 困難
BeautifulSoup 簡單
Lxml 簡單

爬取豆瓣圖書TOP250

爬取的例子直接輸出到螢幕。

需求分析:

(1)要爬取的內容為豆瓣圖書top250的資訊,如下圖所示:

(2)所爬取的網頁鏈接://book.douban.com/top250?start=0

(3)需要爬取的資訊有:書名,書本的鏈接,作者,出版社,出版日期評分和評價。

具體程式碼如下:

# -*- encoding:utf8 -*-
# 爬取豆瓣圖書TOP250。
import requests
from lxml import etree

# 請求頭,用來模擬瀏覽器
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'
}


def get_info(url):
    res = requests.get(url, headers=headers).text
    # lxml庫的etree解析html
    selector = etree.HTML(res)
    # 獲取的是一頁中所有的書本資訊,每本的所以資訊都在類為item的tr下面。
    infos = selector.xpath("//tr[@class='item']")
    for info in infos:
        # 書名
        name = info.xpath('td/div/a/@title')[0]
        # 書的鏈接地址
        book_url = info.xpath('td/div/a/@href')[0]
        # 獲取的是書本的基本資訊,有作者和出版社,和出版日期...
        book_infos = info.xpath('td/p/text()')[0]
        # 作者
        author = book_infos.split('/')[0]
        # 出版社
        publisher = book_infos.split('/')[-3]
        # 出版日期
        date = book_infos.split('/')[-2]
        # 價格
        price = book_infos.split('/')[-1]
        # 書本的評分
        rate = info.xpath('td/div/span[2]/text()')[0]
        # 下面的評論
        comments = info.xpath('td/p/span/text()')
        # 這裡單行的if語句是:如果comments的長度不為0時,則把comments的第1個元素給comment,否則就把"空"賦值給comment
        comment = comments[0] if len(comments) != 0 else "空"
        print(name + " " + book_url + " " + book_infos + " " + author + " " + publisher + " " + date + " " + price + " " + rate + " " + comment)
        print()

    # 獲取下一頁的url
    if selector.xpath("//span[@class='next']/a"):
        next_pag = selector.xpath("//span[@class='next']/a/@href")
        get_info(''.join(next_pag))


if __name__ == "__main__":
    url = '//book.douban.com/top250'
    get_info(url)

部分結果如下圖所示: