文档章节

XPath 与 lxml

mickelfeng
 mickelfeng
发布于 2017/06/01 11:30
字数 2449
阅读 14
收藏 1

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

粉丝 229
博文 2667
码字总数 569081
作品 0
成都
高级程序员
私信 提问
python极客学习笔记

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

stone_
2016/03/29
77
0
Python检查xpath和csspath表达式是否合法

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

j_hao104
2016/11/10
43
0
Python网页解析:BeautifulSoup vs lxml.html

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

不必在乎朕是谁
2013/03/30
0
3
python中用xpath解析网页的基本方法

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

zwq912318834
2017/10/08
0
0
Python网络爬虫(Xpath解析, lxml库, selenium)

安装: Windows :安装selenium python -m pip install selenium Anaconda Prompt下执行 : conda install selenium Linux/Mac OS: sudo pip3 install selenium Ubuntu :安装Scrapy框架 ####......

巴黎香榭
11/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

颜色模型与颜色应用---RGB颜色模型

中国龙-扬科
24分钟前
3
0
网络优化-tcp和udp的协作

TODO

梦想游戏人
26分钟前
4
0
list和数组转化

Java中List转换为数组,数组转List List转换为Array可以这样处理: ArrayList<String> list=new ArrayList<String>(); String[] strings = new String[list.size()]; list.toArray(strings);......

west_coast
27分钟前
3
0
LSP 商户端API

Your domain:                  lsp-api-merchant.hhs2717.cnVirtualhost conf:             /usr/local/nginx/conf/vhost/lsp-api-merchant.hhs2717.cn.confDirectory of:......

BeanHo
36分钟前
2
0
设计模式 之 访问者模式

设计模式 之 访问者模式 概念 核心理念:将数据结构与算法分离。 使用场景:数据结构不变动,算法经常变动。 1、一个Visitor类存放被访问的对象,访问者主要处理具体算法与行为。 // 访问者...

GMarshal
40分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部