xpath

xpath全称XML Path language, 即xml路径语言,最初用来搜寻xml文档的,同样适用于html文档的搜寻

常用规则:

 nodename 选取此节点的所有子节点
/ 从当前节点选取直接子节点
// 从当前节点选取子孙节点
. 选取当前节点
.. 选取当前借点的父节点
@ 选取属性
from lxml import etree
text = '''
<dd>
                        <i class="board-index board-index-1">1</i>
    <a href="/films/1203" title="霸王别姬" class="image-link" data-act="boarditem-click" data-val="{movieId:1203}">
      <img src="//ms0.meituan.net/mywww/image/loading_2.e3d934bf.png" alt="" class="poster-default" />
      <img data-src="http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c" alt="霸王别姬" class="board-img" />
    </a>
    <div class="board-item-main">
      <div class="board-item-content">
              <div class="movie-item-info">
        <p class="name"><a href="/films/1203" title="霸王别姬" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
        <p class="star">
                主演:张国荣,张丰毅,巩俐
        </p>
<p class="releasetime">上映时间:1993-01-01(中国香港)</p>    </div>
    <div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">6</i></p>
    </div>

      </div>
    </div>
'''
html = etree.HTML(text)
result = etree.tostring(html)
print(result.decode('utf-8'))

这里首先导入lxml库的etree模块,然后声明了一段html文本,使用html类进行初始化,这样就成功的构造了一个xpath解析对象,需要注意的是,html文本中最后一个节点dd是没有闭合的,但是etree模块自动修正了html文本

调用tostring()方法即可输出修正后的html代码

也可以直接读取文本文件进行解析

html = etree.aprse('./xpath.html',etree.HTMLParser())
result = etree.tostring(html)
print(result.decode('utf-8'))

这次得输出结果略有不同,多了一个DOCTYPE的声明,但是对解析结果没有任何影响

所有节点

我们一般使用//开头的xpath规则来选取所有符合要求的节点

html = etree.parse('./xpath.html',etree.HTMLParser())
result = html.xpath('//*')
print(result)

使用*号来匹配所有节点,也就是整个html文本中的所有节点都会被获取,返回形式是一个列表,每个元素是Element类型的,其后跟了节点的名称,如html,div,ul等

选取所有的a节点,可以使用//,后面加上节点名称就行

html = etree.parse('./xpath.html',etree.HTMLParser())
result = html.xpath('//a')
print(result)
#[<Element a at 0x108f47448>, <Element a at 0x108f47488>]

print(result[0])
#<Element a at 0x108721488>

可容易看到结果是一个列表形式,每一个元素都是一个Element对象,如果要提取其中一个对象可以直接中括号加索引

属性匹配

//li[@class='item']  #获取所有class为item的li节点

属性获取

我们知道text()获取节点内部文本,那么节点属性该怎样获取呢,其实还是用@符号就可以了

//li/a/@href  #查找所有的li节点的直接子节点的href属性值

属性多值匹配

有些时候某些节点的属性可能有多个值

<li class="li li-first" name="item"><a href="link.html">first</a></li>

这里的li节点的class 属性就有两个值li和li-first,如果还用之前的属性匹配获取,就无法匹配了

需要使用contains()函数

//li[contains(@class,'li')]/a/text()

通过contains()方法,第一个参数传入属性名称,第二个参数传入属性值,只要此属性中包含传入的属性值,就可以完成匹配

多属性匹配

还会遇到一种情况,就是根据多个属性确定一个节点,这时就需要匹配多个属性,使用运算符and来连接

//li[contains(@class,"li") and @name="item"]/a/text()

这里的and其实是xpath中的运算符,还有如下

or
and
mod 取余
| 返回拥有两边元素节点集
+  
-  
*  
div 除法
=  

!=

 
<  
<=  
>  
>=  

按序选择

有时候我们选择属性时,匹配到了多个节点,但是我们只想要其中的某个节点,

//li[1]/a/text() #选取第一个节点,中括号传入1即可,序号是以1开头的

//li[last()]/a/text() #选取最后一个节点

//li[position()<3]/a/text #选取序号小于3的,也就是选择1,2

//li[last()-2]/a/text() #选择倒数第三个节点,因为last()是最后一个,所以last()-2是倒数第三个

节点轴选择

//li[1]/ancestor::*  #获取所有祖先节点

//li[1]/ancestor::div  #获取指定祖先节点div

//li[1]/attribute::*  #获取节点的所有属性

//li[1]/child::a[@href="like.html"] #获取所有直接子节点,条件:href属性为like.html的a节点

//li[1]/descendant::span  #获取所有子孙节点:条件:返回只包含span节点

//li[1]/following::*[2]    #当前节点之后的所有节点,但加了索引匹配,只选择第二个后续节点

//li[1]following-sibling::*  #返回节点之后的同级节点
原文地址:https://www.cnblogs.com/sunlizhao/p/9163534.html