文档章节

XPath 与 lxml

mickelfeng
 mickelfeng
发布于 2017/06/01 11:30
字数 2449
阅读 7
收藏 1
点赞 0
评论 0

XPath 术语

什么是XPath

  XPath 是一门在 XML 文档中查找信息的语言,对 XPath 的理解是很多高级 XML 应用的基础,XPath 在 XML 中通过元素和属性进行导航。

什么是lxml

  lxml 是一个用来处理 XML 的第三方 Python 库,它在底层封装了用 C 语言编写的 libxml2 和 libxslt,并以简单强大的 Python API,兼容并加强了著名的 ElementTree API。

XPath术语

  在 XPath 语境中,XML 文档被视作节点树,节点树的根节点也被称作文档节点。 
  XPath 将节点树中的节点(Node)分为七类:元素(Element),属性(Attribute),文本(Text),命名空间(Namespace),处理指令(Processing-instruction),注释(Comment)和文档节点(Document nodes)。 
  请看一下 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>

  以上 XML 文档中: 

<bookstore> (这是一个“根”)
<author>J K. Rowling</author> (这是一个“元素”)
lang="en" (这是一个“属性”)

  换个视角理解它: 

- bookstore                             (我是根)
    - book                              (我是元素)
        - title                         (我是元素)
            - attributes                (我是属性)
                - lang  = en            (楼上其实是属性容器,我才是属性)
            - text = Harry Potter       (我是文本)
        - author                        (我是元素)
            - text = J K. Rowling       (我是文本)
        - year                          (我是元素)
            - text = 2005               (我是文本)
        - price                         (我是元素)
            - text = 29.99              (我是文本)

  以上就是节点树的示意图,看起来是不是很像 YAML 格式,每一行都表示一个节点,缩进表示各行之间的关系。其中无父或无子的节点被称为原子值(Atomic value)也称基本值,以上等号后面的都是原子值。节点和基本值都统称为项目(Item)。

节点之间的关系

父(Parent)

  每个元素都肯定有一个父节点,最顶层的元素父亲是根节点。同理每个属性必然有一个父,它们的父是元素。 
  上文 XML 文档中,根 bookstore 是元素 book 的父节点,book 是元素 title, author, year, price 的父节点,title 是 lang 的父节点。

子(Children)

  元素可以有零或多个子。 
  上文 XML 文档中,title, author, year, price 是 book 的子节点。

同胞(Sibling)

  父节点相同的节点之间互为同胞,也称彼此的兄弟节点。 
  上文 XML 文档中,title, author, year, price 彼此互为同胞。

先辈(Ancestor)

  某节点的父节点、父的父,以此类推一直追溯至根节点之间所有节点。 
  上文 XML 文档中,title, author, year, price 的先辈就是 book, bookstore。

后代(Descendant)

  某节点的子节点、子的子,以此类推至最后一个子节点之间所有节点。 
  上文 XML 文档中,bookstore 的后代就是 title, author, year, price 。

XPath 语法

  XPath 选取节点时使用的表达式是一种路径表达式。节点是通过路径(path)或者步(steps)来选取的。 
  本章使用以下 XML 文档作为示例。 

<?xml version="1.0" encoding="utf8"?>
<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>

选取节点

以下为基本路径的表达方式,记住 XPath 的路径表达式都是基于某个节点之上的,例如最初的当前节点一般是根节点,这与 Linux 下路径切换原理是一样的。

表达式 描述
nodename 选取已匹配节点下名为 nodename 的子元素节点
/ 如果以 / 开头,表示从根节点作为选取起点。
// 在已匹配节点后代中选取节点,不考虑目标节点的位置。
. 选取当前节点
.. 选取当前节点的父元素节点。
@ 选取属性。
>>> from lxml import etree
>>> xml = """<?xml version="1.0" encoding="utf8"?>
<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>"""


# 得到根节点
>>> root = etree.fromstring(xml)  
>>> print root
<Element bookstore at 0x2c9cc88>

# 选取所有book子元素
>>> root.xpath('book')  
[<Element book at 0x2d88878>, <Element book at 0x2d888c8>]

