
.## 一、XPath 簡介XPathXML Path Language是一種在 XML 文檔中查找信息的語言它使用路徑表達式來選取 XML 文檔中的節點或節點集。XPath 最初是為 XSLT 和 XPointer 設計的核心組件但如今已被廣泛應用于Web 爬蟲Python 的 lxml、Scrapy 框架自動化測試Selenium、Appium 元素定位數據提取從 HTML/XML 中解析結構化數據配置文件XML 配置的動態查詢XPath 1.0 是最廣泛支持的版本本文所有語法均基于 XPath 1.0。二、XPath 基本概念2.1 節點類型XPath 將 XML 文檔抽象為七種節點類型節點類型說明示例元素節點ElementXML 標簽book屬性節點Attribute標簽屬性id1文本節點Text標簽內文本Hello World注釋節點CommentXML 注釋!-- comment --處理指令節點PI?xml ...?命名空間節點Namespacexmlns:xsl根節點Root文檔根不可見/2.2 節點關系父節點Parent每個元素和屬性都有且僅有一個父節點子節點Children元素節點可以有零個或多個子元素兄弟節點Siblings擁有相同父節點的節點祖先節點Ancestor父節點、祖父節點等后代節點Descendant子節點、孫子節點等三、XPath 路徑表達式3.1 基本語法XPath 使用類似文件系統的路徑表達式來定位節點/ # 從根節點開始絕對路徑 // # 從當前節點的后代中選取相對路徑 . # 當前節點 .. # 當前節點的父節點 # 選取屬性 * # 通配符匹配任意元素節點 * # 通配符匹配任意屬性節點 node() # 匹配任意類型節點 text() # 匹配文本節點 comment() # 匹配注釋節點3.2 常用路徑示例假設有如下 XML 文檔bookstorebookcategorycookingtitlelangenEveryday Italian/titleauthorGiada De Laurentiis/authoryear2005/yearprice30.00/price/bookbookcategorychildrentitlelangenHarry Potter/titleauthorJ K. Rowling/authoryear2005/yearprice29.99/price/book/bookstore表達式結果bookstore選取 bookstore 元素的所有子節點/bookstore選取根元素 bookstorebookstore/book選取 bookstore 下所有 book 子元素//book選取所有 book 元素無論位置bookstore//book選取 bookstore 后代中所有 book//lang選取所有名為 lang 的屬性/bookstore/book[1]第一個 book 子元素/bookstore/book[last()]最后一個 book 子元素/bookstore/book[position()3]前兩個 book//title[lang]所有帶 lang 屬性的 title//title[langen]lang 屬性為 en 的 title/bookstore/book[price30]price 大于 30 的 book四、XPath 軸Axes軸定義了相對于當前節點的節點集是 XPath 強大定位能力的核心。4.1 軸的語法軸名稱::節點測試[謂詞]4.2 常用軸一覽軸名稱縮寫說明ancestor當前節點的所有祖先父、祖父…ancestor-or-self祖先及自身attribute當前節點的所有屬性child默認當前節點的所有子元素descendant//當前節點的所有后代descendant-or-self后代及自身following文檔中當前節點結束標簽之后的所有節點following-sibling當前節點之后的所有兄弟節點namespace當前節點的所有命名空間節點parent..當前節點的父節點preceding文檔中當前節點開始標簽之前的所有節點preceding-sibling當前節點之前的所有兄弟節點self.當前節點自身4.3 軸使用示例# 選取當前節點的所有子元素 child::book # 選取當前節點的所有屬性 attribute::lang # 等價于 lang # 選取當前節點所有后代中的 title descendant::title # 等價于 .//title # 選取當前節點的父節點 parent::node() # 等價于 .. # 選取當前節點之后的所有兄弟 book following-sibling::book # 選取當前節點之前的所有兄弟 preceding-sibling::*五、XPath 謂詞Predicates謂詞用于過濾節點集寫在方括號[]中返回布爾值。5.1 數值謂詞# 第一個子元素 /bookstore/book[1] # 最后一個子元素 /bookstore/book[last()] # 倒數第二個 /bookstore/book[last()-1] # 前三個 /bookstore/book[position() 3]5.2 屬性謂詞# 存在 lang 屬性 //title[lang] # lang 屬性等于 en //title[langen] # 多屬性條件 //input[typetext and nameusername] # 屬性包含某值 //div[contains(class, header)] # 屬性以某值開頭 //a[starts-with(href, https)]5.3 文本謂詞# 文本完全匹配 //a[text()登錄] # 文本包含 //button[contains(text(), 提交)] # normalize-space 去除空白后匹配 //div[normalize-space(text())Hello World]5.4 邏輯運算符# and //book[categorycooking and price25] # or //book[price10 or price50] # not() //div[not(class)] # ! //title[lang!en]六、XPath 內置函數XPath 1.0 提供了豐富的內置函數分為四大類。6.1 節點集函數函數說明last()當前節點集中最后一個節點的位置position()當前節點在節點集中的位置從1開始count(node-set)返回節點集中的節點數量name(node-set?)返回節點的名稱local-name(node-set?)返回不帶命名空間前綴的名稱namespace-uri(node-set?)返回命名空間 URI6.2 字符串函數函數說明string(obj?)將對象轉換為字符串concat(string, string, ...)字符串拼接contains(s1, s2)s1 是否包含 s2starts-with(s1, s2)s1 是否以 s2 開頭substring(s, start, len?)截取子串substring-before(s1, s2)s2 之前的部分substring-after(s1, s2)s2 之后的部分string-length(s?)字符串長度normalize-space(s?)去除首尾空白合并中間空白translate(s1, s2, s3)字符替換6.3 數值函數函數說明number(obj?)轉換為數字sum(node-set)節點集數值求和floor(num)向下取整ceiling(num)向上取整round(num)四舍五入6.4 布爾函數函數說明boolean(obj)轉換為布爾值not(condition)邏輯非true()返回 truefalse()返回 falselang(string)判斷節點語言七、XPath 運算符7.1 完整運算符列表運算符說明示例|節點集合并//h1 | //h2加法price 10-減法price - 5*乘法price * 1.1div除法price div 2mod取模position() mod 2等于id1!不等于class!hidden小于price10小于等于price10大于price10大于等于price10and邏輯與a and bor邏輯或a or b注意XPath 中除法用div取模用mod不能用/和%。八、實戰場景HTML 元素定位8.1 Selenium 常用定位技巧fromseleniumimportwebdriverfromselenium.webdriver.common.byimportBy driverwebdriver.Chrome()# 1. 通過 id 定位driver.find_element(By.XPATH,//*[idusername])# 2. 通過 class 定位注意 class 是多值屬性driver.find_element(By.XPATH,//div[contains(class, login-form)])# 3. 通過文本定位driver.find_element(By.XPATH,//button[text()登錄])# 4. 通過父子關系定位driver.find_element(By.XPATH,//form[idlogin]//input[typesubmit])# 5. 通過兄弟節點定位driver.find_element(By.XPATH,//label[text()密碼]/following-sibling::input)# 6. 通過索引定位從1開始driver.find_element(By.XPATH,(//table//tr)[2]/td[3])8.2 Python lxml 解析示例fromlxmlimportetree html html body ul classmenu lia href9/home首頁/a/li lia href/about關于/a/li lia href/contact聯系/a/li /ul /body /html treeetree.HTML(html)# 獲取所有鏈接文本textstree.xpath(//ul[classmenu]//a/text())print(texts)# [首頁, 關于, 聯系]# 獲取所有 href 屬性hrefstree.xpath(//ul[classmenu]//a/href)print(hrefs)# [/home, /about, /contact]# 同時獲取文本和屬性itemstree.xpath(//ul[classmenu]//a)foriteminitems:print(item.text,item.get(href))九、高級技巧與注意事項9.1 XPath 軸的組合使用# 找到當前 td 所在行的第一個 td ./ancestor::tr/td[1] # 找到當前元素前面最近的一個 h2 ./preceding::h2[1] # 找到當前 div 的下一個兄弟 section ./following-sibling::section[1]9.2 常見陷阱索引從 1 開始XPath 的位置索引從 1 開始不是 0class 屬性是多值的classbtn只能匹配完全等于 btn 的元素推薦用contains(class, btn)text() 只取直接子文本如果元素內有嵌套標簽text()只取直接文本節點用.或string()獲取全部文本命名空間問題有命名空間的文檔需要注冊命名空間才能正確查詢謂詞中的 and/orXPath 用and/or不是/||9.3 性能優化建議優先使用//會掃描整個文檔盡量縮小范圍如//div[idmain]//a避免使用//*全文檔掃描屬性定位比文本定位更穩定復雜頁面優先使用 id 或唯一 class 作為錨點十、總結XPath 是一門強大而簡潔的查詢語言掌握它的核心在于理解節點模型把 XML/HTML 看作節點樹熟練路徑表達式/、//、.、..、是基礎善用軸定位軸是 XPath 區別于 CSS 選擇器的核心優勢靈活運用謂詞謂詞讓定位更精確掌握常用函數contains、text()、position()等是高頻使用無論是爬蟲、自動化測試還是數據解析XPath 都是不可或缺的工具。希望本文能幫助你系統掌握 XPath 語法。如果本文對你有幫助歡迎點贊、收藏、關注三連支持