zoukankan      html  css  js  c++  java
  • xpath的基础使用

    一.xpath简介

    XPath 是一门在 XML 文档中查找信息的语言。XPath 用于在 XML 文档中通过元素和属性进行导航。
    • XPath 使用路径表达式在 XML 文档中进行导航
    • XPath 包含一个标准函数库
    • XPath 是 XSLT 中的主要元素
    • XPath 是一个 W3C 标准

    `节点

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

    xpath比美丽汤更通用,在各语言的xpath中都可以使用,scrapy框架也是内置了一个xpath,而美丽汤只能在python中使用.

    二、xpath语法

      1.选取节点

    表达式

    描述

    实例

     

    nodename

    选取nodename节点的所有子节点

    xpath('//div')

    选取了div节点的所有子节点

    /

    从根节点选取

    xpath('/div')

    从根节点上选取div节点

    //

    选取所有的当前节点,不考虑他们的位置

    xpath('//div')

    选取所有的div节点

    .

    选取当前节点

    xpath('./div')

    选取当前节点下的div节点

    ..

    选取当前节点的父节点

    xpath('..')

    回到上一个节点

    @

    选取属性

    xpath('//@calss')

    选取所有的class属性

      2、谓语

         谓语被嵌在方括号内,用来查找某个特定的节点或包含某个特定的值的节点,因为所有xpath解析返回值为一个列表

        xpath的索引从1开始   

    表达式

    结果

    xpath('/body/div[1]')

    选取body下的第一个div节点

    xpath('/body/div[last()]')

    选取body下最后一个div节点

    xpath('/body/div[last()-1]')

    选取body下倒数第二个div节点

    xpath('/body/div[positon()<3]')

    选取body下前两个div节点

    xpath('/body/div[@class]')

    选取body下带有class属性的div节点

    xpath('/body/div[@class="main"]')

    选取body下class属性为main的div节点

    xpath('/body/div[price>35.00]')

    选取body下price元素值大于35的div节点

      3、通配符  

        Xpath通过通配符来选取未知的XML元素

    表达式

    结果

    xpath('/div/*')

    选取div下的所有子节点

    xpath('/div[@*]')

    选取所有带属性的div节点

        4、逻辑运算

        使用“|”或者and运算符可以选取多个路径

        

    表达式

    结果

    xpath('//div|//table')

    选取所有的div和table节点

    xpath(//a[@href="" and @class="du"])

    选取同时具href="",class='du'的a标签

      5、Xpath轴

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

    轴名称

    表达式

    描述

    ancestor

    xpath('./ancestor::*')

    选取当前节点的所有先辈节点(父、祖父)

    ancestor-or-self

    xpath('./ancestor-or-self::*')

    选取当前节点的所有先辈节点以及节点本身

    attribute

    xpath('./attribute::*')

    选取当前节点的所有属性

    child

    xpath('./child::*')

    返回当前节点的所有子节点

    descendant

    xpath('./descendant::*')

    返回当前节点的所有后代节点(子节点、孙节点)

    following

    xpath('./following::*')

    选取文档中当前节点结束标签后的所有节点

    following-sibing

    xpath('./following-sibling::*')

    选取当前节点之后的兄弟节点

    parent

    xpath('./parent::*')

    选取当前节点的父节点

    preceding

    xpath('./preceding::*')

    选取文档中当前节点开始标签前的

      

    preceding-sibling

    xpath('./preceding-sibling::*')

    选取当前节点之前的兄弟节点

    self

    xpath('./self::*')

    选取当前节点

       6、功能函数(模糊匹配) 

          使用功能函数能够更好的进行模糊搜索

    函数

    用法

    解释

    starts-with

    xpath('//div[starts-with(@id,"ma")]')

    选取id值以ma开头的div节点

    contains

    xpath('//div[contains(@id,"ma")]')

    选取id值包含ma的div节点

    and

    xpath('//div[contains(@id,"ma") and contains(@id,"in")]')

    选取id值包含ma和in的div节点

    text()

    xpath('//div[contains(text(),"ma")]')

    选取节点文本包含ma的div节点

        7.取属性和文本

    @ //div[@class="tang"]//li[2]/a/@href 取标签的的href属性值
    text() //div[@class="song"]/p[1]/text() 取p[1]的所有属性值
    text() //div[@class="tang"]//text() 取div标签的所有文本值,包括子标签的

        

         8.通过text()确定标签

    选取文本是'>'的a标签
    xpath('//a[text()=">"]')

        9.string(.)提取所有文本  

    html3 = '''
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="test3">
            我左青龙,
            <span id="tiger">
                右白虎,
                <ul>上朱雀,
                    <li>下玄武。</li>
                </ul>
                老牛在当中,
            </span>
            龙头在胸口。
        </div>
    </body>
    </html>
    '''
    #如果使用一般的办法,就会出现获取到的数据不完整的情况
    selector = lxml.html.fromstring(html3)
    # content_1 = selector.xpath('//div[@id="test3"]/text()')
    # for each in content_1:
    #     print(each)
    
    # 使用string(.)就可以把数据获取完整
    data = selector.xpath('//div[@id="test3"]')[0]
    info = data.xpath('string(.)')
    print(info)


    #####或者使用这种情况
    t=etree.HTML(html3)
    res = t.xpath("//div[@id='test3']//text()")
    print(res)

       10.text_content()

    最开始对html文本使用 etree.HTML(html)解析,得到Element对象。
    
    from lxml import etree
    
    str="""
    
    <div>
    <a href="xxxx">123</a>
    <a href="xxxx">45</a>
    <div>
    
    """
    
    root= etree.HTML(str)
    
    root.xpath("//div//text()")
    
    #发现并没有直接获取12345文本方法
    
    #后来网上调查发现lxml操作html有一个专门的html模块html,然后找到了解决该问题的关键方法text_content(),这个方法在上面的写法中是不存在的于是解决方案如下。
    
    from lxml import html
    
    root = html.fromstring('''<div><a href="xxxx">123</a><a href="xxxx">45</a><div>''')
    
     
    
     root.xpath("//div").text_content()

    三.使用流程

    xpath数据解析流程:
      1.pip install lxml
      2.导包:from lxml import etree
      3.实例化一个etree对象(将页面数据加载到该对象)

      •  本地文件:tree = etree.parse(文件名)          tree.xpath("xpath表达式")  ===>本地文件指的是包打开的网页另存为到本地的文件
      •   网络数据:tree = etree.HTML(网页内容字符串)       tree.xpath("xpath表达式")    

      4.调用etree中的xpath函数结合着xpath表达式进行数据解析操作

       看一个例子(爬取58)

    import requests
    from lxml import etree
    
    headers={
        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER'
    }
    url='https://sz.58.com/ershoufang/?PGTID=0d200001-0000-4229-cd25-6936558931c6&ClickID=1'
    #拿到页面源码数据的text
    page_text=requests.get(url=url,headers=headers).text
    #把页面源码数据作为参数实例一个etree对象
    tree=etree.HTML(page_text)
    
    #用xpath进行解析
    #xpath表达式的作用:xpath表达式如果作用到页面源码中,可以将页面源码中指定的标签进行定位.
    #所有xpath解析返回值为一个列表
    #可以对局部对象在进行xpath,但是路径要记得要变成./
    li_list=tree.xpath('//ul[@class="house-list-wrap"]/li')
    
    f=open('./xpath-58.txt','w',encoding='utf-8')
    for li in li_list:
        title=li.xpath('./div[2]/h2/a/text()')[0]#xpath返回的是一个列表,即使解析对象只有一个
        total_price=li.xpath('./div[3]/p[1]//text()')#返回两个值直接返回
        total_price=''.join(total_price)
    
        f.write(title+':'+total_price+'
    ')
    f.close()

    #这边只爬取了第一页,如想要爬取其他页面,只要去改一下页码参数,进行一个循环即可

     主要几点:

    1.获取文本
    •   a/text() 获取a下文本
    • a//text() 获取a下面的所有文本
    • a[text()='下一页']

    2.@符号

    •   a/@href
    • div[@class='detail']
    • div[@id='content']

    3.//

    • 任意位置开始选择

    四.一些高级用法

      1.count:统计

    tree.xpath('count(//li[@data])') #节点统计

      2.concat:字符串连接

    tree.xpath('concat(//li[@data="one"]/text(),//li[@data="three"]/text())')

      3.string:解析当前节点下的字符

    #string只能解析匹配到的第一个节点下的值,也就是作用于list时只匹配第一个
    tree.xpath('string(//li)') 

      4. local-name:解析节点名称

    tree.xpath('local-name(//*[@id="testid"])') #local-name解析节点名称

      5.not 布尔值(否)

    tree.xpath('count(//li[not(@data)])') #不包含data属性的li标签统计
     #多用于表格中匹配中不包含表头信息的数据
     xpath('//table/tr[not(@class="tbhead")]'

      6.string-length:返回指定字符串的长度

    #string-length函数+local-name函数定位节点名长度小于2的元素
    tree.xpath('//*[string-length(local-name())<2]/text()')[0] 

      7.or:多条件匹配

    tree.xpath('//li[@data="one" or @code="84"]/text()') #or匹配多个条件
    tree.xpath('//li[@data="one"]/text() | //li[@code="84"]/text()') #|匹配多个条件

      8.<:小于

    tree.xpath('//li[@code<200]/text()')

      9.div

    tree.xpath('//div[@id="testid"]/ul/li[3]/@code div //div[@id="testid"]/ul/li[1]/@code')

      10.根据节点下的某一节点数量定位

    tree.xpath('//ul[count(li)>5]/li/text()')

      11.将对象还原为字符串

    >>> s = tree.xpath('//*[@id="testid"]')[0] #使用xpath定位一个节点
    >>> s
    <Element div at 0x2b6ffc8>
    >>> s2 = etree.tostring(s) #还原这个对象为html字符串
    >>> s2
    '<div id="testid">
    		<h2>&#213;&#226;&#192;&#239;&#202;&#199;&#184;&#246;&#208;&#161;&#177;&#234;&#204;&#226;</h2>
    		<ol>
    			<li data="one">1</li>
    			<li data="two">2</li>
    			<li data="three">3</li>
    		</ol>
    		<ul>
    			<li code="84">84</li>
    			<li code="104">104</li>
    			<li code="223">223</li>
    		</ul>
    	</div>
    	'

      注:s2 = etree.tostring(s,encoding=‘utf-8’) 

      12. and

    #匹配所有的tr中不包含 tbhead 属性 和包含 head 的tr标签
    xpath('//table/tr[not(@class="tbhead") and @class="head"]')

      13. or

    匹配包含class="speedbar" 或者 class="content-wrap" 的标签
    xpath('//div[@class="speedbar" or @class="content-wrap"]'

      14.取货所有的属性

    //div/@* 
  • 相关阅读:
    python字符串连接方式(转)
    Python顺序与range和random
    将EXCEL中的列拼接成SQL insert插入语句
    Python OS模块
    Python3.5连接Mysql
    Mysql查看连接端口及版本
    Mysqldb连接Mysql数据库(转)
    Python 文件I/O (转)
    Python 日期和时间(转)
    Python序列的方法(转)
  • 原文地址:https://www.cnblogs.com/tjp40922/p/10433427.html
Copyright © 2011-2022 走看看