# 选取根节点bookstore
>>> root.xpath('/bookstore')  
[<Element bookstore at 0x2c9cc88>]

# 选取所有book子元素的title子元素
>>> root.xpath('book/title')  
[<Element title at 0x2d88878>, <Element title at 0x2d888c8>]

# 以根节点为始祖,选取其后代中的title元素
>>> root.xpath('//title')    
[<Element title at 0x2d88878>, <Element title at 0x2d888c8>]

# 以book子元素为始祖,选取后代中的price元素
>>> root.xpath('book//price')  
[<Element price at 0x2ca20a8>, <Element price at 0x2d88738>]

# 以根节点为始祖,选取其后代中的lang属性值
>>> root.xpath('//@lang')    
['eng', 'eng']

预判(Predicates)

预判是用来查找某个特定的节点或者符合某种条件的节点,预判表达式位于方括号中。

# 选取bookstore的第一个book子元素
>>> root.xpath('/bookstore/book[1]')          
[<Element book at 0x2ca20a8>]

# 选取bookstore的最后一个book子元素
>>> root.xpath('/bookstore/book[last()]')        
[<Element book at 0x2d88878>]

# 选取bookstore的倒数第二个book子元素
>>> root.xpath('/bookstore/book[last()-1]')      
[<Element book at 0x2ca20a8>]

# 选取bookstore的前两个book子元素
>>> root.xpath('/bookstore/book[position()<3]')    
[<Element book at 0x2ca20a8>, <Element book at 0x2d88878>]

# 以根节点为始祖,选取其后代中含有lang属性的title元素
>>> root.xpath('//title[@lang]')     
[<Element title at 0x2d888c8>, <Element title at 0x2d88738>]

# 以根节点为始祖,选取其后代中含有lang属性并且值为eng的title元素
>>> root.xpath("//title[@lang='eng']")    
[<Element title at 0x2d888c8>, <Element title at 0x2d88738>]

# 选取bookstore子元素book,条件是book的price子元素要大于35
>>> root.xpath("/bookstore/book[price>35.00]")    
[<Element book at 0x2ca20a8>]

# 选取bookstore子元素book的子元素title,条件是book的price子元素要大于35
>>> root.xpath("/bookstore/book[price>35.00]/title") 
[<Element title at 0x2d888c8>]

通配符

通配符 描述
* 匹配任何元素。
@* 匹配任何属性。
node() 匹配任何类型的节点。
# 选取 bookstore 所有子元素
>>> root.xpath('/bookstore/*')  
[<Element book at 0x2d888c8>, <Element book at 0x2ca20a8>]

# 选取根节点的所有后代元素
>>> root.xpath('//*')  
[<Element bookstore at 0x2c9cc88>, <Element book at 0x2d888c8>, <Element title at 0x2d88738>, <Element price at 0x2d88878>, <Element book at 0x2ca20a8>, <Element title at 0x2d88940>, <Element price at 0x2d88a08>]

# 选取根节点的所有具有属性节点的title元素
>>> root.xpath('//title[@*]')  
[<Element title at 0x2d88738>, <Element title at 0x2d88940>]

# 选取当前节点下所有节点。'\n    ' 是文本节点。
>>> root.xpath('node()')  
['\n    ', <Element book at 0x2d888c8>, '\n    ', <Element book at 0x2d88878>, '\n']

# 选取根节点所有后代节点,包括元素、属性、文本。
>>> root.xpath('//node()')  
[<Element bookstore at 0x2c9cc88>, '\n    ', <Element book at 0x2d888c8>, '\n        ', <Element title at 0x2d88738>, 'Harry Potter', '\n        ', <Element price at 0x2d88940>, '29.99', '\n    ', '\n    ', <Element book at 0x2d88878>, '\n        ', <Element title at 0x2ca20a8>, 'Learning XML', '\n        ', <Element price at 0x2d88a08>, '39.95', '\n    ', '\n']

或条件选取

使用 “|” 运算符,你可以选取符合“或”条件的若干路径。

# 选取所有book的title元素或者price元素
>>> root.xpath('//book/title|//book/price')  
[<Element title at 0x2d88738>, <Element price at 0x2d88940>, <Element title at 0x2ca20a8>, <Element price at 0x2d88a08>]

# 选择所有title或者price元素
>>> root.xpath('//title|//price')  
[<Element title at 0x2d88738>, <Element price at 0x2d88940>, <Element title at 0x2ca20a8>, <Element price at 0x2d88a08>]

# 选择book子元素title或者全部的price元素
>>> root.xpath('/bookstore/book/title|//price')  
[<Element title at 0x2d88738>, <Element price at 0x2d88940>, <Element title at 0x2ca20a8>, <Element price at 0x2d88a08>]

XPath 坐标轴

XPath 坐标轴

坐标轴用于定义当对当前节点的节点集合。

坐标轴名称 含义
ancestor 选取当前节点的所有先辈元素及根节点。
ancestor-or-self 选取当前节点的所有先辈以及当前节点本身。
attibute 选取当前节点的所有属性。
child 选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素。
descendant-or-self 选取当前节点的所有后代元素以及当前节点本身。
following 选取文档中当前节点的结束标签之后的所有节点。
following-sibling 选取当前节点之后的所有同级节点
namespace 选取当前节点的所有命名空间节点。
parent 选取当前节点的父节点。
preceding 选取当前节点的开始标签之前的所有节点。
preceding-sibling 选取当前节点之前的所有同级节点。
self 选取当前节点。

位置路径表达式

位置路径可以是绝对路径,也可以是相对路径。绝对路径以 “/” 开头。每条路径包括一个或多个步,每步之间以 “/” 分隔。

  • 绝对路径:/step/step/…
  • 相对路径:step/step/…

每步根据当前节点集合中的节点计算。

步(step)包括三部分:

  • 坐标轴(axis):定义所选节点与当前节点之间的关系。
  • 节点测试(node-test):识别某个坐标轴内部的节点。
  • 预判(predicate):提出预判条件对节点集合进行筛选。

步的语法:坐标轴::节点测试[预判]

# child::nodename 选取所有属于当前节点的 book 子元素,等价于 './nodename'
>>> root.xpath('child::book')
[<Element book at 0x2d888c8>, <Element book at 0x2d88878>]
>>> root.xpath('./book')
[<Element book at 0x2d888c8>, <Element book at 0x2d88878>]

# attribute::lang 选取当前节点的 lang 属性,等价于 './@lang'
>>> root.xpath('//*[@lang]')[0].xpath('attribute::lang')
['eng']
>>> root.xpath('//*[@lang]')[0].xpath('@lang')
['eng']

# child::* 选取当前节点的所有子元素,等价于 './*'
>>> root.xpath('child::*')
[<Element book at 0x2d88878>, <Element book at 0x2d88738>]
>>> root.xpath('./*')
[<Element book at 0x2d88878>, <Element book at 0x2d88738>]

# attribute::* 选取当前节点的所有属性,等价于 './@*'
>>> root.xpath('//*[@*]')[0].xpath('attribute::*')
['eng']
>>> root.xpath('//*[@*]')[0].xpath('@*')
['eng']

# child::text() 选取当前节点的所有文本子节点,等价于 './text()'
>>> root.xpath('child::text()')
['\n    ', '\n    ', '\n']
>>> root.xpath('./text()')
['\n    ', '\n    ', '\n']

# child::node() 选取当前节点所有子节点,等价于 './node()'
>>> root.xpath('child::node()')
['\n    ', <Element book at 0x2d88878>, '\n    ', <Element book at 0x2d88738>, '\n']
>>> root.xpath('./node()')
['\n    ', <Element book at 0x2d88878>, '\n    ', <Element book at 0x2d88738>, '\n']

# descendant::book 选取当前节点所有 book 后代,等价于 './/book'
>>> root.xpath('descendant::book')
[<Element book at 0x2d88878>, <Element book at 0x2d88738>]
>>> root.xpath('.//book')
[<Element book at 0x2d88878>, <Element book at 0x2d88738>]

