XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历,而将 HTML文档转换成 XML文档后,就可以用 XPath 查找 HTML 节点或元素。
XML 文档的特点:
XML 文档中的每个成分都是一个节点。整个文档是一个根节点;每个 XML 标签是一个元素节点;包含在 XML 元素中的文本是文本节点;每一个 XML 属性是一个属性节点;注释则属于注释节点。
其中,元素节点可以包含任意的元素节点、文本节点或属性节点,而文本节点或属性节点则不能包含节点。
XPath语法的特点:
XPath 使用路径表达式在 XML 文档中进行导航
XPath 包含一个标准函数库
XPath 表达式可返回节点集、字符串、逻辑值以及数字。
常用的XPath 开发工具:
1.开源的XPath表达式编辑工具:XMLQuire(仅XML格式文件可用)。
2.Firefox插件 Try XPath。
3.Chrome插件 XPath Helper。推荐!可以直接在网页上使用xpath定位元素,非常方便。(安装详情见参考文献2)
一、XPath语法介绍
1. 选取节点
下表列出了常用的路径表达式:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 如果在路径最前面代表从根节点选取,否则表示选择某节点的子节点 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 表示当前节点 |
.. | 表示当前节点的父节点 |
@href | 节点href属性的值(/@href:当前节点href属性的值;//@href:当前节点和子孙节点href属性的值) |
text() | 节点的文本内容(/text():当前节点的文本内容;//text():当前节点和子孙节点的文本内容) |
2.谓语
谓语:用来查找某个特定的节点或者包含某个指定属性值的节点,被嵌在方括号中。
- /bookstore/book[1]:选取属于 bookstore 子元素的第一个 book 元素。注意位置顺序是从1开始的,和python不一样!
- /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 元素,条件:price属性的值须大于 35.00。
3.XPath的运算符
- 加法:+
- 减法:-
- 乘法:*
- 除法:div
- =:等于
- !=:不等于
- <:小于
- <=:小于或等于
- >:大于
- >:大于或等于
- or:或
- and:与
- mod:计算除法的余数
4.XPath的轴
轴可定义相对于当前节点的节点集。
语法:轴名称::节点[谓语]
常用的轴:
- ancestor:选取当前节点的所有先辈节点(父、祖父等)。
- ancestor-or-self:选取当前节点的所有先辈节点(父、祖父等)以及当前节点本身。
- attribute:选取当前节点的所有属性。
- self:选取当前节点。
- child:选取当前节点的所有子节点。
- parent:选取当前节点的父节点。
- descendant:选取当前节点的所有后代节点(子、孙等)。
- descendant-or-self:选取当前节点的所有后代节点(子、孙等)以及当前节点本身。
示例:
- //li[@data="one"]/ancestor::div:选取属性data="one"的li节点的所有div祖先节点。
- //li[@data="one"]/ancestor::*:选取属性data="one"的li标签的所有祖先节点。
- //div[@id="testid"]/attribute::*:选取id="testid"的div节点的所有属性值。
- //div[@id]/self::div[@data-h]/attribute::*:选取含id属性和data-h属性的div标签的所有属性值
- //div[@id="testid"]/child::*:选取id="testid"的div节点的所有子节点。
- //li[@data="one"]/parent::ol/li[last()]/text():选取属性data="one"的li节点的父节点ol,其最后一个li子节点的文本值。
注意:由于每个元素节点只有唯一的一个父节点,所以“parent::父节点”等价于“parent::*” 。
5.XPath常用函数
- contains ()函数:
//div[ contains(@class, 'in') ]:选择class属性值中包含有’in’字符串的div节点。 - text()函数:节点的文本值
//a[text()='baidu']:选取文本值等于'baidu'的a节点。
//a/text():获取a节点文本内容。 - last()函数:
/bookstore/book[last()]:选取属于 bookstore 子节点的最后一个 book 节点。 - position()函数:返回节点的索引位置(从1开始)
/bookstore/book[position()<=3]:选取属于 bookstore 子节点的前三个 book 节点。 - starts-with()函数:
//div[starts-with(@class,'in')]:选择class属性值以字符串’in’开头的div节点。 - ends-with()函数:
//div[ends-with(@class,'in')]:选择class属性值以字符串’in’结尾的div节点。 - not()函数:表示否定
//input[@name=‘identity’ and not( contains(@class,‘a’) )]:
选择属性name=‘identity’ 并且 class属性值中不包含字符’a’的input节点。
not()函数通常与返回值为true or false的函数组合起来用,比如contains(),starts-with()等。但有一种特别情况需注意一下://input[@id]:匹配出含有id属性的input节点;//input[not(@id)]:匹配出不含有id属性的input节点。
6.其他
1.通配符
使用通配符“*”可用来选取未知的 XML 元素。
*:匹配任何元素节点。
@*:匹配任何属性节点。
node():匹配任意类型的节点(元素、属性、文本、注释以及根节点)。
2.选取多条路径
通过在路径表达式中使用“|”运算符,可以选取多条路径。
//book/title | //book/price:选取 book 元素的所有 title 和 price 元素。
//title | //price:选取文档中的所有 title 和 price 元素。
二、xpath在python中的具体运用
lxml库是一个XML、HTML的解析器,主要用于解析和提取XML、HTML数据。lxml库先将HTML文档解析,然后就可以使用XPath 搜索或遍历HTML文档中的节点。
使用lxml解析HTML数据的两种方式:
1.解析HTML字符串:
from lxml import etree
# HTML字符串
text = '''
<bookstore>
<book>
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<name>杰克罗琳</name>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
'''
# 使用HTML()方法解析字符串
# HTML()默认使用的就是HTML解析器,如果遇到不规范的HTML代码,会自动补全。
html_element = etree.HTML(text)
# 解析后就可以调用xpath方法了
name = html_element.xpath('//book/name/text()')
print(name)
# 返回值:
# ['杰克罗琳']
2.直接解析HTML文件:
from lxml import etree
# 创建HTML解析器,指定解析器使用的编码格式(需要和文件编码格式一致)
parser = etree.HTMLParser(encoding='utf-8')
# parse()默认的是XML解析器,在解析HTML代码时,如果HTML代码不规范,则会报错!
# 因此需要指定解析器为HTML解析器,这样不规范的HTML代码,会自动补全!
html_element = etree.parse('./test.html', parser=parser)
#解析后就可以调用xpath方法了
name = html_element.xpath('//book/name/text()')
print(name)
# 返回值:
# ['杰克罗琳']
注意:
1.xpath返回的永远是列表,即使没有匹配到任何元素也返回的是空列表。
2.根节点和任意元素节点都可以使用xpath方法去搜索、遍历其子节点。
# tostring()方法可以将节点对象转换成字节,解码后就可以查看节点内容
author_ele = html_element.xpath('//book/author')[0]
result = etree.tostring(author_ele, encoding='utf-8').decode('utf-8')
print(result)
# 返回值:
# <author>J K. Rowling</author>
参考文献: