1、簡介html
xpath做爲對網頁、對xml文件進行定位的工具,速度快,語法簡潔明瞭,在網絡爬蟲解析內容的過程當中起到很大的做用,除了xpath的基礎用法以外(可參考我以前寫的(數據科學學習手札50)基於Python的網絡數據採集-selenium篇),xpath中還存在着很是之多的進階用法,本文將對筆者平常使用中積累的xpath進階用法進行總結並舉例說明:正則表達式
2、xpath進階用法express
本文以http://quotes.toscrape.com/示例頁面,首先抓取網頁源碼並利用etree解析:網絡
import requests
from lxml import etree html = requests.get('http://quotes.toscrape.com/') tree = etree.HTML(html.text)
2.1 獲取某一節點的上一級節點函數
在xpath中/..表示向上一級,這裏咱們用xpath按照下圖中的路徑提取a標籤裏的內容:工具
'''提取頁面中符合下列位置規則的全部keyword''' tree.xpath("//meta[@class='keywords']/../a[@class='tag']/text()")
或者利用parent來向上一級跳轉,效果是同樣的:學習
'''提取頁面中符合下列位置規則的全部keyword''' tree.xpath("//meta[@class='keywords']/parent::*/a[@class='tag']/text()")
2.2 定位指定屬性以某個特定字符開頭的標籤spa
在xpath中有函數starts-with(屬性名稱,開始字符),可用於定位指定屬性以某個特定字符開頭的標籤,以下例,實現與2.1中相同功能:3d
'''提取href屬性以/tag開頭的a標籤內容''' tree.xpath("//a[starts-with(@href,'/tag')]/text()")
2.3 定位指定屬性值包含特定字符片斷的標籤code
在xpath中函數contains(屬性名稱,包含字符)可用於定位指定屬性值包含特定字符片斷的標籤內容,好比咱們想要找到全部text()內容中帶有know的名人名言,就能夠像下面這樣作:
'''提取text()內容包含know的span標籤對應的text()內容''' tree.xpath("//span[contains(text(),'know')]/text()")
2.4 匹配具備某屬性的全部標籤
好比說咱們想獲取頁面中全部的href超連接,就能夠用下面的方式:
'''獲取整個頁面內全部href屬性''' tree.xpath("//@href")
2.5 同時定位多個內容
好比說咱們想在一行代碼裏同時取得兩種不一樣的規則下匹配的內容,能夠在xpath語句中將不一樣的多個xpath語句用|鏈接起來,最終返回的結果在同一個列表裏,因此使用這種語法時須要考慮取得的內容是否適合放在一塊兒:
'''同時取得多個定位規則下的內容''' tree.xpath("//span[contains(text(),'know')]/text() | //span[contains(text(),'world')]/text()")
2.6 選取指定節點下全部子元素
有時候咱們想要快捷的獲取某一節點下一級全部標籤的某一屬性內容,可使用child來表示下一級節點:
'''選取class爲quote的div節點下全部span子節點的text()內容''' tree.xpath("//div[@class='quote']/child::span/text()")
當不指定標籤名稱而使用*代替時,表明匹配全部子節點:
'''選取class爲quote的div節點下全部子節點的text()內容''' tree.xpath("//div[@class='quote']/child::*/text()")
2.7 選取某一節點全部的屬性值
有時候咱們想要獲取知足條件的節點下全部的屬性值:
'''選取class爲quote的div標籤下全部的屬性值''' tree.xpath("//div[@class='quote']/attribute::*")
也能夠指定要提取的具體屬性值,如這裏咱們只提取href,只須要將*替換成href便可:
'''選取class爲tag的a標籤下全部的href屬性值''' tree.xpath("//a[@class='tag']/attribute::href")
2.8 定位某一節點的祖先節點
好比咱們想要獲取class爲keywords的meta標籤之上全部標籤的class屬性內容,能夠像下面這樣:
tree.xpath("//meta[@class='keywords']/ancestor::*/@class")
若想同時包含全部祖先節點及本身自己,則可以使用ancestor-or-self:
tree.xpath("//meta[@class='keywords']/ancestor-or-self::*/text()")
2.9 定位某一節點的後代節點
相似2.8,只不過這裏咱們來定位某一節點之下的全部後代節點,使用descendant:
'''獲取class爲tags的標籤下全部後代節點中a標籤的href信息''' tree.xpath("//div[@class='tags']/descendant::a/@href")
2.10 條件與或非
在xpath中使用邏輯運算來定位的方法以下:
與:
'''定位class爲text且itemprop爲text的span標籤''' tree.xpath("//span[@class='text' and @itemprop='text']/text()")
或:
tree.xpath("//div[@class='quote' or @class='tags']/@class")
非:
'''提取全部span標籤class屬性不爲text的class屬性值''' tree.xpath("//span[not(@class='text')]/@class")
2.11 選取指定標籤結束以後的全部指定標籤
在xpath中咱們可使用following來定位以某個標籤在文檔中的位置爲起點的全部指定標籤:
'''提取全部class爲keywords的meta標籤結束標籤以後出現的標籤a的text()內容''' tree.xpath("//meta[@class='keywords']/following::a/text()")
2.12 選取指定標籤開始以前的全部指定標籤
與following的功能截然相反,在xpath中使用preceding能夠定位指定標籤以前的全部標籤:
'''選取body標籤以前的全部標籤的text()內容''' tree.xpath("//body/preceding::*/text()")
2.13 選取指定標籤結束以後的全部同級指定標籤
在following的基礎上,若想定位全部指定標籤以後且與指定標籤同一級別的標籤,可以使用following-sibling:
'''提取全部class爲keywords的meta標籤結束標籤以後出現的同級別標籤a的text()內容''' tree.xpath("//meta[@class='keywords']/following-sibling::a/text()")
2.14 選取指定標籤開始以前的全部同級指定標籤
相似following-sibling,使用preceding-sibling能夠實現相反的效果:
'''選取body標籤以前的全部同級標籤的text()內容''' tree.xpath("//body/preceding-sibling::*/text()")
2.15 對提取內容中的空格進行規範化處理
在xpath中咱們可使用normalize-space對目標內容中的多餘空格進行清洗,其做用是刪除文本內容以前和以後的全部\s類的內容,並將文本中夾雜的兩個及以上空格轉化爲單個空格,下面比較使用normalize-space先後對提取結果的影響:
'''清洗前''' tree.xpath("//p[@class='text-muted']/text()")
'''清洗後''' tree.xpath("normalize-space(//p[@class='text-muted']/text())")
使用normalize-space以後獲得的結果更加的規整,能夠提升爬取數據的效率。
2.16 在xpath中使用正則表達式
有時候一些任務狀況比較特殊,在xpath中可能沒有對應的函數直接可使用,這時能夠在xpath語句中穿插正則表達式,好比咱們想要提取class爲tag且href屬性符合.*?-.*?page.*?規則的a標籤中的href與text()內容,就能夠在傳入規範的正則命名空間,並利用match來匹配自定義的正則語句,以下:
tree.xpath(r"//a[@class='tag' and ns:match(@href, '.*?-.*?page.*?')]/text() | //a[@class='tag' and ns:match(@href, '.*?-.*?page.*?')]/@href", namespaces={"ns": "http://exslt.org/regular-expressions"})
以上就是本文的所有內容,實際上xpath中還有更多方便使用的功能,本文僅根據筆者的平常使用積累作了片面的總結,若有筆誤之處望斧正!