# ancestor::book 选取当前节点所有 book 先辈
>>> root.xpath('.//title')[0].xpath('ancestor::book')
[<Element book at 0x2d88878>]

# ancestor-or-self::book 选取当前节点的所有 book 先辈以及如果当前节点是 book 的话也要选取
>>> root.xpath('.//title')[0].xpath('ancestor-or-self::book')
[<Element book at 0x2d88878>]
>>> root.xpath('.//book')[0].xpath('ancestor-or-self::book')
[<Element book at 0x2d88878>]
>>> root.xpath('.//book')[0].xpath('ancestor::book')
[]

# child::*/child::price 选取当前节点的所有 price 孙节点,等价于 './*/price'
>>> root.xpath('child::*/child::price')
[<Element price at 0x2d88878>, <Element price at 0x2d88738>]
>>> root.xpath('./*/price')
[<Element price at 0x2d88878>, <Element price at 0x2d88738>]

本文转载自:http://blog.csdn.net/dengzhilong_cpp/article/details/51828672

共有 人打赏支持
mickelfeng

mickelfeng

粉丝 226
博文 964
码字总数 548988
作品 0
成都
高级程序员
python极客学习笔记

正则 import res = '12abc33arr' print re.match(r'2.', s) 从字符开头匹配,匹配不到返回None print re.search(r'2.', s) 匹配到内容就取消接下来的字符匹配,到字符结束没匹配到就返回Non...

stone_ ⋅ 2016/03/29 ⋅ 0

Python网页解析:BeautifulSoup vs lxml.html

Python里常用的网页解析库有BeautifulSoup和lxml.html,其中前者可能更知名一点吧,熊猫开始也是使用的BeautifulSoup,但是发现它实在有几个问题绕不过去,因此最后采用的还是lxml: 1. Bea...

不必在乎朕是谁 ⋅ 2013/03/30 ⋅ 3

Python检查xpath和csspath表达式是否合法

在做一个可视化配置爬虫项目时,需要配置爬虫的用户自己输入xpath和csspath路径以提取数据或做浏览器操作。考虑到用户的有时会输入错误的xpath或csspath路径,后台需要对其做合法性校验。 xp...

j_hao104 ⋅ 2016/11/10 ⋅ 0

python中用xpath解析网页的基本方法

1. 背景 目前爬虫解析网页的技术有:Json, 正则表达式,BeautifulSoup,PyQuery,XPath XPath 教程 官方文档: 2. XPath简述 2.1. 什么是XPath? XPath (XML Path Language) 是一门在 XML 文...

zwq912318834 ⋅ 2017/10/08 ⋅ 0

requests+lxml爬虫利器

requests 1.requests是一个强大的Python第三方Http库,基于httplib和urllib3,接口清晰易用,功能十分强大。 ###1. 安装 pip install requests或者easy_install requests ###2. 基本使用 在i...

曾劲松 ⋅ 2016/10/04 ⋅ 0

Xpath模拟登陆GitHub

PTYHON 爬虫 这是我用python2.7写的简单教程 准备工作 安装requests lxml模块 pip install requests pip install lxml requests文档 lxml文档 Xpath教程 实战应用 首先进入GitHub登陆页面htt...

Treehl ⋅ 2017/10/20 ⋅ 0

用23行代码爬取豆瓣音乐top250

学习.png 网上有各种爬取豆瓣电影top250的教程,虽然豆瓣音乐top250和豆瓣电影top250的爬取十分类似,但是我大致对比了一下,我这种方法应该是最简单的,仅需要23行代码。 豆瓣对于爬虫十分友...

爱吃西瓜的番茄酱 ⋅ 2017/12/19 ⋅ 0

python网络爬虫系列教程——python中lxml库应用全解(xpath表达式)

全栈工程师开发手册 (作者:栾鹏) python教程全解 python网络爬虫lxml库的应用全解。 在线安装方法:cmd中输入”pip install lxml” 离线安装,下载lxml库点击下载 python库的安装请参考P...

