XPath從入門到精通:基礎和高級用法完整指南,附美團APP匹配示例

来源:https://www.cnblogs.com/easy1996/p/18000898
-Advertisement-
Play Games

廢話不多說,龍年騰雲特效送給大家 預覽 線上預覽 龍年騰雲 源碼 龍是使用的 svg,你也可以替換成其他樣式的龍,而雲是圖片轉化成的 base64 編碼,所以整個文件就是一個 html。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...


XPath 通常用來進行網站、XML (APP )和數據挖掘,通過元素和屬性的方式來獲取指定的節點,然後抓取需要的信息。

學習 XPath 語法之前,首先瞭解一下一些概念。

概念介紹

節點之間的關係

以上面的 HTML 節點樹為例,節點之間包含了下列的關係:

  1. 父節點 (Parent): HTML 是 DIV 和 P 節點的父節點;
  2. 子節點 (Child):DIV 和 P 是 HTML 的子節點;
  3. 兄弟節點 (Sibling):擁有同樣的一個父節點,DIV 和 P 就是兄弟節點。類似的 span、img 和 i 也是兄弟節點。
  4. 祖先節點 (Ancestor):html 是 span 的祖先節點,隔開一級;
  5. 後代節點 (Descendant):span 是 HTML 的後代節點,隔開一級。

除了瞭解這些概念,parent、sibling 等關鍵詞也非常關鍵,在匹配複雜的結構時常常用到。

絕對和相對路徑

xpath 中絕對路徑使用 / 開始,比如:/html/body/div[1]/a/img,絕對路徑較長,其中可能包含變化的部分,不建議單獨使用絕對路徑來選擇元素,最好配合其它語法。
比如下麵的情況單獨使用絕對路徑進行定位就會出錯:

// 本意是匹配第三個div下的span,但因為第一個div因為是動態顯隱的,導致匹配第而個div匹配到之前的第三個了

/html/body/div[2]/span

相對路徑以 // 開始,比如 //*[@class],表示只要包含 class 屬性的元素均可匹配,無論從哪一個節點開始。

下麵是一些常見選擇節點示例:

表達式 說明 舉例
/ 下一個節點,或者根節點開始 /html/body/div
// 從任意節點開始 //img
. 選取當前節點 //a/.
.. 當前節點的父節點 //a/..
@ 選取包含某屬性的元素 //div[@class]或//@class
* 表示任意元素或者任意屬性 //*[@class]

除此之外,通過谷歌瀏覽器-元素上審查元素-複製 xpath,可以直接獲取絕對路徑和相對路徑。

但複製下來的代碼,通常還需要進行一些修改,才能具備通用性。

基礎語法

定位需要的信息通常通過元素、屬性名、屬性值以及三者結合等方式進行。

下麵來分別看一下,也這段 html 代碼為例:

<div id="app">
  <p class="title">喜歡的動物</p>
  <ul>
	<li class="cat">貓</li>
	<li class="dog">狗</li>
	<li id="panda">熊貓</li>
  </ul>
  <p class="title">喜歡的電影</p>
  <ul>
	<li>阿甘正傳</li>
	<li>霸王別姬</li>
	<li>阿凡達</li>
  </ul>
  <p>其它不需要信息</p>
</div>

1. 通過元素名定位

示例:

1.1 //div/p

定位所有 div 下的 p 子元素,可以是任何 div,只要這個 div 的子節點包含 p 就可以匹配

1.2 //ul

會定位從任何節點開始的 ul 元素

1.3 /html/body/div/p

使用絕對路徑定位元素,必須從 /html 開始,否則最好使用 // 相對路徑開始

2. 通過屬性名定位

通過元素是否包含某個屬性來進行定位,屬性名需要使用 @ 開始,同時放在 []

2.1 //*[@class]

定位包含 class 屬性的元素

2.2 //@class

這種語法定位到的是屬性裡面的具體值 title,而不是元素,所有沒有元素沒選中

3. 通過屬性值定位

示例:
//li[@class="cat"]

定位包含 class 屬性,值為 cat 的 li 屬性元素

4. 使用邏輯運算符定位

