• 爬虫


    定义

    XPath,全称 XML Path Language,即 XML 路径语言,它是一门在XML文档中查找信息的语言,是一个文档解析库。XPath 最初设计是用来搜寻XML文档的,但是它同样适用于 HTML 文档的搜索。
    所以在做爬虫时,可以使用 XPath 来做相应的信息抽取,定位节点。XPath有特定的语法、函数、运算符去定位节点、获取节点信息

    常用规则

    表达式 描述
    nodename 选取此节点的所有子节点
    / 从当前节点选取直接子节点
    // 从当前节点选取子孙节点
    . 选取当前节点
    .. 选取当前节点的父节点
    @ 选取属性

    1. lxml的etree模块可以对HTML文档进行自动修正

    直接解析文本

    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-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a>
         </ul>
     </div>
    '''
    html = etree.HTML(text)
    result = etree.tostring(html)
    print(result.decode('utf-8'))
    

    读取文件,再解析

    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = etree.tostring(html)
    print(result.decode('utf-8'))
    

    test.html

    <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-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a>
         </ul>
     </div>
    

    2. 选取所有节点

    选取所有节点:XPath语法://*

    from lxml import etree
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//*')
    print(result)
    

    只选取所有li节点:XPath语法://li

    from lxml import etree
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//li')
    print(result)
    print(result[0])
    

    3. 获取孩子节点(/)和孙子节点(//)

    孩子节点

    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//li/a')
    print(result)
    

    孙子节点

    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//ul//a')
    print(result)
    

    这个例子中,运行结果是相同的。因为ul里面只有一个a。

    4. 获取父节点

    XPath语法:/..或者parent::

    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//a[@href="link4.html"]/../@class')
    print(result)
    
    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//a[@href="link4.html"]/parent::*/@class')
    print(result)
    

    5. 获取有相应属性的节点(属性匹配)

    选取 class 为 item-1 的 li 节点

    from lxml import etree
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//li[@class="item-1"]')
    print(result)
    

    6. 获取节点的文本

    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//li[@class="item-0"]/text()')
    print(result)
    
    # 运行结果:['
         ']
    

    匹配到的结果就是被修正的 li 节点内部的换行符,因为自动修正的li节点的尾标签换行了
    即选中的是这两个节点:

    <li class="item-0"><a href="link1.html">first item</a></li>
    <li class="item-0"><a href="link5.html">fifth item</a>
    </li>
    
    

    其中一个节点因为自动修正,li 节点的尾标签添加的时候换行了,所以提取文本得到的唯一结果就是 li 节点的尾标签和 a 节点的尾标签之间的换行符

    如果我们想获取 li 节点内部的文本就有两种方式,一种是选取到 a 节点再获取文本,另一种就是使用 //

    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//li[@class="item-0"]/a/text()')
    print(result)
    
    # 运行结果:['first item', 'fifth item']
    
    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//li[@class="item-0"]//text()')
    print(result)
    
    # 运行结果:['first item', 'fifth item', '
         ']
    

    先选取到特定的子孙节点,然后再调用 text() 方法获取其内部文本,这样可以保证获取的结果是整洁的

    7. 获取属性值

    获取所有 li 节点下所有 a 节点的 href 属性

    from lxml import etree
    
    html = etree.parse('./test.html', etree.HTMLParser())
    result = html.xpath('//li/a/@href')
    print(result)
    

    通过 @href 即可获取节点的 href 属性,注意此处和属性匹配的方法不同,属性匹配是中括号加属性名和值来限定某个属性去获取节点,如 a[@href="link1.html"],而此处的 @href 指的是获取节点的某个属性,二者需要做好区分。

    8. 属性多值匹配

    from lxml import etree
    text = '''
    <li class="li li-first"><a href="link.html">first item</a></li>
    '''
    html = etree.HTML(text)
    result = html.xpath('//li[@class="li"]/a/text()')
    print(result)
    
    # 运行结果 []
    

    有多个值就需要用 contains() 函数,因为//li[@class="li"]代表精确匹配

    from lxml import etree
    text = '''
    <li class="li li-first"><a href="link.html">first item</a></li>
    '''
    html = etree.HTML(text)
    result = html.xpath('//li[contains(@class, "li")]/a/text()')
    print(result)
    
    # 运行结果 ['first item']
    

    9. 多属性匹配

    可能需要根据多个属性才能确定一个节点,这是就需要同时匹配多个属性才可以,那么这里可以使用运算符 and 来连接

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

    and是XPath的运算符,参考地址http://www.w3school.com.cn/xpath/xpath_operators.asp

    10. 按序选择节点

    有时候在选择的时候可能某些属性同时匹配了多个节点,但是我们只想要其中的某个节点,如第二个节点,或者最后一个节点。可以利用中括号传入索引的方法获取特定次序的节点。

    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-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a>
         </ul>
     </div>
    '''
    html = etree.HTML(text)
    result = html.xpath('//li[1]/a/text()')    # 注意这里和代码中不同,序号是以 1 开头的,不是 0 开头的。result是0开头的,因为result是一个列表。
    print(result)
    result = html.xpath('//li[last()]/a/text()')    # 返回最后一个li节点
    print(result)
    result = html.xpath('//li[position()<3]/a/text()')    # 选取了位置小于 3 的 li 节点,也就是位置序号为 1 和 2 的节点。即得到了前两个节点
    print(result)
    result = html.xpath('//li[last()-2]/a/text()')    # 中括号中传入 last()-2即可,因为 last() 是最后一个,所以 last()-2 就是倒数第三个
    print(result)
    

    XPath 中提供了 100 多个函数,包括存取、数值、字符串、逻辑、节点、序列等处理功能,具体所有的函数作用可以参考:http://www.w3school.com.cn/xpath/xpath_functions.asp

    11. 节点轴选择

    XPath 提供了很多节点轴选择方法,英文叫做 XPath Axes,包括获取子元素、兄弟元素、父元素、祖先元素等等,在一定情况下使用它可以方便地完成节点的选择

    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-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a>
         </ul>
     </div>
    '''
    html = etree.HTML(text)
    result = html.xpath('//li[1]/ancestor::*')
    print(result)
    result = html.xpath('//li[1]/ancestor::div')
    print(result)
    result = html.xpath('//li[1]/attribute::*')
    print(result)
    result = html.xpath('//li[1]/child::a[@href="link1.html"]')
    print(result)
    result = html.xpath('//li[1]/descendant::span')
    print(result)
    result = html.xpath('//li[1]/following::*[2]')
    print(result)
    result = html.xpath('//li[1]/following-sibling::*')
    print(result)
    

    参考:http://www.w3school.com.cn/xpath/xpath_axes.asp

    总结

    XPath ,熟练使用之后可以大大提升 HTML(文档) 信息的提取效率

  • 相关阅读:
    JQuery操作DOM
    JQuery事件和动画
    Jquery选择器
    初学JQuery
    JavaScript对象及面向对象
    JavaScript操作DOM
    JavaScript操作BOM
    JavaScript基础
    网络流之最大流Dinic算法模版
    杭电1532----Drainage Ditches『最大流』
  • 原文地址:https://www.cnblogs.com/allen2333/p/9300122.html
Copyright © 2020-2023  润新知