luanpeng825485697 ⋅ 2017/11/01 ⋅ 0

Python 第三方库

http://www.lfd.uci.edu/~gohlke/pythonlibs/ Python第三库下载地址。 下载完成后解压缩,把相应放在python的Lib文件夹下。 如想使用xpath操作,则需要安装lxml库 在命令提示符下 通过 pip ...

HouZhong ⋅ 2016/02/28 ⋅ 0

Python爬虫(十二)_XPath与lxml类库

Python学习指南 有同学说,我正则用的不好,处理HTML文档很累,有没有其他的方法? 有!那就是XPath,我们可以用先将HTML文档转换成XML文档,然后用XPath查找HTML节点或元素。 什么是XML XML...

小七奇奇 ⋅ 2017/12/03 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

解决yum安装报错Protected multilib versions

使用yum安装报错Protected multilib versions原因是因为多个库不能共存,不过更新的话也并不行,但是可以在安装命令后面加上如下一段命令: --setopt=protected_multilib=false 案例: 比如需...

北岩 ⋅ 33分钟前 ⋅ 0

为什么要学习Typescript???

简单来说 目前的typescript就是未来的javascript 为什么?? 这要从ECMA-262标准的第4版说起 对了 我们说的ES5 其实是ECMAScript3.1这个替代性建议被扶正了而已... 那么 第4版标准是什么? 看看...

hang1989 ⋅ 38分钟前 ⋅ 0

linux安装ipfs

一、下载ipfs # cd /usr/local/ipfs/ # wget https://dist.ipfs.io/go-ipfs/v0.4.15/go-ipfs_v0.4.15_linux-amd64.tar.gz # tar -zxvf go-ipfs_v0.4.15_linux-amd64.tar.gz 二、安装ipfs # ......

八戒八戒八戒 ⋅ 43分钟前 ⋅ 0

jvm程序执行慢诊断手册

生产环境最多的几种事故之一就是程序执行慢,如果是web服务的话,表现就是响应时间长。本文分享,从业多年形成的排查守则。 诊断步骤 系统资源查看 首先是系统资源查看,而且必须是在第一步。...

xpbob ⋅ 44分钟前 ⋅ 0

YII2 advanced 高级版本项目搭建-添加API应用以及多应用

一、YII安裝 安裝yii可以用composer安裝,也可以在yii中文社区下载归档文件安装 composer安装就不介绍了,因为要安装composer,比较麻烦,当然安装了composer是最好的,以后安装yii的插件要用...

botkenni ⋅ 45分钟前 ⋅ 0

在jdk1.8的环境下模拟永久代内存溢出

相信不少小伙伴在看深入理解Java虚拟机的时候,作者给我们举例一个demo来发生PermGen space 1、通过List不断添加String.intern(); 2、通过设置对应的-XX:PermSize与-XX:MaxPermSize(更快看到...

虾几把写 ⋅ 今天 ⋅ 0

开发OpenDaylight组件的完整流程

在前面介绍学习了OpenDaylight的几个重要模块后,这里再来介绍下完整开发一个模块的过程。 OSGI的bundles提供被其他OSGI组件调用的服务。这个教程中展示的是Data Packet Service去解析数据包...

wangxuwei ⋅ 今天 ⋅ 0

Java序列化和反序列化

1、什么是序列化和反序列化 序列化:把对象转换为字节序列的过程。 反序列化:把字节序列恢复成对象的过程。 2、被序列化的类需要实现serializable接口,只是为了标注该对象是可以被序列化的...

IT-Mamba ⋅ 今天 ⋅ 0

流式构建原理

流式构建需要达到分钟级的数据更新频率,Kylin采用类似于Spark Streaming的做法,每隔数分钟进行一次微构建。这边的构建需要考虑到一个延迟因素,分布式网络存在延迟等因素,该时间段的数据有...

无精疯 ⋅ 今天 ⋅ 0

在maven项目工程编写solr代码,需要的依赖

solrJ <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> <version>6.6.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents<......

爱运动的小乌龟 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部