常用邏輯運算符包括:andornot 三種

示例:

4.1 //li[@class and @class="cat"]

選中包含 class 屬性,並且屬性值為 cat 的 li 元素對象。

4.2 //li[@class or @id]

選中包含 class 或者 id 屬性的 li 元素對象。

4.3 //li[not(@class)]

選中不包含 class 屬性的 li 元素對象。

5. 使用謂語定位

5.1 //li[1]

定位任意元素下的第一個 li。

註意
xpath 中索引從 1 開始。

5.2 (//li)[1]

兩者區別如下:
//li[1] 任意元素下第一個li,也就是說這個 li 在任意的 ul 下是第一個就會被選中
(//li)[1] 將所有的 li 選出來的結果數組中取第一個,這兩者是完全不同的含義

6. 使用文本定位

使用元素中文本的內容進行定位。

示例:

6.1 //li[text()="貓"]

選中文本內容為 的 li 元素對象。

6.2 //*[contains(text(),"喜歡")]

選中任意元素文本中包含 喜歡 兩個字的元素,其中 * 表示所有元素是通配符,contains() 表示包含函數。
類似的有:starts-withends-with 函數,表示以什麼字元開始和字元結尾的文本。

節點選擇器

除了相對和絕對選擇之外,下麵這些選擇器在處理較複雜的匹配場景可以發揮關鍵作用。

  • parent:::選中父級節點,/.. 也是選中父級,但是通常 parent:: 用於寫在 [] 裡面作為條件來判斷
  • child:::選中子級節點,/ 也是選中子級,通常也是作為條件來使用
  • preceding-sibling:::選中同一層級的前面所有兄弟節點
  • following-sibling:::選中同一層級的後面所有兄弟節點
  • ancestor:::選中祖先節點,包括父級以及更上層的節點
  • descendant:::選中當前節點下麵的所有節點,包括子級

舉例:

//*[ancestor::div]

選中所有元素中,上級是 div 的元素,其實也就是選中了所有元素,來看看這個
//ancestor::div

只選中了一個元素。

兩者的區別如下:
//*[ancestor::div] 選中的 * 表示所有元素,這些元素條件是 [ancestor::div] 父級及以上有 div。
//ancestor::div 選中的是作為別人父級及以上的 div,也就是選中的是 div,這個 div 的是別人的父級或者爺級等
兩者是完全不同的概念

美團 APP 匹配示例

看了半天 HTML,我們來瞭解一下 APP 中的 XML,通常匹配 APP 比網頁複雜太多,基本就那幾個元素,而且屬性名基本都一樣,所以常用的手段還是使用各種條件來進行限制匹配,下麵來看一個例子。

 <android.view.View index="5" class="android.view.View" text="" checked="false" clickable="true">
  <android.widget.TextView index="1" class="android.widget.TextView" text="象山酥院(湛江印象匯店)" checked="false"/>
  <android.widget.TextView index="2" class="android.widget.TextView" text="" checked="false" clickable="true"/>
  <android.view.View index="3" class="android.view.View" text="" checked="false">
    <android.widget.TextView index="0" class="android.widget.TextView" text="5.0" checked="false" />
  </android.view.View>
  <android.widget.TextView index="4" class="android.widget.TextView" text="周銷量 872" checked="false" />
</android.view.View>
<android.view.View index="5" class="android.view.View" text="" checked="false" clickable="true">
  <android.widget.TextView index="1" class="android.widget.TextView" text="蜜雪冰城" checked="false"/>
  <android.widget.TextView index="2" class="android.widget.TextView" text="" checked="false" clickable="true"/>
  <android.view.View index="3" class="android.view.View" text="" checked="false">
    <android.widget.TextView index="0" class="android.widget.TextView" text="5.0" checked="false"/>
  </android.view.View>
  <android.widget.TextView index="4" class="android.widget.TextView" text="周銷量 2322" checked="false"/>
</android.view.View>

上面代碼為美團的城市列表頁面的 UI XML 代碼,其中每個元素都包含大量相同的屬性和屬性值,關鍵在於整個頁面,任何地方基本就是 android.view.Viewandroid.widget.TextView ,像匹配 HTML 那樣元素顯然行不通。

示例:獲取兩個商品的評分
//*[@text and ancestor::*/following-sibling::*[contains(@text, '周銷量')]]
規則解釋:獲取任何包含 text 屬性的元素,它的父級的的兄弟元素必須是一個 text 值中包含 "周銷量"的元素。
我這裡沒有使用 [1][2][3] 來定位,是因為不同商品的屬性很多時候不一樣。

通常還是根據想要的元素的位置,以及相鄰元素的特征來定位,首先找到獨特的文本,比如上面的周銷量是固定會出現的,還有 ¥ 符號也可以,這些都是位置和文本值固定的,找到這個的位置,再去定位需要的元素的位置。

工具推薦

  1. 谷歌瀏覽器-審查元素- ctrl + f,可以直接輸入 xpath 語句
  2. 谷歌瀏覽器-selectorshub 插件,文中使用的是這個插件

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 與其說是年終總結,更像是一場回顧,看看這一年 Fantastic-admin 都做了哪些與眾不同的功能,也給大家提供一些創造思路。 ...
  • 回顧 大致掌握了上一節的 插值語法 我已經可以把想要的數據顯示到頁面上,並且僅需要修改變數,頁面就會跟著實時改變 但如果對於已經熟悉前端的人來說,單單有數據還是不太行,還需要css對數據進行樣式的修飾,讓頁面更加好看 所本篇將記錄記錄 Class 與 Style 綁定 的學習 總所周知,想要給DOM ...
  • 回顧 大致掌握了上一節的 插值語法 我已經可以把想要的數據顯示到頁面上,並且僅需要修改變數,頁面就會跟著實時改變 但如果對於已經熟悉前端的人來說,單單有數據還是不太行,還需要css對數據進行樣式的修飾,讓頁面更加好看 所本篇將記錄記錄 Class 與 Style 綁定 的學習 總所周知,想要給DOM ...
  • `async` 和 `defer` 是兩種不同的JavaScript特性,它們的主要區別在於它們的執行順序和時間點。 `async` 意味著函數或代碼塊會被非同步執行。當瀏覽器遇到帶有 `async` 屬性的資源時,它會立即開始下載該資源,同時繼續載入頁面。這樣可以避免由於同步執行而導致的頁面載入阻 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 如何實現一個雨滴落下效果 前言 下雨天坐在車窗前,看著雨滴順著車窗漸漸落下,這一唯美的場景,忍不住想記錄下來。最近在糾結電腦壁紙時,無意間看到有類似的場景,可以將自己喜歡的壁紙加上這種效果。作為多年切圖仔,不由地想到了用css動畫應該可以 ...
  • 描述 這是一個用於 Tampermonkey 或其他支持用戶腳本的瀏覽器擴展的油猴腳本。 看到論壇經常有小伙伴們需要下載某創力文檔-某人文庫一些免費文檔,但是相關網站瀏覽體驗不好各種廣告,各種登錄驗證,需要很多步驟才能下載文檔,該腳本就是為瞭解決您的煩惱而誕生,儘可能做到自動化。 安裝 安裝 Tam ...
  • 已經用 uni-app+vue3+ts 開發了一段時間,記錄一下日常遇見的問題和解決辦法 uni-app 中的單端代碼 uni-app 是支持多端,如果你想讓你的代碼,只在部分平臺使用,那麼就需要用的它的單端處理語法 //#ifdef 和 //#ifndef 等。 1. //#ifdef xxx 只 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 前端開發中難免會遇到價格和金額計算的需求,這類需求所要計算的數值大多數情況下是要求精確到小數點後的多少位。但是因為JS語言本身的缺陷,在處理浮點數的運算時會出現一些奇怪的問題,導致計算不精確。 本文嘗試從現象入手,分析造成這一問題原 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 微服務架構已經成為搭建高效、可擴展系統的關鍵技術之一,然而,現有許多微服務框架往往過於複雜,使得我們普通開發者難以快速上手並體驗到微服務帶了的便利。為瞭解決這一問題,於是作者精心打造了一款最接地氣的 .NET 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...