zoukankan      html  css  js  c++  java
  • Python爬虫从入门到进阶(4)之xpath的使用

    官网地址:https://lxml.de/xpathxslt.html

    导入:

     from lxml import etree

    lxml.tree 支持 ElementTree 和 Element 上的 find,findall,findtext方法的简单路径语法,作为特定的 lxml 扩展,这些类提供了 xpath()方法,该方法支持完整xpath语法中的表达式,以及定制的扩展函数。

    xpath()方法

    对于ElementTree,xpath 方法对文档(绝对路径)或者根节点执行全局(相对路径) xpath查询

    def demo_1():
        f = StringIO('<foo><bar></bar></foo>')
        tree = etree.parse(f)
        r = tree.xpath('/foo/bar')
        print(len(r))
        print(r[0].tag)
    
        r_2 = tree.xpath('bar')
        print(r_2[0].tag)

    在 Element 上使用 xpath() 时,xpath()表达式根据元素(相对路径)或根树(绝对路径)查询:

    def demo_2():
        f = StringIO('<foo><bar></bar></foo>')
        tree = etree.parse(f)
    
        root = tree.getroot()
        r = root.xpath('bar')
        print(r[0].tag)
    
        bar = root[0]
        r = bar.xpath('/foo/bar')
        print(r[0].tag)

    xpath()方法支持xpath变量:

    def demo_3():
        f = StringIO('<foo><bar></bar></foo>')
        tree = etree.parse(f)
        root = tree.getroot()
    
        expr = "//*[local-name() = $name]"
        print(root.xpath(expr, name='foo')[0].tag)
        print(root.xpath(expr, name="bar")[0].tag)
        print(root.xpath("$text", text="Hello World!"))
        

    命名空间和前缀

    如果XPath表达式使用名称空间前缀,则必须在前缀映射中定义它们。为此,将一个字典传递给namespace关键字参数,该参数将XPath表达式中使用的名称空间前缀映射到名称空间uri

    def demo_4():
        f = StringIO('''
        <a:foo xmlns:a="http://codespeak.net/ns/test1"
               xmlns:b="http://codespeak.net/ns/test2">
            <b:bar>Text</b:bar>
        </a:foo>
        ''')
    
        doc = etree.parse(f)
        r = doc.xpath('/x:foo/b:bar',
                      namespaces={'x': 'http://codespeak.net/ns/test1',
                                  'b': 'http://codespeak.net/ns/test2'})
        print(len(r))
        print(r[0].tag)
        print(r[0].text)

    在这里选择的前缀并没有连接到XML文档中使用的前缀,文档可以定义任何前缀,包括空前缀,也不会破坏上面的代码

    注意 XPath 没有默认的命名空间,因此,XPath 中没有定义空前缀,不能在命名空间前缀映射中使用

    XPath返回值

    XPath返回值的类型取决于使用的Xpath 表达式:

      (1) True 或者 False

      (2) float

      (3) “智能的”string

        XPath字符串的结果是“智能的”,因为它们提供了一个getparent()方法,该方法知道它们的起源:

          (i)对于属性值,result.getparent()返回携带它们的元素。例如//foo/@attribute,它的父元素是一个foo元素。

          (ii)对于text()函数(如//text()),它返回包含返回的文本或尾部的元素。

        以使用布尔属性is_text、is_tail和is_attribute来区分不同的文本源。

        注意,getparent()不一定总是返回一个元素。例如,XPath函数string()和concat()将构造没有原点的字符串。对于它们,getparent()将不返回任何值。

        有些情况下 smart string 并不受欢迎。例如:它意味着树将字符串保持活动状态,如果字符串值是树中唯一真正需要的东西,那么它可能会对内存产生相当大的影响。对于这些情况,可以使用关键字 smart_strings禁用父关系 

    def demo_5():
        root = etree.XML("<root><a>TEXT</a></root>")
        find_text = etree.XPath("//text()")
        text = find_text(root)[0]
        print(text)
        print(text.getparent().text)
    
        # 禁用父关系
        find_text = etree.XPath("//text()", smart_strings=False)
        text = find_text(root)[0]
        print(text)
        hasattr(text, 'getparent')   

      (4) list 或者 items

    生成XPath表达式

    ElementTree对象有一个getpath(element)方法,它返回一个结构的、绝对的XPath表达式来查找该元素:

    def demo_6():
        a = etree.Element("a")
        b = etree.SubElement(a, "b")
        c = etree.SubElement(a, "c")
        d1 = etree.SubElement(c, "d")
        d2 = etree.SubElement(c, "d")
        tree = etree.ElementTree(c)
        print(tree.getpath(d2))  # /c/d[2]
        print(tree.xpath(tree.getpath(d2)) == [d2])

    XPath类

    XPath类将XPath表达式编译为可调用函数

    def demo_7():
        root = etree.XML("<root><a><b/></a><b/></root>")
        find = etree.XPath("//b")
        print(find(root)[0].tag)

    编译花费的时间和 xpath()方法相同,但是每个类实例化编译一次,这能提高重复计算相同 Xpath 表达式的效率。就像xpath()方法一样,XPpath类支持xpath变量

    def demo_8():
        root = etree.XML("<root><a><b/></a><b/></root>")
        count_elements = etree.XPath("count(//*[local-name() = $name])")
        print(count_elements(root, name="a"))
        print(count_elements(root, name="b"))

    这支持非常有效地计算XPath表达式的修改版本,因为编译仍然只需要一次。

    前缀到命名空间的映射可以作为第二个参数传递:

    def demo_9():
        root = etree.XML("<root xmlns='NS'><a><b/></a><b/></root>")
        find = etree.XPath("//n:b", namespaces={'n': 'NS'})
        print(find(root)[0].tag)

    XPath中的正则表达式

    默认情况下,XPath支持EXSLT名称空间中的正则表达式,也可以使用 regexp 关键字禁用它,默认值是 True

    def demo_10():
        regexpNS = "http://exslt.org/regular-expressions"
        find = etree.XPath("//*[re:test(., '^abc$', 'i')]", namespaces = {'re': regexpNS})
        root = etree.XML("<root><a>aB</a><b>aBc</b></root>")
        print(find(root)[0].text)

    后面还有一些看不下去了,下一篇写下 xpath 的常规用法,点击下载代码

  • 相关阅读:
    centos7的网络设置
    day1学习
    举例讲解Linux系统下Python调用系统Shell的方法
    Python引用模块和查找模块路径
    详解Python中的循环语句的用法
    [cf1566H]Xorquiz
    [luogu5180]支配树
    [atAGC055D]ABC Ultimatum
    [cf1552H]A Serious Referee
    [gym102538H]Horrible Cycles
  • 原文地址:https://www.cnblogs.com/zimengfang/p/10141005.html
Copyright © 2011-2022 走看看