xpath总结

Python包

pip install lxml

  在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。XML 文档是被作为节点树来对待的。

xpath语法

/ 代表根路径, 在下面的实例中能够找到/html, 找不到/body

from lxml import etree
html = """<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <ul>
            <li class="item-"><a id='i1' href="link.html">first item</a></li>
            <li class="item-0"><a id='i2' href="llink.html">first item</a></li>
            <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li>
        </ul>
        <div><a href="llink2.html">second item</a></div>
    </body>
</html>
"""

page = etree.HTML(html)
a = page.xpath("/html")
b = page.xpath("/body")
print(a) # [<Element html at 0x1e9c3aa4508>]
print(b) # []

// 代表任何路径, 在下面的例子中,我们甚至可以选到li标签

from lxml import etree
html = """<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <ul>
            <li class="item-"><a id='i1' href="link.html">first item</a></li>
            <li class="item-0"><a id='i2' href="llink.html">first item</a></li>
            <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li>
        </ul>
        <div><a href="llink2.html">second item</a></div>
        <a>我是直属body的</a>
    </body>
</html>
"""

page = etree.HTML(html)
a = page.xpath("//li")
print(a)

/可以嵌套使用,如下实例

from lxml import etree
html = """<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <ul>
            <li class="item-"><a id='i1' href="link.html">first item</a></li>
            <li class="item-0"><a id='i2' href="llink.html">first item</a></li>
            <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li>
        </ul>
        <div><a href="llink2.html">second item</a></div>
    </body>
</html>
"""

page = etree.HTML(html)
a = page.xpath("//a")
b = page.xpath("//div/a")
print(a) # 他有4个
print(b) # 而div下的只有一个

 .和..分别是当前节点和当前节点的父节点

from lxml import etree
html = """<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <ul>
            <li class="item-"><a id='i1' href="link.html">first item</a></li>
            <li class="item-0"><a id='i2' href="llink.html">first item</a></li>
            <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li>
        </ul>
        <div><a href="llink2.html">second item</a></div>
    </body>
</html>
"""

page = etree.HTML(html)
a = page.xpath("//ul")
print(a[0].xpath("./li")) # 在ul下可以找到3个li
print(a[0].xpath("../li")) # 而在ul的父标签下找不到li
print(a[0].xpath("../div")) # 但是却可以找到div

66的中括号, 说出来你可能不信. 这个中括号可以根据索引取, 根据属性取, 还不是一般的索引和属性

还是用上面的那个html

a = page.xpath("//li[1]/a/text()") # 取第一个
a = page.xpath("//li[last()]/a/text()") # 取最后一个
a = page.xpath("//li[last()-1]/a/text()") # 取倒数第二个, 减几都行

# 上面是取固定的, 下面是按范围
a = page.xpath("//li[position()<3]/a/text()") # 小于3的前两个

# [@attr] 可以按照属性取值
a = page.xpath("//li[@class]/a/text()") # 这样三个就都取出来了
a = page.xpath("//li[@class='item-0']/a/text()") # 只取出来固定属性的

# 甚至可以按照元素值的大小来查找
'''
<li class="item-"> <count>88</count> <a id='i1' href="link.html">first item</a></li>
<li class="item-0"><count>77</count> <a id='i2' href="llink.html">first item2</a></li>
<li class="item-1"><count>66</count> <a href="llink2.html">second item<span>vv</span></a></li>
'''
a = page.xpath("//li[count>68]/a/text()") # 查询子标签里的count标签里的文本大于68的

[]里还可以放函数

from lxml import etree
html = """<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <ul>
            <li class="item-"> <count>88</count> <a id='i1' href="link.html">first item</a></li>
            <li class="item-0"><count>77</count> <a id='i2' href="llink.html">first item2</a></li>
            <li class="item-1"><count>66</count> <a href="llink2.html">second item<span>vv</span></a></li>
        </ul>
        <ul>
            <li class="test-"> <count>88</count> <a id='i1' href="link.html">first item</a></li>
            <li class="test-0"><count>77</count> <a id='i2' href="llink.html">first item2</a></li>
            <li class="test-1"><count>66</count> <a href="llink2.html">second item<span>vv</span></a></li>
        </ul>
        
        <div><a href="llink2.html">second item</a></div>
    </body>
</html>
"""

page = etree.HTML(html)
a = page.xpath("//li[starts-with(@class,'test')]/@class") # class以test开头的
print(a)

a = page.xpath("//li[contains(@class,'1')]/@class") # class里包含1的
print(a)

a = page.xpath("//a[contains(text(),'item2')]/text()") # a标签的内容包含item2的
print(a)

# []里的and关系
a = page.xpath("//a[contains(text(),'item2') and @href='llink.html']/text()")
print(a)

其中还包括通配符

*表示任意节点,@*表示任何属性, node()表示任意节点

a = page.xpath("//*/a/text()") # 所有的a标签都选出来了, 不管是div下的a还是li下的a
a = page.xpath("//*/a[@*]/text()") # 这也是所有a, 你要是不服就把@*换成@id
a = page.xpath("//ul/node()") # 里面包括文本节点(换行符之类的)

选取多个路径

a = page.xpath("//ul | //div") # ul或div

轴可定义相对于当前节点的节点集。

语法

轴名称::选择语句
轴名称 结果
ancestor 选选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute  选取当前节点的所有属性。
child  选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素(子、孙等)。
descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
namespace  选取当前节点的所有命名空间节点
parent 选取当前节点的父节点。
preceding 选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling  选取当前节点之前的所有同级节点。
self 选取当前节点。
following 选取文档中当前节点的结束标签之后的所有节点。

 

示例:
 就随便来俩吧

a = page.xpath("//ul/child::li") # ul的子标签
a = page.xpath("//ul/li/child::a/attribute::href") # 取到href属性的值

取值

上卖我们一直用text()来取某个标签的文本, 下面来介绍其他几种

通过string取文本

page = etree.HTML(html)
a = page.xpath("string(//ul/li)")
print(a)

a = page.xpath("//ul/li")
for i in a:
    print(i.xpath("string(.)"))

通过@attr取属性

a = page.xpath("//a/@href")
print(a)

  

posted @ 2019-04-23 11:41  瓜田月夜  阅读(316)  评论(0编辑  收藏  举报