• XPath使用


    XPath

    一,简介

      全称XMl Path Language,是一种在XML中寻找信息的语言,同样适用于HTML文档搜索。XPath功能十分强大,提供了非常简洁明了的路径选择表达式。拥有超过100个内建函数,用于字符串,数字,时间以及节点的匹配,序列的处理等。几乎所有想要定位的节点都可以用XPath来选择。

    二,使用

    1.常用规则

      nodename :选取此节点的所有子节点

      /      :从当前节点选取直接子节点

      //     :从当前节点选取子孙节点

      .      :选取当前节点

      ..     :选取当前节点的父节点

      @      :选取属性

      

      示例://title[@lang='eng'],代表锁选择的名称为title,同时属性;lang的值为eng的节点。

    2,安装lxml

      windows:pip3 install lxml

    3,使用示例
    from lxml import etree
    
    text = """
    <div>
        <ul>
            <li class="item-0"><a href="link1.html">first item</a></li>
            <li class="item-1"><a href="link2.html">second item</a></li>
            <li class="item-active"><a href="link3.html">third item</a></li>
            <li class="item-4"><a href="link4.html">fourth item</a></li>
            <li class="item-5"><a href="link5.html">fifth item</a>
        </ul>
    </div>
    """
    html = etree.HTML(text)
    res = etree.tostring(html)
    print(res.decode('utf-8'))

      首先到如etree模块,声明一段HTML文本,调用HTML类进行初始化,这样就成功构造了一个Xpath解析对象,text中最后一个li节点时没有闭合的,但是etree可以自动修正HTML文本。调用tostring输出修正后的文本,在decode转成str。

    <html><body><div>
        <ul>
            <li class="item-0"><a href="link1.html">first item</a></li>
            <li class="item-1"><a href="link2.html">second item</a></li>
            <li class="item-active"><a href="link3.html">third item</a></li>
            <li class="item-4"><a href="link4.html">fourth item</a></li>
            <li class="item-5"><a href="link5.html">fifth item</a>
        </li></ul>
    </div>
    </body></html>

      经过处理,li节点被不全,并自动添加了,body,html节点。另外,可以直接读取文本文件进行解析:

    html = etree.parse('./text.html', etree.HTMLParser())
    print(etree.tostring(html).decode('utf-8'))
     4.选取所有节点

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

    # 选取所有节点
    html = etree.parse('./text.html', etree.HTMLParser())
    res = html.xpath('//*')
    print(res)

      运行结果:

    [<Element html at 0x117994842c8>, <Element head at 0x117994843c8>, <Element meta at 0x11799484408>, 
    <Element title at 0x11799484448>, <Element body at 0x11799484488>, <Element div at 0x11799484508>,
    <Element ul at 0x11799484548>, <Element li at 0x11799484588>, <Element a at 0x117994845c8>,
    <Element li at 0x117994844c8>, <Element a at 0x11799484608>, <Element li at 0x11799484648>,
    <Element a at 0x11799484688>, <Element li at 0x117994846c8>, <Element a at 0x11799484708>,
    <Element li at 0x11799484748>, <Element a at 0x11799484788>]

      这里*代表所有节点,返回的是一个列表,每个元素都是element类型,其后跟了节点的名称,如html,body,title,ul,li等等,所有的节点都包含在其中。当日也可以获取指定节点:

    res = html.xpath('//li')
    print(res)
    print(res[0])

      运行结果:

    [<Element li at 0x22855a593c8>, <Element li at 0x22855a59408>,<Element li at 0x22855a59448>, 
    <Element li at 0x22855a59488>, <Element li at 0x22855a594c8>]
    <Element li at 0x22855a593c8>

      想要取出其中的某一个对象,直接使用索引。

    6.选取子节点

      通过/或//可以查找元素的子节点或者子孙节点。查找li节点的所有直接a节点

    # 选取子节点
    res = html.xpath('//li/a')
    print(res)

      运行结果:

     [<Element a at 0x27107af43c8>, <Element a at 0x27107af4408>, 
    <Element a at 0x27107af4448>, <Element a at 0x27107af4488>, <Element a at 0x27107af44c8>]

      这里通过追加/a选择所有li节点下面的直接子节点a。//li用于选取所有的li节点,/a用于选中li节点中所有直接子节点a。想要获取所有子孙节点可以使用//,获取ul节点下的所有孙子a节点:  

    res = html.xpath('//ul//a')
    print(res)

      运行结果:

    [<Element a at 0x1a88f8c43c8>, <Element a at 0x1a88f8c4408>, <Element a at 0x1a88f8c4448>, 
    <Element a at 0x1a88f8c4488>, <Element a at 0x1a88f8c44c8>]

      与上面的例子运行结果是相同的。但是这里如果使用//ul/a,就无法获取任何结果了,ul节点下面没有直接子节点a。

    7.属性选择

      在选取的时候,我们还可以使用@符号进行属性过滤。选取class值为item-0的li节点:

    # 属性选择
    res = html.xpath('//li[@class="item-0"]')
    print(res)

      运行结果:

    [<Element li at 0x178e69653c8>]
    8.父节点

      选取href属性为link4.html的a节点的父节点,再获取其class的属性,使用..选择父节点:

    res = html.xpath('//a[@href="link4.html"]/../@class')
    print(res)

      运行结果:

    ['item-4']
    9.文本获取

      我们可以使用XPath中的text()方法进行文本获取,尝试获取li节点中的文本:

    # 文本获取,选取li节点所有子孙节点的文本
    res = html.xpath('//li[@class="item-5"]//text()')
    print(res)

      运行结果:

    ['fifth item']
    # 文本获取,先选取直接子节点a,再获取其文本res = html.xpath('//li[@class="item-5"]/a/text()')
    print(res)

      运行结果:

    ['fifth item']
     10.属性多值匹配

      某些时候,某个节点的属性可能存在多个值,例如:

    from lxml import etree
    
    text = "<li class='li li-first'><a href='link.html'>first li</a></li>"
    html = etree.HTML(text)
    res = html.xpath('//li[@class="li"]/a/text()')
    print(res)

    运行结果:
    []

      这里的li节点的属性存在li,li-first两个值,使用之前的获取方法是无法获取的。此时就需要使用contains()函数了,:

    res = html.xpath('//li[contains(@class,"li")]/a/text()')
    print(res)
    
    运行结果:
    ['first li']

      通过contains()方法,第一个参数传入属性名称,第二个参数传入属性值,只要此属性包含所传入的属性值,就能完成匹配了。可以在某个节点的某个属性存在多个值的时候使用。

    11.多属性匹配

      根据多个属性来确定一个节点,需要同时匹配多个属性:

    text = "<li class='li li-first' name='item'><a href='link.html'>first li</a></li>"
    html = etree.HTML(text)
    res = html.xpath('//li[contains(@class,"li") and @name="item"]/a/text()')
    print(res)

    运行结果:
    ['first li']

      li节点里面又增加了一个name属性,且li节点的class属性存在多个值。此时需要同时使用class和name属性进行选择,一个条件时class里面包含li字符串,另一个条件是name的属性值为item,二者需要同时满足,使用and操作符相连,之后再置于中括号内进行条件筛选。

       xpath运算符介绍

      or:或。          例:age=19 or age=20,如果age是19或20,则返回True,否则返回False

      and:与。          例:age>19 and age<21,同时满足and前后条件则返回True,否则False

      mod:计算除法的余数。   例:5 mod 2 , 1

      |  :计算两个节点集。     例://bock | //cd ,返回所有用于bock和cd元素的节点集

      +:    加。        例:6 + 2,  8

      -:  减。        例:6 - 2,   4

      *:  乘。        例:6 * 2,  12

      div:   除。        例:6 div 2,  3

      =:  等于

      !=: 不等于

      <:  小于

      <=:  小于等于

      >:    大于

      >=:   大于等于

    12.按序选择

      有时候,我们在选择节点时同时匹配了多个节点,但是只想要其中的某个节点,或者第二个节点,这时候该怎么办呢?

    from lxml import etree
    
    text = """
    <div>
        <ul>
            <li class="item-0"><a href="link1.html">first item</a></li>
            <li class="item-1"><a href="link2.html">second item</a></li>
            <li class="item-active"><a href="link3.html">third item</a></li>
            <li class="item-4"><a href="link4.html">fourth item</a></li>
            <li class="item-5"><a href="link5.html">fifth item</a>
        </ul>
    </div>
    """
    # 按序选择
    html = etree.HTML(text)
    res = html.xpath('//li[1]/a/text()')
    print(res)
    res2 = html.xpath('//li[last()]/a/text()')
    print(res2)
    res3 = html.xpath('//li[position()<3]/a/text()')
    print(res3)
    res4 = html.xpath('//li[last()-2]/a/text()')
    print(res4)

      运行结果:

    ['first item']
    ['fifth item']
    ['first item', 'second item']
    ['third item']

      第一次选择,选取第一个li节点,在括号中传入数字1。这里与索引不同,序号是以1开始的。

      第二次选择,选取最后一个li节点,使用last()即可。

      第三次选择,选取位置小于3的li节点,也就是位置序号为1和2的li节点。

      第四次选择,选取倒数第三个li节点,在括号中传入last()-2即可,因为last()为最后一个,那么last()-2则为倒数第三个。

    13.节点轴选择

      XPath提供了很多节点轴的选择方法,包括子元素,兄弟元素,父元素,祖先元素等,:

    from lxml import etree
    
    text = """
    <div>
        <ul>
            <li class="item-0"><a href="link1.html"><span>first item</span></a></li>
            <li class="item-1"><a href="link2.html">second item</a></li>
            <li class="item-active"><a href="link3.html">third item</a></li>
            <li class="item-4"><a href="link4.html">fourth item</a></li>
            <li class="item-5"><a href="link5.html">fifth item</a>
        </ul>
    </div>
    """
    # 节点轴选择
    html = etree.HTML(text)
    res = html.xpath('//li[1]/ancestor::*')
    print(res)
    res2 = html.xpath('//li[1]/ancestor::div')
    print(res2)
    res3 = html.xpath('//li[1]/attribute::*')
    print(res3)
    res4 = html.xpath('//li[1]/child::a[@href="link1.html"]')
    print(res4)
    res5 = html.xpath('//li[1]/descendant::span')
    print(res5)
    res6 = html.xpath('//li[1]/following::*[2]')
    print(res6)
    res7 = html.xpath('//li[1]/following-sibling::*')
    print(res7)

      运行结果:

    [<Element html at 0x165f62363c8>, <Element body at 0x165f6236348>, <Element div at 0x165f6236308>, <Element ul at 0x165f6236408>]
    [<Element div at 0x165f6236308>]
    ['item-0']
    [<Element a at 0x165f62364c8>]
    [<Element span at 0x165f6236548>]
    [<Element a at 0x165f6236588>]
    [<Element li at 0x165f6236648>, <Element li at 0x165f6236688>, <Element li at 0x165f62366c8>, <Element li at 0x165f6236708>]

      第一次选择,调用ancestor轴可以获取所有祖先节点。其后跟两个冒号,然后是节点的选择器,这里直接使用*表示匹配所有节点,返回的是第一个li节点的所有祖先节点,包括body,html,div和ul。

      第二次选择,我们在后面加上了限制条件,只选择div。

      第三次选择,调用attribute轴,可以获取所有节点的属性。加上*,返回的是li节点的所有属性值。

      第四次选择,调用child轴,可以获取所有子孙节点。加上先限制条件,选取href值为link1.html的a节点。

      第五次选择,调用descendant轴,可以获取所有子孙节点。这里我们又加上了限制span节点,返回结果只包含span节点而不包含a节点。

      第六次选择,调用following轴,获取当前节点之后的所有节点。这里虽然使用了*匹配所有,但又加上了索引,返回的只有第二个后续节点。

      第七次选择,调用following-sibling轴,获取当前节点之后所有的同级节点。使用*获取后续所有的同级节点。

    三,总结

      到此为止,我们基本上把XPath可能用到的选择器介绍完了。是不是觉得,哇!!!XPath好强大!内置函数非常多,熟练之后可以大大提升HTML信息提取效率。

  • 相关阅读:
    Mysql:read-only 配置
    Mysql:我自己总也记不住的【选项语法规则】: Command-Line-Options、Configure-Options、System-Variables、Status-Variables
    Mysql:Delayed Replication:延迟复制
    Mysql:Semi-Synchronous Replication:大名鼎鼎的 【半同步】复制
    Mysql:Replication
    Mysql:Group Replication:实战:注意事项
    Mysql:Group Replication
    端口映射工具En化版:PortMap_Gold_Edition_Premium_3.4:可以绑定特定的网卡NIC
    Mysql:SQL Modes:最令我烦的sql-modes:一个标准它不香么?!
    Mysql:Alternative Storage Engines:可替换存储引擎:mysqld的核心特性
  • 原文地址:https://www.cnblogs.com/zivli/p/10887268.html
Copyright © 2020-2023  润新知