XPath

学习自:

XPath官方文档

XPath 教程

lxml+Xpath实现爬虫ck784101777的博客-CSDN博客

0、简介

XPath是一门在XML文档中查找信息的语言。

Xpath可以用于在XML文档中对元素和属性进行遍历。

XPath是W3C XSLT标准的主要元素,并且XQueryXPointer都可以构建于XPath表达之上。

因此,对XPath的理解是很多高级XML应用的基础。

①、什么是XPath

XPath使用路径表达式在XML文档中进行导航

XPath包含了一个标准函数库

XPath是XSLT中的主要元素

XPath是一个W3C标准

②、XPath路径表达式

XPath使用路径表达式来选取XML文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。

③、XPath标准函数

XPath含有100个内建的函数。这些函数用于字符串值、数值、日期、时间、节点、QName处理、序列处理、逻辑值等等。

④、XPath在XSLT中使用

XPath是XSLT主要元素,如果没有XPath方面的知识,就无法创建XSLT文档。

XQuery和XPointer均构建在XPath表达式之上。

1、XPath节点

在XPath中,有7种类型的节点:元素、属性、文本、命名空间、处理指令、注释、文档节点(根节点)

①、XPath术语

节点(Node):在XPath中,有7种类型的节点。XML文档是被作为节点树对待的,树根被称为文档节点根节点

基本值(原子值,Atomic value):无父或无子的节点。

项目(Item):基本值或者节点。

②、节点关系

父(Parent):每个元素以及属性都有一个父节点

子(Children):元素节点可以有0、1或多个

同胞(Sibling):拥有相同父节点的节点

祖先(Ancestor):父节点、父的父……

后代(Descendant):子节点、子的子……

2、XPath语法

XPath使用路径表达式来选取XML文档中的节点或者节点集。节点是通过路径(Path)步(Steps)来选取的。

以一个XML文档为例介绍:

复制代码
<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

<book>
    <title lang='eng'>Harry Potter</title>
    <price>29.99</price>
</book>

<book>
    <title lang='eng'>Learning XML</title>
    <price>39.95</price>
</book>

</bookstore>
复制代码

①、路径表达式

表达式对字母大小写、单双引号不敏感,但是建议写对

表达式 描述
nodename 该节点的所有子节点(一层子节点,而非所有后代)
/

以该元素为根;

如果路径起始于/,则该路径始终表示到某元素的绝对路径

// 所有匹配选择的元素,而不管它们在文档中的位置
. 选取当前节点
.. 当前节点的父节点
@ 选取属性

实例:

路径表达式 结果
bookstore bookstore的所有子元素
/bookstore 节点bookstore
bookstore/book bookstore的子元素book
//book 所有的book,不管它们在文中的位置,即不论它们是否是bookstore的子元素
bookstore//book bookstore下的所有book(区别于/只是子元素,//包括了所有后代)
//@lang 选取名为lang的所有属性

②、谓语

用来查找某个特定节点或者包含某个指定值的节点。谓语被嵌在方括号[ ]

实例:

路径表达式 结果
/bookstore/book[1] bookstore子元素中第一个book(下标从1开始而不是0)
/bookstore/book[last()] bookstore子元素中最后一个book
/bookstore/book[last()-1] bookstore子元素中倒数第二个book
/bookstore/book[position()<3] bookstore子元素中最前边两个book
//title[@lang] 所有拥有属性lang的元素title
//title[@lang='eng'] 所有拥有属性lang且值为eng的元素title
/bookstore/book[price>35.00] bookstore子元素book,且该book的同胞元素price须大于35.00(此处price与book为同胞,而非book的属性)
/bookstore/book[price>35.00]/title bookstore子元素book的子元素title,且该book的同胞price大于35.00

③、通配符、未知元素

XPath通配符可以用来选取未知的XML元素

通配符 描述
* 匹配任何元素节点
@* 匹配任何属性节点
node() 匹配任何类型的节点

实例

路径表达式 结果
/bookstore/*

bookstore下的所有子元素

等同于单一个bookstore

//* 文档中的所有元素
//title[@*] 所有带有属性的title元素

④、选取多个元素

在路径表达式中使用'|'运算符,可以选取多个路径

实例

路径表达式 结果
//book/title | //book/price 所有book元素下的price和title元素
//price | //title 文档中的所有的price和title元素
/bookstore/book/title | //price bookstore下的book下的title元素和文档中的所有price元素

4、XPath Axes(轴)

①、轴

定义相对于当前节点节点集

说明(相对当前节点)
ancestor 所有祖先
ancestor-or-self 所有祖先、包括自己
attribute 所有属性
child 所有子元素
descendant 所有后代
descendant-or-self 所有后代、包括自己
following 当前节点的结束标签之后的所有节点
namespace 所有命名空间节点
parent 父节点
preceding 开始标签前的所有节点
preceding-sibling 当前节点前的所有同胞节点
self 当前节点

②、位置路径表达式

位置路径可以是绝对的,也可以是相对的。

绝对路径起始于正斜杠/,相对路径则以节点名开始:

<!--绝对路径-->
/step/step/...
<!--相对路径-->
step/step/...

在两种情况下,路径均包含一个或者多个,每个步被斜杠/分割

③、步(step)

步的语法:

轴名称::节点属性[ 谓语 ]

实例

路径表达式 结果(有存在时均为相对于当前节点
child::book 子元素的book节点
attribute::lang 当前节点的lang属性
child::* 所有子元素
attribute::* 所有属性
child::text() 所有文本子节点
child::node() 所有子节点
descendant::book 所有book后代
ancestor::book 所有book先辈
ancestor-or-self::book 所有book先辈和该节点本身(如果它是book节点的话)
child::*/child::price 所有子节点中的price子节点(price孙节点)

