• lxml:底层C语言实现、高效地处理html


    介绍

     
    lxml也是一个用于筛选指定html内容的模块,pyquery就是基于lxml。
    使用lxml主要需要了解xpath

    xpath语法

    • /:在子节点里面找
    • //:在子子孙孙节点里面找
    • //div:查找当前网页的所有div标签
    • //div/p:先找到所有的div标签,再从div的字标签中找p标签
    • //div//p:先找到所有的div标签,再从div的子孙标签中找p标签
    • //div/a:先查找所有div标签,再从div的子标签中找a标签
    • //div/a[@id]:先查找所有div标签,再从div的子标签中找有id属性的a标签
    • //div//a[@id='fuck']:先查找所有div标签,再从div的子孙标签中找有id='fuck'的a标签
    • //div/a[1]:先查找所有的div标签,再找div的子标签中的第一个a标签,这里的索引是从1开始的,不是0
    • //div/a[last()]:和上面一样,不过这里是最后一个a标签
    • //div/a[position()<3]:前两个a标签
    • //div/a[@price]:拥有price属性的a标签
    • //div/a[@price=10]:拥有price属性,并且值等于10的a标签。当然里面还支持>,<,>=,<=等等
    • **//div/*:星号表示通配符,选取所有div的子标签**
    • //div/a[@*]:选取所有div的子标签中带有属性的a标签,什么属性都可以,id、class、href等等都可以
    • //div/a | //div/p:选取所有的div的子标签中的所有a元素和p元素
    • //div/a[contains(@class, "BDE")]:找出所有div的子标签中的class属性包含"BDE"的a标签
    • //div/a[starts-with(@class, "BDE")]:找出所有div的子标签中的class属性以"BDE"开头的a标签
    • //div/a[contains(@href, "mashiro")]:找出所有div的子标签中的class属性包含"mashiro"的a标签
    • //a/@href:获取href属性
    • //a/@class:获取class属性
    • //a/text():获取文本
    • //a[contains(text(), "清纯可爱")]:找出文本包含"清纯可爱"的a标签
     
    我们可能注意到:@href、@class、text()前面只有一个/,如果是两个/的话,比如div标签,它里面是没有href属性的。但是div里面有a标签,a标签里面有href属性,所以我们仍然可以通过//div//@href去获取,此时获取的是里面的a标签里面的href,但是//div/@href是获取不到的,因为//div/@href表示的是获取div标签里面的href,而div没有href属性。
    
    因此如果是/@href,那么前面必须是有href属性的标签,否则获取不到。但如果是//@href的话,前面的标签就没有太多要求了,可以是p标签,也可以是div标签,只要里面有具有href属性的标签即可

    使用lxml

    python
    from lxml import etree
    import requests
    
    res = requests.get("http://www.baidu.com",
                       headers={"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"})
    res.encoding = res.apparent_encoding
    
    # 调用etree内部的HTML方法,将html文本传进去,便得到一个可以进行xpath的对象
    # 我们可以调用etree.tostring(html),会得到一个字节对象,再解码会得到字符串,这里就不演示了。
    html = etree.HTML(res.text)
    
    # 找出class属性等于"toindex"的a标签
    result = html.xpath("//a[@class='toindex']")
    for res in result:
        # 打印的结果是一个标签
        print(res)  # <Element a at 0x1b2cb5cecc8>
        # 可以调用tostring转成字节
        print(etree.tostring(res))  # b'<a class="toindex" href="/">&#30334;&#24230;&#39318;&#39029;</a>'
        print(str(etree.tostring(res), encoding="utf-8"))  # <a class="toindex" href="/">&#30334;&#24230;&#39318;&#39029;</a>
    
        # 内部还有一个etree.parse()方法,可以直接传入html文件或者xml文件的路径,进行解析
    
    
    # 获取一下内部属性
    result = html.xpath("//a[@class='toindex']/@href")
    # 由于标签只有一个,所以列表里面只有一个元素
    print(result)  # ['/']
    result = html.xpath("//a[@class='toindex']/@class")
    print(result)  # ['toindex']
    result = html.xpath("//a[@class='toindex']/text()")
    print(result)  # ['百度首页']
    # 可以看到此时的result又都不是标签了,这是为什么?
    # 如果我们不选择href、class等具体属性的话,那么得到的是一个标签,如果选择属性那么得到是字符串
    # 因为不止一个标签,所以会将所有的字符串组合成一个列表
    # 即便只有一个元素,得到依旧是一个列表
    
    result = html.xpath("//div[contains(@class, 'tab_inner')]")
    # 现在获取的result里面只有一个元素
    for res in result:
        print(res)  # <Element div at 0x2644f88>
        print(etree.tostring(res))  # b'<div class="s_tab_inner">
        <b>网页</b>
        <a href=。。。。。。
        # 我们看到了,如果不是获取href、class、text等属性的时候,得到的依旧是一个Element对象,这就意味着我们可以继续使用xpath
        titles = res.xpath(".//a/text()")  # 注意这里是.//不是//,因为我们要在当前元素的子孙中去查找
        print(titles)  # ['资讯', '贴吧', '知道', '音乐', '图片', '视频', '地图', '文库', '更多»']
        # 我们试试不加.
        titles = res.xpath("//a/text()")
        # 可以看到内容就多了,因为即便是res.xpath,但指定//的话依旧会在全局html页面中查找
        print(titles)
        """
        # ['手写', '拼音', '关闭', '百度首页', '设置', '登录', '新闻', 'hao123', 
        '地图', '视频', '贴吧', '学术', '登录', '设置', '更多产品', '资讯', '贴吧', 
        '知道', '音乐', '图片', '视频', '地图', '文库', '更多»', '把百度设为主页', 
        '关于百度', 'Aboutxa0xa0Baidu', '百度推广', '使用百度前必读', '意见反馈', 
        '京公网安备11000002000001号']
        """
        # 进一步证实了两者结果是一样的
        print(res.xpath("//a/text()") == html.xpath("//a/text()"))  # True
  • 相关阅读:
    linux截图工具
    Git理论知识补充
    Git基本操作(add,commit的理解)
    VS2017 error CS0234: 命名空间“Microsoft”中不存在类型或命名空间名“Office”问题的一种解决方案
    MFC CFileDialog DoModal()无法弹出窗口,直接返回IDCANCEL
    VS2015 、VS2017 MFC输出日志到控制台窗口
    win10 VMware 关闭虚拟机失败导致再打开时显示连接不上虚拟机的一种解决方法
    c语言之位段
    Adobe Acrobat DC 制作多级书签
    MFC基于对画框工程笔记->更改窗口图标以及生成的.exe图标
  • 原文地址:https://www.cnblogs.com/valorchang/p/11395423.html
Copyright © 2020-2023  润新知