XPath 是一门在 XML 文档中查找信息的语言。XPath 用来在 XML 文档中对元素和属性进行遍历。关于xpath的说明文档可以参照:XPATH基础说明
首先掌握基础知识:
F12开发者工具有console标签,在其内执行console命令可以交互性验证css或者xpath表达式效果
xpath用,将表达式用引号括起来放进去,回车执行命令,如果成功产生非空输出的匹配元素列表(可以点击自动框选定位、可以展开子元素查看),举例:利用F12 找到对应连接,并利用$x()找到文件
正式进入XPATH:
1.路径表达式语法、相对/绝对路径
2.表达式上下文
3.谓词(筛选表达式)及轴的概念
4.运算符及特殊字符
5.常用表达式实例
6.函数及说明
简单说,xpath就是选择XML文件中节点的方法。
所谓节点(node),就是XML文件的最小构成单位,一共分成7种。
- element(元素节点)
- attribute(属性节点)
- text (文本节点)
- namespace (名称空间节点)
- processing-instruction (处理命令节点)
- comment (注释节点)
- root (根节点)
xpath可以用来选择这7种节点。不过,下面的笔记只涉及最常用的第一种element(元素节点),因此可以将下文中的节点和元素视为同义词。
1.路径表达式语法(书面文章):
路径 = 相对路径 | 绝对路径
XPath路径表达式 = 步进表达式 | 相对路径 "/"步进表达式。
步进表达式=轴 节点测试 谓词
说明:
其中轴表示步进表达式选择的节点和当前上下文节点间的树状关系(层次关系),节点测试指定步进表达式选择的节点名称扩展名,谓词即相当于过滤表达式以进一步过滤细化节点集。
谓词可以是0个或多个。多个多个谓词用逻辑操作符and, or连接。取逻辑非用not()函数。
案例说明:
请看一个典型的XPath查询表达式:/messages/message//child::node()[@id=0],其中/messages/message是路径(绝对路径以"/“开始),child::是轴表示在子节点下选择,node()是节点测试表示选择所有的节点。[@id=0]是谓词,表示选择所有有属性id并且值为0的节点。
相对路径与绝对路径:
如果”/“处在XPath表达式开头则表示文档根元素,(表达式中间作为分隔符用以分割每一个步进表达式)如:/messages/message/subject是一种绝对路径表示法,它表明是从文档根开始查找节点。假设当前节点是在第一个message节点【/messages/message[1]】,则路径表达式subject(路径前没有”/")这种表示法称为相对路径,表明从当前节点开始查找。具体请见下面所述的"表达式上下文"。
表达式上下文(Context):
上下文其实表示一种环境。以明确当前XPath路径表达式处在什么样的环境下执行。例如同样一个路径表达式处在对根节点操作的环境和处在对某一个特定子节点操作的环境下执行所获得的结果可能是完全不一样的。也就是说XPath路径表达式计算结果取决于它所处的上下文。
看懂上面看下面,一样的:
一、xpath表达式的基本格式
xpath通过"路径表达式"(Path Expression)来选择节点。在形式上,"路径表达式"与传统的文件系统非常类似。
# 斜杠(/)作为路径内部的分割符。
# 同一个节点有绝对路径和相对路径两种写法。
# 绝对路径(absolute path)必须用"/"起首,后面紧跟根节点,比如/step/step/...。
# 相对路径(relative path)则是除了绝对路径以外的其他写法,比如 step/step,也就是不使用"/"起首。
# "."表示当前节点。
# ".."表示当前节点的父节点
二、选择节点的基本规则
- nodename(节点名称):表示选择该节点的所有子节点
- "/":表示选择根节点
- "//":表示选择任意位置的某个节点
- "@": 表示选择某个属性
xpath:对应函数也是比较多的,大概有100多所以可以参照上面的参考网址。
三、选择节点的实例
先看一个XML实例文档。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>建立测试网址文本</title>
</head>
<body>
<div id="content" version="1.0">
<ul id="useful">
<li>数学建模方法</li>
<li>数学建模数据</li>
<li>数学建模软件</li>
</ul>
<ul id="useless">
<li>不需要的信息1</li>
<li>不需要的信息2</li>
<li>不需要的信息3</li>
</ul>
<book>
<title lang="eng">数学建模书籍1</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">数学建模书籍2</title>
<price>39.95</price>
</book>
<div id="url">
<a href="http:nveyun.com">虐云建模网</a>
<a href="http://nveyun.com/forum.php" title="虐云建模论坛">建模论坛</a>
</div>
</div>
</body>
</html>
1.代码片段:#a.提取文本
content = selector.xpath('//ul[@id="useful"]/li/text()')
for each in content:
print ('each:',each)
-----
each: 数学建模方法
each: 数学建模数据
each: 数学建模软件
-----
2.代码片段:#b.提取属性
link = selector.xpath('//a/@href')
for href in link:
print ('href:',href)
------
href: http:nveyun.com
href: http://nveyun.com/forum.php
------
3.代码片段:#c.提取title
title = selector.xpath('//a/@title')
print ('title[0]:',title[0])
------
title[0]: 虐云建模论坛
------
4.代码片段:#c.提取多层字符
data = selector.xpath('//span[@name="data"]')[0]
#二进制数'\r\n'
info = data.xpath('string(.)')
content=info.replace('\r\n', '').replace(' ', '')
print('content:',content)
------
content: [书籍数据]数学建模书籍1:29.99数学建模书籍2:39.95
------
xpath的谓语条件(Predicate)
'''
谓"谓语条件",就是对路径表达式的附加条件。
所有的条件,都写在方括号"[]"中,表示对节点进行进一步的筛选。
'''
5.代码片段#提取book对应的数据
book=selector.xpath('//title[@lang="eng"]/text()')
print('book:',book)
------
book: ['数学建模书籍1:', '数学建模书籍2:']
------
6.代码片段:#仅提取所需的book数据
book1=selector.xpath('//book[1]/title[@lang="eng"]/text()')
print('book1:',book1)
------
book1: ['数学建模书籍1:']
------
7.代码片段:#使用last函数,其表示最后一个book子元素。[last()-1]:表示选择的倒数第二个book子元素
book_last=selector.xpath('//book[last()]/title[@lang="eng"]/text()')
print('book_last:',book_last)
------
book_last: ['数学建模书籍2:']
------
8.代码片段:#[position()<3] :表示选择前两个book子元素
book_p=selector.xpath('//book[position()<3]/title[@lang="eng"]/text()')
print('book_p:',book_p)
------
book_p: ['数学建模书籍1:', '数学建模书籍2:']
------
9.代码片段:#//title[@lang] 表示选择所有具有lang属性的title节点。
lang=selector.xpath('//title[@lang]/text()')
print('lang',lang)
------
lang ['数学建模书籍1:', '数学建模书籍2:']
------
10.代码片段:#select price>35 ,book下面的两个标签一个price一个title,如果为//span/book[price>35.00]则选择的是所有 book 元素,且其中的 price 元素的值须大于 35.00。
price_35=selector.xpath('//span/book[price>35.00]/title/text()')
print('price_35:',price_35)
------
price_35: ['数学建模书籍2:']
------
11.代码片段:#=符号要求属性完全匹配,部分匹配可以用contains,如:<div id="content" version="1.0"> 版本1.0
denghao=selector.xpath('//*[@id="content"]/text()')[0].replace('\r\n','')
print('denghao:',denghao)
contains=selector.xpath('//*[contains(@id,"content")]/text()')[0].replace('\r\n','')
print('contains:',contains)
------
denghao: 版本1.0
contains: 版本1.0
------
12.代码片段:#运算符:and 和 or 【@class='a' or @class='b'】
operators1=selector.xpath('//div[@id="content"]//*[self::ul[@id="useful"]/li or self::span]/text()')
print('operators1:',operators1)
operators2=selector.xpath('//div[@id="content"]//*[self::li or self::span]/text()')
print('operators2:',operators2)
------
operators1: ['\r\n ', '\r\n ', '\r\n ', '\r\n ', '\r\n [书籍数据]\r\n ', '\r\n ', '\r\n ']
operators2: ['数学建模方法', '数学建模数据', '数学建模软件', '不需要的信息1', '不需要的信息2', '不需要的信息3', '\r\n [书籍数据]\r\n ', '\r\n ', '\r\n ']
------
**完整源码:**
-----
#coding=utf-8
'''
python 3.6 2.7 版本在读取文件时替换格式即可
'''
from lxml import etree
html=open('TEST.txt','rb').read()
selector = etree.HTML(html)
#a.提取文本
content = selector.xpath('//ul[@id="useful"]/li/text()')
for each in content:
print ('each:',each)
#b.提取属性
link = selector.xpath('//a/@href')
for href in link:
print ('href:',href)
#c.提取title
title = selector.xpath('//a/@title')
print ('title[0]:',title[0])
data = selector.xpath('//span[@name="data"]')[0]
#二进制数'\r\n'
info = data.xpath('string(.)')
content=info.replace('\r\n', '').replace(' ', '')
print('content:',content)
#xpath的谓语条件(Predicate)
'''
谓"谓语条件",就是对路径表达式的附加条件。
所有的条件,都写在方括号"[]"中,表示对节点进行进一步的筛选。
'''
#提取book对应的数据
book=selector.xpath('//title[@lang="eng"]/text()')
print('book:',book)
#仅提取所需的book数据
book1=selector.xpath('//book[1]/title[@lang="eng"]/text()')
print('book1:',book1)
#使用last函数,其表示最后一个book子元素。[last()-1]:表示选择的倒数第二个book子元素
book_last=selector.xpath('//book[last()]/title[@lang="eng"]/text()')
print('book_last:',book_last)
#[position()<3] :表示选择前两个book子元素
book_p=selector.xpath('//book[position()<3]/title[@lang="eng"]/text()')
print('book_last:',book_p)
#//title[@lang] 表示选择所有具有lang属性的title节点。
lang=selector.xpath('//title[@lang]/text()')
print('lang',lang)
#select price>35 ,book下面的两个标签一个price一个title,如果为//span/book[price>35.00]则选择的是所有 book 元素,且其中的 price 元素的值须大于 35.00。
price_35=selector.xpath('//span/book[price>35.00]/title/text()')
print('price_35:',price_35)
#=符号要求属性完全匹配,部分匹配可以用contains,如:<div id="content" version="1.0"> 版本1.0
denghao=selector.xpath('//*[@id="content"]/text()')[0].replace('\r\n','')
print('denghao:',denghao)
contains=selector.xpath('//*[contains(@id,"content")]/text()')[0].replace('\r\n','')
print('contains:',contains)
#运算符:and 和 or 【@class='a' or @class='b'】
operators1=selector.xpath('//div[@id="content"]//*[self::ul[@id="useful"]/li or self::span]/text()')
print('operators1:',operators1)
operators1=selector.xpath('//div[@id="content"]//*[self::li or self::span]/text()')
print('operators1:',operators1)
'''
xpath运算符:http://www.w3school.com.cn/xpath/xpath_operators.asp
xpath函数:http://www.w3school.com.cn/xpath/xpath_functions.asp
'''配符
附录:通配符与多路径
# "*"表示匹配任何元素节点。
//* :选择文档中的所有元素节点。
/*/* :表示选择所有第二层的元素节点。
/bookstore/* :表示选择bookstore的所有元素子节点。
# "@*"表示匹配任何属性值。
//title[@*] :表示选择所有带有属性的title元素。
# node()表示匹配任何类型的节点。
用"|"选择多个并列的路径。
//book/title | //book/price :表示同时选择book元素的title子元素和price子元素。
lxml用法源自 lxml python 官方文档,更多内容请直接参阅官方文档,本文对其进行翻译与整理。
官方英文版(lxml说明) 安装方法: pip install lxml
案例:百度百科词条为案例:明月镇词条
明月镇对应的源码view-source: