xpath--数据提取的魔法棒
xpath介绍
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。
XPath使用路径表达式在XML文档(字符串)中选取节点,节点是通过沿着路径来选取的。路径由节点名组成,节点之间以“/”分割。
在查找web的某些元素时,我们可以通过xpath查找到特定的元素。
如何测试xpath
在浏览器(以chrome为例)中开启控制台,点击元素,按快捷键ctrl+f并在搜索框中输入xpath即可测试xpath是否成功运作
术语
节点
以以下XML为例:
<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book>
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。XML 文档是被作为节点树来对待的。树的根被称为文档节点或者根节点。
上面的XML文档中的节点例子:
<bookstore>
:(文档节点)<author>J K. Rowling</author>
:(元素节点)lang="en"
(属性节点)
节点关系
父(Parent)
每个元素以及属性都有一个父。
在下面的例子中,book 元素是 title、author、year 以及 price 元素的父:
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
子(Children)
元素节点可有零个、一个或多个子。
在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子:
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
同胞(Sibling)
拥有相同的父的节点
在下面的例子中,title、author、year 以及 price 元素都是同胞:
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
先辈(Ancestor)
某节点的父、父的父,等等。
在下面的例子中,title 元素的先辈是 book 元素和 bookstore 元素:
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
后代(Descendant)
某个节点的子,子的子,等等。
在下面的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素:
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
路径表达式
基础路径表达式
以下是基础的路径表达式:
表达式 | 描述 |
---|---|
| 选取此节点的所有子节点。 |
| 从根节点选取。 |
| 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
| 选取当前节点。 |
| 选取当前节点的父节点。 |
| 选取属性。 |
用以下XML为例:
<?xml version="1.0" encoding="ISO-8859-1"?>
<body>
<head>
<div lang="en">Harry Potter</div>
<div><a href="www.baidu.com">J K. Rowling</a></div>
<div class="aaa">2005</year>
<div><span>29.99</span></div>
</head>
</body>
以下是一些路径表达式的参考语法
路径表达式 | 结果 |
---|---|
| 选取 body 元素的所有子节点。 |
| 选取根元素下head。假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
| 选取属于 div 的子元素的所有 a 元素。 |
| 选取所有 a 子元素,而不管它们在文档中的位置。 |
| 选择属于 div 元素的后代的所有 a 元素,而不管它们位于 bookstore 之下的什么位置。 |
| 选取名为 class 的所有属性。 |
| 选取当前元素下的a |
| 选取父元素下的a |
| 选取a标签的href属性 |
通配符
在XPath中,可以使用通配符来匹配特定的节点。一般以*
为主
通配符 | 说明 | 举例 |
---|---|---|
| 匹配任何元素节点 |
|
| 匹配任何属性节点,即匹配具有属性的节点,不包含无属性的节点。 |
|
| 匹配选择路径下的任何类型的节点。 |
|
谓语
在XPath中,谓语(Predicate)是一个可选的子句,用于进一步过滤符合谓语条件的节点。谓语通常用于选择满足特定条件的元素或属性。
谓语的语法是在方括号中包含条件表达式,例如:[condition]
。谓语可以用于选择具有特定属性值的元素、特定文本内容的元素、满足位置条件的元素等。
下面是一些实例:
路径表达式 | 结果 |
---|---|
| 选取属于body子元素的第一个div元素。 |
| 选取属于body子元素的最后一个div元素。 |
| 选取属于body子元素的倒数第二个div元素。 |
| 选取所有拥有名为lang的属性的div元素。 |
| 选取所有拥有名为lang等于eng的属性的div元素。 |
运算符
下面列出了可用在 XPath 表达式中的运算符:
运算符 | 作用 | 示例 |
---|---|---|
| | 匹配多个条件 | //book | //cd |
+ | 加法 | 1 + 1 |
- | 减法 | 2 - 1 |
* | 乘法 | 1 * 2 |
div | 除法 | 4 div 2 |
= | 等于 | price=10 |
!= | 不等于 | price!=10 |
< | 小于 | price<10 |
<= | 小于或等于 | price<=10 |
> | 大于 | price>10 |
>= | 大于或等于 | price>=10 |
or | 或(匹配满足至少一个条件的节点) | //div[@class="1" or @class="2"] |
and | 与(匹配同时满足条件的节点) | //div[@class="1" and @id="2"] |
mod | 计算除法的余数 | 5 mod 2 |
通过节点关系选择元素
选取当前节点的结束标签之后的所有节点,包括节点的子孙节点
//li[@class="item-0"]/following::li # 获取li后面的所有节点中的li
选取当前节点的开始标签之前的所有节点,包括节点的子孙节点
//li[@class="item-0"]/preceding::li # 获取li前面的所有节点中的li
选取当前节点之后的所有同级节点
//li[@class="item-0"]/following-sibling::li # 获取li后面所有同级节点中的li
选取当前节点的子元素
//ul/child::* # 获取ul所有的子元素
//ul/child::li # 获取ul所有子元素中的li
选取当前节点的属性
//ul/li/attribute::* # 获取li的所有属性
//ul/li/attribute::class # 获取li所有属性中的class属性
选择父辈元素或父辈元素及当前元素
//div[@id="testid"]/ancestor::* # 获取div所有父元素
//div[@id="testid"]/ancestor::div # 获取div所有父元素中的div
//div[@id="testid"]/ancestor-or-self::* # 获取div所有父元素及当前元素
//div[@id="testid"]/ancestor-or-self::div # 获取div所有父元素及当前元素中的div
选择后代或后代及当前节点本身
//div[@id="testid"]/descendant::* # 获取div所有后代元素
//div[@id="testid"]/descendant::div # 获取div所有后代元素中的div
//div[@id="testid"]/descendant-or-self::* # 获取div所有后代元素及当前元素
//div[@id="testid"]/descendant-or-self::div # 获取div所有后代元素及当前元素中的div
xpath函数
XPath 提供了许多内置函数
获取文本
/text()
:获取当前节点文本,不包括子孙节点;
//text()
:获取当前节点和子孙节点的文本,若有多个,返回多个字符串的列表;
string()
:获取匹配第一个节点的所有文本(包括子孙节点)
示例:
//li[@class="item-0"]/a/text()
//li[@class="item-0"]//text()
string(//li[@class="item-0"])
包含
选择文本中或属性中包含某些内容的元素
//*[contains(text(),"123")] # 选择所有文本中包含123的节点
//*[contains(@href, "test")] # 选择所有属性href中包含test的节点
以...开始
选择文本中或属性中以某些内容开始的元素
//li[starts-with(@class,"test")] # 匹配类名以test开头的li
定位
返回元素的位置,其中:
选择偶数项:
[position()=(position() mod 2 = 0)]
选择奇数项:
[position()=(position() mod 2 != 0)]
//li[1] # 选择第一个li
//li[position()<3] # 选择定位小于3的li
//li[position()<6 and position()>3] # 选择定位大于3小于6的li
//li[last()] # 选择最后一个li
//li[last()-2] # 选择倒数第三个li
# 重点:匹配奇数项和偶数项
//tr/td[position()=(position() mod 2 = 0)] # 匹配tr下面所有的偶数个td
//tr/td[position()=(position() mod 2 != 0)] # 匹配tr下面所有的奇数个td
非
选择没有某个属性值的元素
//li[not(@data)] # 获取所有没有data属性的li
统计子节点数量
统计节点下的某个子节点数量,并选择当前节点下某个子节点数量为多少的元素
//ul[count(li)>10] # 获取子节点li数量超过10个的ul