5、XPath运算符

运算符有|、+、-、*、div、=、!=、<、<=、>、>=、or、and、mod

这里的运算符的运算方法与其他语言的运算方法相同,现在只补充若干项说明:

运算符 说明 实例 返回值
| 这个不是或运算符,而是选择两个节点集 //book | //cd 所有book与cd节点
div 触发 8 div 4 2
比较运算符 如果表达式为真,返回true;否则返回false A = B(相等比较只需写一个等号)  
mod 余数 5 mod 2 1
逻辑运算符 需要两个表达式,对它们进行逻辑运算 price=9 or price= 10  price为9或10时为true,否则false

6、实例

①、实例文档

我们在下面的例子中使用XML文档 'books.xml'

复制代码
<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

<book category="COOKING">
  <title lang="en">Everyday Italian</title>
  <author>Giada De Laurentiis</author>
  <year>2005</year>
  <price>30.00</price>
</book>

<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

<book category="WEB">
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
</book>

<book category="WEB">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
</book>

</bookstore>
复制代码

②、加载XML文档

所有现代浏览器都支持使用XMLHttpRequest来加载XML文档的方法。

针对大多数现代浏览器的代码:

var xmlhttp = new XMLHttpRequest()

针对IE5、6的代码:

var xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')

③、选取节点

IE浏览器使用selectNodes()方法从XML文档中选取节点:

xmlDoc.selectNodes(xpath);

其他浏览器使用evaluate()方法从XML文档中选取节点:

xmlDoc.evaluate(xpath , xmlDoc , null , XPathResult.ANY_TYPE , null )

 7、在爬虫中的应用

 下载Chrome插件XPath helper,有了这个插件之后,我们可以很轻松的获取到页面中的要素的XPath写法(当然,如果刚开始学XPath,建议还是动手写上一些,熟练掌握之后再用这个插件)。

 

测试页面为猫眼电影网:https://maoyan.com/board

①、查看页面源码

按F12进入开发者模式,按CTRL+SHIFT+C找到想要爬取的要素的源码。

 

 2)信息分析与XPath构建

可以看到,电影名都是在<div class="movie-item-info">下的p标签的a链接的内容。

依照我们之前所学XPath的内容,div、p、a都是节点class、title等都是节点属性,因此我们就可以以此为出发点构建XPath:

//div[@class="movie-item-info"]/p/a

上文就表示,整个页面中所有的class="movie-item-info"的节点div的子节点p的子节点a

我们用XPath helper插件验证一下:

 

 可以发现成功筛选出了这个页面中的所有电影。

8、进阶(以7中的网页为例)

①带属性值的匹配

所有的影片信息,都在<div class="movie-item-info">下,我们找到这个div的始终(上图左边红框),可以看到,一个影片信息由3个标签p构成,而标签p的不同class,则分别代表了具体的信息,比如上图蓝框中的,name——片名、star——主演、releasetime——上映时间

 

 我们就可以通过设置属性值class来筛选具体想要的信息(实际应用中,单引号双引号作用相同):

 

 

 

②查看第n个标签

可以通过[n]决定输出第几个标签的内容,不加n将输出所有的内容

//div[@class="movie-item-info"]/p[1]

代码意思是:筛选所有影片的第一个标签(之前曾说过每个影片有3个p标签,分别是片名、主演和时间),即片名

 

 

③输出属性值

方法:把@属性作为普通项放在斜杠之后,而不是在中括号中即可。

举例:获取所有影片名和其对应的链接

二者都是a标签下的属性,链接是属性href影片名是属性title

//div[@class='movie-item-info']/p[@class='name']/a/@href
//div[@class='movie-item-info']/p[@class='name']/a/@title

 

9、XPath常用函数

所有函数见 :XPath、XQuery 以及 XSLT 函数

注意:

1)使用时将想要进行函数的元素,作为函数的参数,而不是作为调用函数的对象(即不要写为a.func()的形式);

2)判断类函数使用时常用在[]内,做筛选,比如下文的contain

3)转换类函数可以当做节点使用,表明对上一节点进行转化,比如下文的text

 

contains():匹配属性值中包含某些字符串的节点(类似Pythonin 关键字)

节点li有两种类型的属性id

<li id="car_bw" >宝马</li>

<li id="car_byd" >比亚迪</li>

二者的相同点是都是以car_为前缀,所以我们只要检查id属性中是否有字符串car_即可

//li[contain(@id,'car_')]

text():获取标签中的内容,并作为字符串输出

 

//div[@class='movie-item-info']/p[@class='name']/a/text()

 

为什么要用text(),不加text()或者不以@属性结尾的情况下,返回的结果都是Element,即元素节点,如果想把抓取的结果作为String输出,必须加上text()或者@属性

 

10、易错点

①@的使用场景

  1)属性值作为条件

 

    //p/a[@title='金刚川']

  2)直接获取属性值

    //p/a/@href

②获取文本内容需要加text()9.②

③element与string,见9.②

 ④父节点的父节点:../..

11、Python对XPath的支持

python要使用XPath,需要安装lxml模块。只需在命令行窗口中输入pip3 install lxml即可。如果是Linux系统,指令为sudo pip3 install lxml。

 

posted @   ShineLe  阅读(184)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示