zoukankan      html  css  js  c++  java
  • Python(00):解析xml文件(sax、dom、ElementTree)和lxml

    一、Python对XML的解析

    常见的XML编程接口有DOM和SAX,这两种接口处理XML文件的方式不同,使用场合也不同。

    python有三种方法解析XML:SAX,DOM和ElementTree

    1、DOM(Document Object Model)

    DOM的解析器在解析一个XML文档时,一次性读取整个文档,把文档中所有元素保存在内存中的一个树结构里,之后利用DOM提供的不同函数来读取该文档的内容和结构,也可以把修改过的内容写入XML文件。

    由于DOM是将XML读取到内存,然后解析成一个树,如果要处理的XML文本比较大的话,就会很耗内存,所以DOM一般偏向于处理一些小的XML(如配置文件)比较快。

    python中用xml.dom.minidom来解析xml文件。

    from xml.dom.minidom import parse
    
    DOMTree = parse(r'book.xml')  # minidom解析器打开xml文档并将其解析为内存中的一棵树
    booklist = DOMTree.documentElement  # 获取xml文档对象,就是拿到树的根
    
    if booklist.hasAttribute('type'):
        print('Root element is ', booklist.getAttribute('type'))  # 判断根节点booklist是否有type属性,有则获取并打印属性值
    books = booklist.getElementsByTagName('book')  # 获取booklist对象中所有的book节点的list集合
    print('book节点的个数为:', len(books))
    print('book节点的个数为:', books.length)
    
    for book in books:
        print("*******************book*******************")
        if book.hasAttribute('category'):
            print('category is ', book.getAttribute('category'))
        # 根据节点名title/author/pageNumber得到这些节点的集合list
        title = book.getElementsByTagName('title')[0]
        author = book.getElementsByTagName('author')[0]
        pageNumber = book.getElementsByTagName('pageNumber')[0]
    
        print('title is ', title.childNodes[0].data)
        print('author is ', author.childNodes[0].data)
        print('pageNumber is ', pageNumber.childNodes[0].data)

    2、SAX(simple API for XML)

    Python标准库中包含SAX解析器,SAX是用的是事件驱动模型,通过在解析XML过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。
    解析的基本过程:
    读到一个XML开始标签,就会开始一个事件,然后事件就会调用一系列的函数去处理一些事情,当读到一个结束标签时,就会触发另一个事件。所以,我们写XML文档如果有格式错误的话,解析就会出错。
    这是一种流式处理,一边读一边解析,占用内存少。适用场景如下:
    1、对大型文件进行处理;
    2、只需要文件的部分内容,或者只需从文件中得到特定信息。
    3、想建立自己的对象模型的时候。

    from xml.sax import *
    
    class DengHandler(ContentHandler):
        def startDocument(self):
            print("----开始解析xml文档----")
        def endDocument(self):
            print("----xml文档解析完毕----")
        def startElement(self,name,attrs):
            if name == "author":
                print("名字:",attrs['name']," 日期:",attrs["birth"])
    
    parse("deng.xml",DengHandler())

    3、ElementTree(元素树)

    ElementTree就像一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少。

    因DOM需要将XML数据映射到内存中的树,一是比较慢,二是比较耗内存;而SAX流式读取XML文件,比较快,占用内存少,但需要用户实现回调函数(handler),所以一般选用ElementTree(元素树)。

    二、xml.etree.ElementTree解析XML

    <?xml version="1.0"?>
    <data>
        <country name="Liechtenstein">
            <rank updated="yes">2</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor name="Austria" direction="E"/>
            <neighbor name="Switzerland" direction="W"/>
        </country>
        <country name="Singapore">
            <rank updated="yes">5</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor name="Malaysia" direction="N"/>
        </country>
        <country name="Panama">
            <rank updated="yes">69</rank>
            <year>2011</year>
            <gdppc>13600</gdppc>
            <neighbor name="Costa Rica" direction="W"/>
            <neighbor name="Colombia" direction="E"/>
        </country>
    </data>

    1、遍历和查找xml

    xml协议在各个语言里的都是支持的,在python中可以用以下模块操作xml:

    # print(root.iter('year')) #全文搜索
    # print(root.find('country')) #在root的子节点找,只找一个
    # print(root.findall('country')) #在root的子节点找,找所有
    
    import xml.etree.ElementTree as ET
    
    tree = ET.parse("xmltest.xml")
    root = tree.getroot()
    print(root.tag)
    
    # 遍历xml文档
    for child in root:
        print('========>', child.tag, child.attrib, child.attrib['name'])
        for i in child:
            print(i.tag, i.attrib, i.text)
    
    # 只遍历year 节点
    for node in root.iter('year'):
        print(node.tag, node.text)
    

    2、修改和删除节点

    import xml.etree.ElementTree as ET
    
    tree = ET.parse("xmltest.xml")
    root = tree.getroot()
    
    # 修改
    for node in root.iter('year'):
        new_year = int(node.text) + 1
        node.text = str(new_year)
        node.set('updated', 'yes')
        node.set('version', '1.0')
    tree.write('test.xml')
    
    # 删除node
    for country in root.findall('country'):
        rank = int(country.find('rank').text)
        if rank > 50:
            root.remove(country)
    
    tree.write('output.xml')

    3、添加节点

    # 在country内添加(append)节点year2
    import xml.etree.ElementTree as ET
    
    tree = ET.parse("a.xml")
    root = tree.getroot()
    for country in root.findall('country'):
        for year in country.findall('year'):
            if int(year.text) > 2000:
                year2 = ET.Element('year2')
                year2.text = '新年'
                year2.attrib = {'update': 'yes'}
                country.append(year2)  # 往country节点下添加子节点
    
    tree.write('a.xml.swap')

    4、自己创建xml文档

    import xml.etree.ElementTree as ET
    
    new_xml = ET.Element("namelist")
    name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
    age = ET.SubElement(name, "age", attrib={"checked": "no"})
    sex = ET.SubElement(name, "sex")
    sex.text = '33'
    name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
    age = ET.SubElement(name2, "age")
    age.text = '19'
    
    et = ET.ElementTree(new_xml)  # 生成文档对象
    et.write("test.xml", encoding="utf-8", xml_declaration=True)
    
    ET.dump(new_xml)  # 打印生成的格式

    三、lxml.etree解析XML(推荐)

    lxml 是一种使用 Python 编写的库,可以迅速、灵活地处理 XML,支持 XPath

    lxml.etree和xml.etree.ElementTree两个的操作方式看起来差不多,但lxml要更好一些,使用更简洁。解析xml的时候,自动处理各种编码问题。而且它天生支持 XPath 1.0、XSLT 1.0、定制元素类。

    不过,lxml不是Python自带的标准库。需要自己安装,如下方式安装:

    $ pip install lxml

    from lxml import etree
     
     
    with open('./books.xml') as f:
        # print(f.read())
        text = f.read()
        html = etree.HTML(text.encode())
        # print(html)
        print(html.tag)
     
        print(html.xpath('//title'))  # 从根节点向下找任意层中title的节点
        print(html.xpath('//book//title'))
        print(html.xpath('//book[@id="bk102"]'))
        print(html.xpath('//book[@id]'))
        print(html.xpath('//@id'))  # 取回的是属性
        print(html.xpath('//*[@id]'))
        print(html.xpath('//bookstore/book[1]'))
        print(html.xpath('//bookstore/book[1]/@id'))  # ['bk101']
        print(html.xpath('//bookstore/book[last()]/@id'))  # last()为最后一个节点
        print(html.xpath('//*[contains(local-name(), "store")]'))  # [<Element bookstore at 0x2ce5648>]
        # local-name()为当前标签名字
        print(html.xpath('//bookstore/*'))  # 匹配根节点bookstore下的所有子节点,不递归;
        print(html.xpath('//*[@*]'))  # 匹配所有有属性的节点
        print(html.xpath('//@*'))  # 匹配所有属性
        print(html.xpath('//book/title|//book/price'))  # 匹配book节点下title标签或prices标签
        print(html.xpath('//book[position()=2]/@id'))  # ['bk102']
        print(html.xpath('//book[price > 40]/@id'))
        print(html.xpath('//book[1]/text()'))  # 匹配第一个book节点下所有文本子节点
        print(html.xpath('//book[1]//text()'))  # 匹配第一个book节点下所有文本节点
        print(html.xpath('//*[contains(@class,"even")]'))  # 匹配属性class中包含even字符串的节点

    可以使用 lxml 的 etree 库来进行爬取网站信息。

    从豆瓣电影中提取“本周口碑榜”:

    import requests
    from lxml import etree  # lxml 是c语言的库,效率非常高
    
    
    url = 'http://movie.douban.com'
    headers = {'User-agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) 
                Chrome/55.0.2883.75 Safari/537.36"}
    response = requests.get(url, headers=headers)
    
    with response:
        if response.status_code == 200:
            text = response.text
            html = etree.HTML(text)
            print(html.tag)
    
            titles = html.xpath('//div[@class="billboard-bd"]//a/text()')
            for title in titles:
                print(title)
    
            print("*********************")
  • 相关阅读:
    HDU-1275-两车追及或相遇问题(数学题目)
    hdu 2209 翻纸牌游戏
    HDU1217:Arbitrage(SPFA)
    HDU1548:A strange lift(Dijkstra或BFS)
    Hdu-2112 HDU Today (单源多点最短路——Dijsktra算法)
    HDU 3374 String Problem (KMP+最大最小表示)
    mysql导入的时候提示“1046-No Database selected”的解决办法
    win10开发环境下安装mongodb
    微服务项目开发学成在线_day01_CMS服务端开发
    springboot的http监控接口启动器的配置
  • 原文地址:https://www.cnblogs.com/springsnow/p/12524687.html
Copyright © 2011-2022 走看看