zoukankan      html  css  js  c++  java
  • lxml模块学习

    一、简介

    lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高。

    XPath的选择功能十分强大,它提供了非常简明的路径选择表达式,另外,它还提供了超过100个内建函数,用于字符串、数值、时间的匹配以及节点、序列的处理等,几乎所有我们想要定位的节点,都可以用XPath来选择。

    二、运用

    xpath 的思想是通过 路径表达 去寻找节点。节点包括元素属性,和内容。

    表达式  描述
     nodename  选取此节点的所有子节点
     /  从当前节点选取直接子节点
     //  从当前节点选取子孙节点
     .  选取当前节点
     ..  选取当前节点的父节点
     @  选取属性
     *  通配符,选择所有元素节点与元素名
     @*  选取所有属性
     [@attrib]  选取具有给定属性的所有元素
     [@attrib='value']  选取给定属性具有给定值的所有元素
     [tag]  选取所有具有指定元素的直接子节点

    1、lxml 读取文本解析节点

    from lxml import etree
    
    text='''
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">第一个</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0"><a href="link5.html">a属性</a>
         </ul>
     </div>
    '''
    html=etree.HTML(text) #初始化生成一个XPath解析对象
    result=etree.tostring(html,encoding='utf-8')   #解析对象输出代码
    print(type(html))
    print(type(result))
    print(result.decode('utf-8'))
    
    #etree会修复HTML文本节点
    <class 'lxml.etree._Element'>
    <class 'bytes'>
    <html><body><div>
        <ul>
             <li class="item-0"><a href="link1.html">第一个</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0"><a href="link5.html">a属性</a>
         </li></ul>
     </div>
    </body></html>

    2、lxml 读取HTML文件进行解析

    from lxml import etree
    
    html=etree.parse('test.html',etree.HTMLParser()) #指定解析器HTMLParser会根据文件修复HTML文件中缺失的如声明信息
    result=etree.tostring(html)   #解析成字节
    #result=etree.tostringlist(html) #解析成列表
    print(type(html))
    print(type(result))
    print(result)
    
    #输出
    <class 'lxml.etree._ElementTree'>
    <class 'bytes'>
    b'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
    <html><body><div>&#13;
        <ul>&#13;
             <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>&#13;
         </li></ul>&#13;
     </div>&#13;
    </body></html>'

    3、xpath运用

    (1)获取所有节点

    from lxml import etree
    
    html=etree.parse('test',etree.HTMLParser())
    result=html.xpath('//*')  #//代表获取子孙节点,*代表获取所有
    
    print(type(html))
    print(type(result))
    print(result)
    
    #
    <class 'lxml.etree._ElementTree'>
    <class 'list'>
    [<Element html at 0x754b210048>, <Element body at 0x754b210108>, <Element div at 0x754b210148>, <Element ul at 0x754b210188>, <Element li at 0x754b2101c8>, <Element a at 0x754b210248>, <Element li at 0x754b210288>, <Element a at 0x754b2102c8>, <Element li at 0x754b210308>, <Element a at 0x754b210208>, <Element li at 0x754b210348>, <Element a at 0x754b210388>, <Element li at 0x754b2103c8>, <Element a at 0x754b210408>]

    (2)获取父节点

    from lxml import etree
    from lxml.etree import HTMLParser
    text='''
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">第一个</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
         </ul>
     </div>
    '''
    
    html=etree.HTML(text,etree.HTMLParser())
    result=html.xpath('//a[@href="link2.html"]/../@class')
    result1=html.xpath('//a[@href="link2.html"]/parent::*/@class')
    print(result)
    print(result1)
    
    
    #
    ['item-1']
    ['item-1']

    (3)属性匹配

    from lxml import etree
    from lxml.etree import HTMLParser
    text='''
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">第一个</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
         </ul>
     </div>
    '''
    
    html=etree.HTML(text,etree.HTMLParser())
    result=html.xpath('//li[@class="item-1"]')
    print(result)

    (4)文本获取

    from lxml import etree
    
    text='''
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">第一个</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
         </ul>
     </div>
    '''
    
    html=etree.HTML(text,etree.HTMLParser())
    result=html.xpath('//li[@class="item-1"]/a/text()') #获取a节点下的内容
    result1=html.xpath('//li[@class="item-1"]//text()') #获取li下所有子孙节点的内容
    
    print(result)
    print(result1)

    (5)属性多值匹配

    from lxml import etree
    
    text1='''
    <div>
        <ul>
             <li class="aaa item-0"><a href="link1.html">第一个</a></li>
             <li class="bbb item-1"><a href="link2.html">second item</a></li>
         </ul>
     </div>
    '''
    
    html=etree.HTML(text1,etree.HTMLParser())
    result=html.xpath('//li[@class="aaa"]/a/text()')
    result1=html.xpath('//li[contains(@class,"aaa")]/a/text()')
    
    print(result)
    print(result1)
    
    #通过第一种方法没有取到值,通过contains()就能精确匹配到节点了
    []
    ['第一个']

    (6)多属性匹配

    from lxml import etree
    
    text1='''
    <div>
        <ul>
             <li class="aaa" name="item"><a href="link1.html">第一个</a></li>
             <li class="aaa" name="fore"><a href="link2.html">second item</a></li>
         </ul>
     </div>
    '''
    
    html=etree.HTML(text1,etree.HTMLParser())
    result=html.xpath('//li[@class="aaa" and @name="fore"]/a/text()')
    result1=html.xpath('//li[contains(@class,"aaa") and @name="fore"]/a/text()')
    
    
    print(result)
    print(result1)
    
    
    #
    ['second item']
    ['second item']

    (7)运算符

     运算符  描述  实例  返回值
     or  或  age=10 or age=20  如果age等于10或者等于20则返回true反正返回false
     and  与  age>19 and age<21  如果age等于20则返回true,否则返回false
     mod  取余  5 mod 2  1
     |  取两个节点的集合  //book | //cd  返回所有拥有book和cd元素的节点集合
     +  加  5+4  9
     -  减  5-4  1
     *  乘  5*4  20
     div  除法  6 div 3  2
     =  等于  age=10  true
     !=  不等于  age!=10  true
     <  小于  age<10  true
     <=  小于或等于  age<=10  true
     >  大于  age>10  true
     >=  大于或等于  age>=10  true

    (8)按序选择

    from lxml import etree
    
    text1='''
    <div>
        <ul>
             <li class="aaa" name="item"><a href="link1.html">第一个</a></li>
             <li class="aaa" name="item"><a href="link1.html">第二个</a></li>
             <li class="aaa" name="item"><a href="link1.html">第三个</a></li>
             <li class="aaa" name="item"><a href="link1.html">第四个</a></li> 
         </ul>
     </div>
    '''
    
    html=etree.HTML(text1,etree.HTMLParser())
    
    result=html.xpath('//li[contains(@class,"aaa")]/a/text()') #获取所有li节点下a节点的内容
    result1=html.xpath('//li[1][contains(@class,"aaa")]/a/text()') #获取第一个
    result2=html.xpath('//li[last()][contains(@class,"aaa")]/a/text()') #获取最后一个
    result3=html.xpath('//li[position()>2 and position()<4][contains(@class,"aaa")]/a/text()') #获取第一个
    result4=html.xpath('//li[last()-2][contains(@class,"aaa")]/a/text()') #获取倒数第三个
    
    
    print(result)
    print(result1)
    print(result2)
    print(result3)
    print(result4)
    
    
    #
    ['第一个', '第二个', '第三个', '第四个']
    ['第一个']
    ['第四个']
    ['第三个']
    ['第二个']

    (9)节点轴选择

    from lxml import etree
    
    text1='''
    <div>
        <ul>
             <li class="aaa" name="item"><a href="link1.html">第一个</a></li>
             <li class="aaa" name="item"><a href="link1.html">第二个</a></li>
             <li class="aaa" name="item"><a href="link1.html">第三个</a></li>
             <li class="aaa" name="item"><a href="link1.html">第四个</a></li> 
         </ul>
     </div>
    '''
    
    html=etree.HTML(text1,etree.HTMLParser())
    result=html.xpath('//li[1]/ancestor::*')  #获取所有祖先节点
    result1=html.xpath('//li[1]/ancestor::div')  #获取div祖先节点
    result2=html.xpath('//li[1]/attribute::*')  #获取所有属性值
    result3=html.xpath('//li[1]/child::*')  #获取所有直接子节点
    result4=html.xpath('//li[1]/descendant::a')  #获取所有子孙节点的a节点
    result5=html.xpath('//li[1]/following::*')  #获取当前子节之后的所有节点
    result6=html.xpath('//li[1]/following-sibling::*')  #获取当前节点的所有同级节点
    
    
    #
    [<Element html at 0x3ca6b960c8>, <Element body at 0x3ca6b96088>, <Element div at 0x3ca6b96188>, <Element ul at 0x3ca6b961c8>]
    [<Element div at 0x3ca6b96188>]
    ['aaa', 'item']
    [<Element a at 0x3ca6b96248>]
    [<Element a at 0x3ca6b96248>]
    [<Element li at 0x3ca6b96308>, <Element a at 0x3ca6b96348>, <Element li at 0x3ca6b96388>, <Element a at 0x3ca6b963c8>, <Element li at 0x3ca6b96408>, <Element a at 0x3ca6b96488>]
    [<Element li at 0x3ca6b96308>, <Element li at 0x3ca6b96388>, <Element li at 0x3ca6b96408>]

    (10)自定义函数

    from lxml import etree
    
    #定义函数
    def ends_with(context,s1,s2):
        return s1[0].endswith(s2)
    if __name__ == '__main__':
        doc='''
            <div>
                <ul class='ul items'>
                     <li class="item-0 active"><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> # 注意,此处缺少一个 </li> 闭合标签
                 </ul>
             </div>
            '''
        html = etree.XML(doc)
        ns = etree.FunctionNamespace(None)  
        ns['ends-with'] = ends_with #将ends_with方法注册到方法命名空间中
        print(html.xpath("//li[ends-with(@class,'active')]"))
        print(html.xpath("//li[ends-with(@class,'active')]/a/text()"))
    • 形参s1会传入xpath中的第一个参数@class,但这里注意@class是个列表
    • 形参s2会传入xpath中的第二个参数'active''active'是个字符串

    4、xpath支持的内建函数

    • number last() 谓语中返回在兄弟元素中排在最末尾的
    • number position() 谓语中,返回该元素在兄弟中的排名
    • number count(node-set) 返回子节点的个数 ,node-set代表子节点的表达式
    • node-set id("foo") 返回唯一id为foo的元素 。尝试了多次,未尝试出来,这里的唯一id是基于xml的,有下面这样一句话。所以确实没测试出来
    • string local-name(node-set?)

    • string name(node-set?)

    • string namespace-uri(node-set?)

    • string concat(string, string, string*)

    • boolean starts-with(string, string)

    • boolean contains(string, string)

    • string substring-before(string, string)

    • string substring-after(string, string)

    • string substring(string, number, number?)

    • number string-length(string?)

    • string normalize-space(string?)

    • number sum(node-set)

    • number floor(number)

    • number ceiling(number)

    • number round(number)

    5、xpath使用工具

    chome生成xpath表达式

    经常使用chome的小伙伴的都应该知道这个功能,在 审查 状态下(快捷键ctrl+shift+i,F12),定位到元素(快捷键ctrl+shift+c) ,在Elements选项卡中,右键元素 Copy->Copy xpath,就能得到该元素的xpath了

    6、xpath插件

    为chome装上XPath Helper就可以很轻松的检验自己的xpath是否正确了。安装插件需要kxsw(使用lanternFQ,或者Astar VPN),安装好插件后,在chrome右上角点插件的图标,调出插件的黑色界面,编辑好xpath表达式,表达式选中的元素被标记为黄色

  • 相关阅读:
    flume+kafka+storm打通过程
    kafka入门
    hive执行更新和删除操作
    redis存储对象与对象序列化详解
    语音常识--语音信号的数字模型
    声源测向: TDOA-GCC-PATH方法
    【面试】如何比较一个类型【模板使用】【sizeof用法】
    【概括】C++11/14特性
    【面试】编译器为我们实现了几个类成员函数?(c++)
    语音信号处理常识【摘抄|自用】
  • 原文地址:https://www.cnblogs.com/windyrainy/p/15158537.html
Copyright © 2011-2022 走看看