python Xpath语法的使用
一、XMl简介
(一)什么是XML
XML指可扩展标记语言(EXtensible)
XML是一种标记语言,很类似HTML。
XML的设计宗旨是传输数据,而非显示数据。
XML的标签需要我们自行定义。
XML被设计为具有自我描述性。
XML是W3C的推荐标准。
W3School官方文档:http://www.w3school.com.cn/xml/index.asp
(二)XML和HTML的区别
他们两者都是用于操作数据或者结构数据,在结构上大致相同的,但他们在本质上却存在着明显的区别。
数据格式 | 描述 | 设计目标 |
---|---|---|
XML | ExtensibleMarkupLanguage(可扩展标记语言) | 被设计为传输和存储数据,其焦点是数据的内容。 |
HTML | HyperTextMarkupLanguage(超文本标记语言) | 显示数据以及如何更好显示数据。 |
HTMLDOM | DocumentObjectModelforHTML(超文本标文档对象模型) | 通过HTMLDOM,可以访问所有的HTML元素,连同它们所包含的文本和属性。可以对其中的内容进行修改和删除,同时也可以创建新的元素。 |
(三)XML的节点关系
HarryPotter JK.Rowling 2005 29.00
1.父(Parent)
每个元素以及属性都有一个父。上面是一个简单的XML例子中,book元素是title、author、year以及price元素的父
2.子(Children)
元素节点可有零个、一个或多个子元素。在上面的例子中,title、author、year以及price元素都是book元素的子元素
3.同胞(Sibling)
拥有相同的父的节点。在上面的例子中,title、author、year以及price元素都是同胞
4.先辈(Ancestor)
某节点的父、父的父,等等。在上面的例子中,title元素的先辈是book元素和bookstore元素
5.后代(Descendant)
某个节点的子,子的子等等。在上面的例子中,bookstore的后代是book、title、author、year以及price元素:
二、XPATH
XPath(XMLPathLanguage)是一门在XML文档中查找信息的语言,可用来在XML文档中对元素和属性进行遍历。
(一)选取节点
XPath使用路径表达式来选取XML文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。下面列出了最常用的路径表达式:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑他们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
路径表达式 | 描述 |
---|---|
bookstore | 选取bookstore元素的所有子节点 |
/bookstore | 选取根元素bookstore。代表元素的绝对路径。 |
bookstore/book | 选取属于bookstore的子元素的所有book元素。 |
//book | 选取所有book子元素,而不管它们在文档中的位置 |
bookstore//book | 选择属于booksore元素的后代所有的book元素,而不管他们位于bookstore之下的什么位置。 |
//@lang | 选取名为lang的所有属性。 |
text() | 取标签当中的值 |
(二)谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式 | 描述 |
---|---|
/bookstore/book[l] | 选取属于bookstore子元素的第一个book元素。 |
/bookstore/book[last()] | 选取属于bookstore子元素的最后一个book元素。 |
/bookstore/book[last()-1] | 选取属于bookstore子元素的倒数第二个book元素。 |
/bookstore/book[position()<2] | 选最前面的一个属于bookstore元素的子元素的book元素。 |
//title[@lang] | 选取所有属性名为lang的属性的title元素。 |
//titlel@lang=‘eng'] | 选取所有tltle元素,且这些元素有属性值为eng的lang属性。 |
(三)选取未知节点
XPath通配符可用来选取未知的XML元素。
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 描述 |
---|---|
/bookstore/* | 选取bookstore元素的所有子元素 |
//* | 选取文档中的所有元素。 |
//title[@*] | 选取所有带有属性的title元素。 |
(四)选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 描述 |
---|---|
//book/title | //book/price |
//title | //price |
//price | 选取文档中所有的price元素。 |
三、lxml模块
(一)lxml简介与安装
lxml是一个HTML/XML的解析器,主要的功能是如何解析和提取HTML/XML数据。我们可以利用之前学习的XPath语法,来快速的定位特定元素以及节点信息。
安装方法:pipinstalllxml
(二)lxml初步使用
1、解析HTML字符串
fromlxmlimportetree text="""""" html=etree.HTML(text) result=etree.tostring(html,pretty_print=True).decode('utf-8') print(result) fromlxmlimportetree text="""
firstitem seconditem thirditem fourthitem fifthitem """ #初始化一个Xpath解析对象 html=etree.HTML(text) #解析对象输出代码是一个bytes类型 result=etree.tostring(html,encoding='utf-8') print(type(html))#
firstitem seconditem thirditem> fourthitem fifthitem print(type(result))# print(result.decode('utf-8'))
小结:lxml可以自动修正html代码,例子里不仅补全了li标签,还添加了body,html标签。
2.、lxml文件读取
fromlxmlimportetree text="""""" #初始化一个Xpath解析对象 html=etree.HTML(text) #解析对象输出代码是一个bytes类型 result=etree.tostring(html,encoding='utf-8') print(type(html))#
firstitem seconditem thirditem> fourthitem fifthitem print(type(result))# print(result.decode('utf-8'))
除了直接读取字符串,lxml还支持从文件里读取内容。我们新建一个hello.html文件,再利用etree.parse()方法来读取文件。
注意:从文件中读取数据,要求文件内容符合xml格式,如果标签缺失,则不能正常读取。
四、XPath节点信息解析:
#安装lxml:pipinstalllxml #1.导入etree:两种导入方式 #第一种:直接导入 fromlxmlimportetree #注意:此种导入方式,可能会导致报错(etree下面会出现红色波浪线,不影响正常使用) #第二种: #fromlxmlimporthtml #etree=html.etree str=''\ ' ' #2.etree.HTML()将字符串转换成HTML元素对象,可以自动添加缺失的元素 html=etree.HTML(str)#'\ ' '\ 'HarryPotter'\ ' 29.99 '\ ''\ ' '\ 'LearningXML'\ ' 39.95 '\ ''\ ' '\ '西游记'\ ' 69.95 '\ ''\ ' '\ '水浒传'\ ' 29.95 '\ ''\ ' '\ '三国演义'\ ' 29.95 '\ '是一个el对象 #print(html) #3.方法: #3.1tostring()查看转换之后的内容(二进制类型) #如果想要查看字符串,需要解码 #如果想要显示汉字,需要先编码,再解码 #content=etree.tostring(html,encoding='utf-8') #print(content.decode()) #3.2xpath()方法作用:提取页面数据,返回值是一个列表 #xpath的使用一定是建立在etree.HTML()之后的内容中的 #xpath是如何来提取页面数据的? #答:使用的是路径表达式 #3.2.1xpath路径分为两种: #第一种:/代表一层层的查找,如果/存在于开头,代表根路径 #bookstore=html.xpath('/html/body/bookstore') #print(bookstore)#[ ] #第二种://任意路径焦点在元素身上 #例如:查找bookstore标签 #bookstore=html.xpath('//bookstore') #print(bookstore)#[ ] #第一种和第二种结合 #例如:查找所有book标签 #book=html.xpath('//bookstore/book') #print(book)#[ , , , , ] #3.2.2/text()获取标签之间的内容 #例如:获取所有title标签的内容 #步骤: #1.找到所有title标签 #2.获取内容 #title=html.xpath('//book/title/text()') #print(title)#['HarryPotter','LearningXML','西游记','水浒传','三国演义'] #3.3位于使用[]可以理解成条件 #3.3.1[n]代表获取第n个元素,n是数字,n<=1 #例如:获取第二个title标签 #title=html.xpath('//book[2]/title/text()') #title1=html.xpath('//title[2]/text()') #print(title)#['LearningXML'] #print(title1)#[] #last()获取最后一个 #同理:last()-1获取倒数第二个 #例如:获取最后一本书的title标签之间的内容 #title=html.xpath('//book[last()]/title/text()') #title1=html.xpath('//book[last()-1]/title/text()') #print(title)#['三国演义'] #print(title1)#['水浒传'] #3.3.2position()位置,范围支持>/=/>=/<=/!= #例如:获取最后两本书的title标签之间的内容 #步骤: #1.先获取后两本书 #2.获取内容 #title=html.xpath('//book[position()>3]/title/text()') #print(title)#['水浒传','三国演义'] #?title=html.xpath('//book[position()>last()-2]/title/text()') #print(title)#['水浒传','三国演义'] #3.3.3获取属性值:@属性名 #例如:获取lang属性值为cng的title标签的内容 #title=html.xpath('//book/title[@lang="cng"]/text()') #print(title)#['西游记'] #例如:获取包含src属性得title标签的内容 #title=html.xpath('//book/title[@src]/text()') #print(title)#['HarryPotter','水浒传','三国演义'] #例如:获取包含属性的title标签的内容 #title=html.xpath('//book/title[@*]/text()') #print(title)#['HarryPotter','LearningXML','西游记','水浒传','三国演义'] #例如:获取最后一个title标签的src属性的值 #title=html.xpath('//book[last()]/title/@src') #print(title)#['https://www.jd.com'] #例如:获取所有包含src属性的标签之间的内容 #node=html.xpath('//*[@src]/text()') #print(node)#['HarryPotter','水浒传','三国演义'] #3.4and与连接的是谓语(条件) #例如:获取lang="dng"并且class="t1"的title标签的内容 #title=html.xpath('//book/title[@lang="dng"and@class="t1"]/text()') #title1=html.xpath('//book/title[@lang="dng"][@class="t1"]/text()') #print(title)#['三国演义'] #print(title1)#['三国演义'] #3.5or或连接谓语 #例如:查找lang="cng"或者lang="bng"的title标签的内容 #title=html.xpath('//book/title[@lang="cng"or@lang="bng"]/text()') #print(title)#['HarryPotter','西游记'] #3.6|连接路径 #例如:获取所有title标签和price标签之间的内容 #title=html.xpath('//title/text()|//price/text()') #print(title)#['HarryPotter','29.99','LearningXML','39.95','西游记','69.95','水浒传','29.95','三国演义','29.95'] #3.8parse()作用:从文件中读取数据 #注意:读取的文件,必须满足xml格式**(不存在单标签,全部都是上标签)** content=etree.parse('test.html') #print(content)# res=etree.tostring(content,encoding='utf-8') print(res.decode()) test 这是一个html