Python xpath模块

一、开始使用

使用时先安装 lxml 包

pip install lxml

和beautifulsoup类似,首先我们需要得到一个文档树

  • 把文本转换成一个文档树对象

    from lxml import etree
    if __name__ == '__main__':
        doc='''
            <div>
                <ul>
                     <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> # 注意,此处缺少一个 </li> 闭合标签
                 </ul>
             </div>
            '''
    
        html = etree.HTML(doc)
        result = etree.tostring(html)
        print(str(result,'utf-8'))
    
  • 把文件转换成一个文档树对象

    from lxml import etree
    
    # 读取外部文件 index.html
    html = etree.parse('./index.html')
    result = etree.tostring(html, pretty_print=True)    #pretty_print=True 会格式化输出
    print(result)
    

二、节点、元素、属性、内容

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

  • 元素举例

    html ---> <html> ...</html>
    div ---> <div> ...</div>
    a  ---> <a> ...</a>
    

    这里我们可以看到,这里的元素和html中的标签一个意思。单独的元素是无法表达一个路径的,所以单独的元素不能独立使用

三、路径表达式

    /   根节点,节点分隔符,
    //  任意位置
    .   当前节点
    ..  父级节点
    @   属性

四、通配符

*   任意元素
@*  任意属性
node()  任意子节点(元素,属性,内容)

五、谓语

使用中括号来限定元素,称为谓语

    //a[n] n为大于零的整数,代表子元素排在第n个位置的<a>元素
    //a[last()]   last()  代表子元素排在最后个位置的<a>元素
    //a[last()-]  和上面同理,代表倒数第二个
    //a[position()<3] 位置序号小于3,也就是前两个,这里我们可以看出xpath中的序列是从1开始
    //a[@href]    拥有href的<a>元素
    //a[@href='www.baidu.com']    href属性值为'www.baidu.com'的<a>元素
    //book[@price>2]   price值大于2的<book>元素

六、多个路径

| 连接两个表达式,可以进行 匹配

//book/title | //book/price  

七、函数

xpath内置很多函数。更多函数查看https://www.w3school.com.cn/xpath/xpath_functions.asp

  • contains(string1,string2)
  • starts-with(string1,string2)
  • text()
  • last()
  • position()
  • node()

可以看到last()也是个函数,在前面我们在谓语中已经提到过了

八、定位元素

匹配多个元素,返回列表

from lxml import etree

if __name__ == '__main__':
    doc='''
        <div>
            <ul>
                 <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> # 注意,此处缺少一个 </li> 闭合标签
             </ul>
         </div>
        '''

    html = etree.HTML(doc)
    print(html.xpath("//li"))
    print(html.xpath("//p")) 

结果为

[<Element li at 0x2b41b749848>, <Element li at 0x2b41b749808>, <Element li at 0x2b41b749908>, <Element li at 0x2b41b749948>, <Element li at 0x2b41b749988>]
[]  #没找到p元素
html = etree.HTML(doc)
print(etree.tostring(html.xpath("//li[@class='item-inactive']")[0]))
print(html.xpath("//li[@class='item-inactive']")[0].text)
print(html.xpath("//li[@class='item-inactive']/a")[0].text)
print(html.xpath("//li[@class='item-inactive']/a/text()"))
print(html.xpath("//li[@class='item-inactive']/.."))
print(html.xpath("//li[@class='item-inactive']/../li[@class='item-0']"))

结果为

b'<li class="item-inactive"><a href="link3.html">third item</a></li>\n                 '
None    #因为第三个li下面没有直接text,None
third item  # 
['third item']
[<Element ul at 0x19cd8c4c848>]
[<Element li at 0x15ea3c5b848>, <Element li at 0x15ea3c5b6c8>]

九、使用函数

contains

有的时候,class作为选择条件的时候不合适@class='....' 这个是完全匹配,当网页样式发生变化时,class或许会增加或减少像activeclass。用contains就能很方便

from lxml import etree
if __name__ == '__main__':
    doc='''
        <div>
            <ul>
                 <p class="item-0 active"><a href="link1.html">first item</a></p>
                 <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.HTML(doc)
    print(html.xpath("//*[contains(@class,'item')]"))

starts-with

from lxml import etree
if __name__ == '__main__':
    doc='''
        <div>
            <ul class='ul items'>
                 <p class="item-0 active"><a href="link1.html">first item</a></p>
                 <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.HTML(doc)
    print(html.xpath("//*[contains(@class,'item')]"))
    print(html.xpath("//*[starts-with(@class,'ul')]"))

text、last

#最后一个li被限定了
print(html.xpath("//li[last()]/a/text()"))

#会得到所有的`<a>`元素的内容,因为每个<a>标签都是各自父元素的最后一个元素。
#本来每个li就只有一个<a>子元素,所以都是最后一个
print(html.xpath("//li/a[last()]/text()"))  

print(html.xpath("//li/a[contains(text(),'third')]"))

position

print(html.xpath("//li[position()=2]/a/text()"))
#结果为['third item']

node

返回所有子节点,不管这个子节点是什么类型(熟悉,元素,内容)

print(html.xpath("//ul/li[@class='item-inactive']/node()"))
print(html.xpath("//ul/node()"))

#结果为
[<Element a at 0x239a0d197c8>]
['\n                 ', <Element li at 0x239a0d19788>, '\n                 ', <Element li at 0x239a0d19888>, '\n                 ', <Element li at 0x239a0d19908>, '\n                 ', <Element li at 0x239a0d19948>, '\n                 ', <Element li at 0x239a0d198c8>, ' 闭合标签\n             ']

十、获取内容

刚刚已经提到过,可以使用.texttext()的方式来获取元素的内容

from lxml import etree
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)
    print(html.xpath("//a/text()"))
    print(html.xpath("//a")[0].text)
    print(html.xpath("//ul")[0].text)
    print(len(html.xpath("//ul")[0].text))
    print(html.xpath("//ul/text()"))

十一、获取属性

print(html.xpath("//a/@href"))
print(html.xpath("//li/@class"))
posted @ 2023-03-05 22:40  与鹿逐秋  阅读(70)  评论(0编辑  收藏  举报