1. 程式人生 > >Python爬蟲從入門到進階(4)之xpath的使用

Python爬蟲從入門到進階(4)之xpath的使用

names 擴展函數 .get 結果 定義 提高 調用函數 命名空間 concat

官網地址: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 的常規用法,點擊下載代碼

Python爬蟲從入門到進階(4)之xpath的使用