zoukankan      html  css  js  c++  java
  • xml 解析 python

    1 综述

    有很多种解析方法。

    (1)  DOM   缺点是:1 不能解析格式不正确或者不规则xml  2据说只能解析utf-8格式,非utf-8需要转码

      与SAX比较,DOM典型的缺点是比较慢,消耗更多的内存,因为DOM会将整个XML数读入内存中,并为树
    中的第一个节点建立一个对象。使用DOM的好处是你不需要对状态进行追踪,因为每一个节点都知道谁是它的
    父节点,谁是子节点。但是DOM用起来有些麻烦。


     

    Python中使用minidom解析xml,会遇到编码问题。minidom支持UTF-8的编码,对于其他的编码,必须进行转换,否则解析时会产生异常。下面以读取gb2312编码的xml文件为例。 

              sourceFile = codecs.open(sourceFilePath,mode='r')

               xmlContentStr = sourceFile.read()

               xmlContentStr = xmlContentStr.decode('gb2312').encode('utf-8')

               xmlContentStr =xmlContentStr.replace('encoding="gb2312"','encoding="utf-8"')

               sourceXML = minidom.parseString(xmlContentStr)



     (2) beatifulsoup    特点是可以处理格式不正确的html文档

    (3).SAX (simple API for XML )
           pyhton 标准库包含SAX解析器,SAX是一种典型的极为快速的工具,在解析XML时,不会占用大量内存。
    但是这是基于回调机制的,因此在某些数据中,它会调用某些方法进行传递。这意味着必须为数据指定句柄,
    以维持自己的状态,这是非常困难的。

     (4)   ElementTree(元素树)
         ElementTree就像一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少,这里主要
    介绍ElementTree。


    DOM(Document Object Model)

           与SAX比较,DOM典型的缺点是比较慢,消耗更多的内存,因为DOM会将整个XML数读入内存中,并为树
    中的第一个节点建立一个对象。使用DOM的好处是你不需要对状态进行追踪,因为每一个节点都知道谁是它的
    父节点,谁是子节点。但是DOM用起来有些麻烦。

    一 、xml.dom 解析XML的API描述


    minidom.parse(filename)
    加载读取XML文件

    doc.documentElement
    获取XML文档对象

    node.getAttribute(AttributeName)
    获取XML节点属性值

    node.getElementsByTagName(TagName)
    获取XML节点对象集合

    node.childNodes #返回子节点列表。

    node.childNodes[index].nodeValue
    获取XML节点值


    node.firstChild
    #访问第一个节点。等价于pagexml.childNodes[0]

     

    doc = minidom.parse(filename)
    doc.toxml('UTF-8')
    返回Node节点的xml表示的文本


    Node.attributes["id"]
    a.name #就是上面的 "id"
    a.value #属性的值 
    访问元素属性

    二、代码演示

    1、创建user.xml文件,添加XMl节点

    复制代码
    <?xml version="1.0" encoding="UTF-8" ?>
    <users>
    <user id="1000001">
    <username>Admin</username>
    <email>admin@live.cn</email>
    <age>23</age>
    <sex></sex>
    </user>
    <user id="1000002">
    <username>Admin2</username>
    <email>admin2@live.cn</email>
    <age>22</age>
    <sex></sex>
    </user>
    <user id="1000003">
    <username>Admin3</username>
    <email>admin3@live.cn</email>
    <age>27</age>
    <sex></sex>
    </user>
    <user id="1000004">
    <username>Admin4</username>
    <email>admin4@live.cn</email>
    <age>25</age>
    <sex></sex>
    </user>
    <user id="1000005">
    <username>Admin5</username>
    <email>admin5@live.cn</email>
    <age>20</age>
    <sex></sex>
    </user>
    <user id="1000006">
    <username>Admin6</username>
    <email>admin6@live.cn</email>
    <age>23</age>
    <sex></sex>
    </user>
    </users>
    复制代码

    2、Demo.py解析user.xml文档数据

    复制代码
    # -*- coding:utf-8 -*-
    """
    * User: lhj588
    * Date: 11-11-9
    * Time: 13:20
    * Desc:
    """
    from xml.dom import minidom


    def get_attrvalue(node, attrname):
    return node.getAttribute(attrname) if node else ''

    def get_nodevalue(node, index = 0):
    return node.childNodes[index].nodeValue if node else ''

    def get_xmlnode(node,name):
    return node.getElementsByTagName(name) if node else []

    def xml_to_string(filename='user.xml'):
    doc = minidom.parse(filename)
    return doc.toxml('UTF-8')

    def get_xml_data(filename='user.xml'):
    doc = minidom.parse(filename)
    root = doc.documentElement

    user_nodes = get_xmlnode(root,'user')
    user_list=[]
    for node in user_nodes:
    user_id = get_attrvalue(node,'id')
    node_name = get_xmlnode(node,'username')
    node_email = get_xmlnode(node,'email')
    node_age = get_xmlnode(node,'age')
    node_sex = get_xmlnode(node,'sex')

    user_name =get_nodevalue(node_name[0]).encode('utf-8','ignore')
    user_email = get_nodevalue(node_email[0]).encode('utf-8','ignore')
    user_age = int(get_nodevalue(node_age[0]))
    user_sex = get_nodevalue(node_sex[0]).encode('utf-8','ignore')
    user = {}
    user['id'] , user['username'] , user['email'] , user['age'] , user['sex'] = (
    int(user_id), user_name , user_email , user_age , user_sex
    )
    user_list.append(user)
    return user_list

    def test_xmltostring():
    print xml_to_string()

    def test_laod_xml():
    user_list = get_xml_data()
    for user in user_list :
    #print user['sex']
    print '-----------------------------------------------------'
    if user:
    user_str='编 号:%d 用户名:%s 性 别:%s 年 龄:%s 邮 箱:%s ' % (int(user['id']) , user['username'], user['sex'] , user['age'] , user['email'])
    print user_str
    print '====================================================='

    if __name__ == "__main__":
    test_xmltostring()
    test_laod_xml()
    复制代码


    3、测试效果

      A、测试toxml

       

    demo.py 文件中修改成
    if __name__ == "__main__":
    test_xmltostring()
     执行打印结果:
    复制代码
    <user id="1000001">
    <username>Admin</username>
    <email>admin@live.cn</email>
    <age>23</age>
    <sex></sex>
    </user>
    <user id="1000002">
    <username>Admin2</username>
    <email>admin2@live.cn</email>
    <age>22</age>
    <sex></sex>
    </user>
    <user id="1000003">
    <username>Admin3</username>
    <email>admin3@live.cn</email>
    <age>27</age>
    <sex></sex>
    </user>
    <user id="1000004">
    <username>Admin4</username>
    <email>admin4@live.cn</email>
    <age>25</age>
    <sex></sex>
    </user>
    <user id="1000005">
    <username>Admin5</username>
    <email>admin5@live.cn</email>
    <age>20</age>
    <sex></sex>
    </user>
    <user id="1000006">
    <username>Admin6</username>
    <email>admin6@live.cn</email>
    <age>23</age>
    <sex></sex>
    </user>
    复制代码
    B、测试解析XML
    demo.py 文件中修改成

       if __name__ == "__main__": 
            test_laod_xml()

    执行打印出结果:
    复制代码
    -----------------------------------------------------
    编 号:1000001
    用户名:Admin
    性 别:男
    年 龄:23
    邮 箱:admin@live.cn

    =====================================================
    -----------------------------------------------------
    编 号:1000002
    用户名:Admin2
    性 别:男
    年 龄:22
    邮 箱:admin2@live.cn

    =====================================================
    -----------------------------------------------------
    编 号:1000003
    用户名:Admin3
    性 别:男
    年 龄:27
    邮 箱:admin3@live.cn

    =====================================================
    -----------------------------------------------------
    编 号:1000004
    用户名:Admin4
    性 别:女
    年 龄:25
    邮 箱:admin4@live.cn

    =====================================================
    -----------------------------------------------------
    编 号:1000005
    用户名:Admin5
    性 别:男
    年 龄:20
    邮 箱:admin5@live.cn

    =====================================================
    -----------------------------------------------------
    编 号:1000006
    用户名:Admin6
    性 别:女
    年 龄:23
    邮 箱:admin6@live.cn

    =====================================================

    转自:http://www.cnblogs.com/lhj588/archive/2011/11/09/2242483.html

    3  Beautiful Soup

    Beautiful Soup 是用 Python 写的一个 HTML/XML 的解析器,它可以很好的处理不规范标记并生成剖析树。通常用来分析爬虫抓取的web文档。对于 不规则的 Html文档,也有很多的补全功能,节省了开发者的时间和精力。

    Beautiful Soup 的官方文档齐全,将官方给出的例子实践一遍就能掌握。官方英文文档中文文档

    一 安装 Beautiful Soup

    安装 BeautifulSoup 很简单,下载 BeautifulSoup  源码。解压运行

    python setup.py install 即可。

    测试安装是否成功。键入 import BeautifulSoup 如果没有异常,即成功安装

    二 使用 BeautifulSoup

    1. 导入BeautifulSoup ,创建BeautifulSoup 对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    fromBeautifulSoupimportBeautifulSoup          # HTML
    fromBeautifulSoupimportBeautifulStoneSoup     # XML
    importBeautifulSoup                             # ALL
                                                                                                   
    doc=[
        '<html><head><title>Page title</title></head>',
        '<body><p id="firstpara" align="center">This is paragraph <b>one</b>.',
        '<p id="secondpara" align="blah">This is paragraph <b>two</b>.',
        '</html>'
    ]
    # BeautifulSoup 接受一个字符串参数
    soup=BeautifulSoup(''.join(doc))

    2. BeautifulSoup对象简介

    用BeautifulSoup 解析 html文档时,BeautifulSoup将 html文档类似 dom文档树一样处理。BeautifulSoup文档树有三种基本对象。

    2.1. soup BeautifulSoup.BeautifulSoup

    1
    2
    type(soup)
    <class'BeautifulSoup.BeautifulSoup'>

    2.2. 标记 BeautifulSoup.Tag

    1
    2
    type(soup.html)
    <class'BeautifulSoup.Tag'>

    2.3 文本 BeautifulSoup.NavigableString

    1
    2
    type(soup.title.string)
    <class'BeautifulSoup.NavigableString'>

    3. BeautifulSoup 剖析树

    3.1 BeautifulSoup.Tag对象方法

    获取 标记对象(Tag)

    标记名获取法 ,直接用 soup对象加标记名,返回 tag对象.这种方式,选取唯一标签的时候比较有用。或者根据树的结构去选取,一层层的选择

    1
    2
    3
    4
    5
    6
    7
    >>> html = soup.html
    >>> html
    <html><head><title>Page title</title></head><body><pid="firstpara"align="center">This is paragraph<b>one</b>.</p><pid="secondpara"align="blah">This is paragraph<b>two</b>.</p></body></html>
    >>> type(html)
    <class'BeautifulSoup.Tag'>
    >>> title = soup.title
    <title>Page title</title>

    content方法

    content方法 根据文档树进行搜索,返回标记对象(tag)的列表

    1
    2
    >>> soup.contents
    [<html><head><title>Page title</title></head><body><pid="firstpara"align="center">Thisisparagraph<b>one</b>.</p><pid="secondpara"align="blah">Thisisparagraph<b>two</b>.</p></body></html>]
    1
    2
    3
    4
    5
    6
    >>> soup.contents[0].contents
    [<head><title>Page title</title></head>, <body><p id="firstpara"align="center">Thisisparagraph<b>one</b>.</p><pid="secondpara"align="blah">Thisisparagraph<b>two</b>.</p></body>]
    >>>len(soup.contents[0].contents)
    2
    >>>type(soup.contents[0].contents[1])
    <class'BeautifulSoup.Tag'>

    使用contents向后遍历树,使用parent向前遍历树

    next 方法

    获取树的子代元素,包括 Tag 对象 和 NavigableString 对象。。。

    1
    2
    3
    4
    >>> head.next
    <title>Page title</title>
    >>> head.next.next
    u'Page title'
    1
    2
    3
    4
    5
    >>> p1 =soup.p
    >>> p1
    <pid="firstpara"align="center">Thisisparagraph<b>one</b>.</p>
    >>> p1.next
    u'This is paragraph'

    nextSibling 下一个兄弟对象 包括 Tag 对象 和 NavigableString 对象

    1
    2
    3
    4
    >>> head.nextSibling
    <body><pid="firstpara"align="center">Thisisparagraph<b>one</b>.</p><pid="secondpara"align="blah">Thisisparagraph<b>two</b>.</p></body>
    >>> p1.next.nextSibling
    <b>one</b>

    与 nextSibling 相似的是 previousSibling,即上一个兄弟节点。

    replacewith方法

    将对象替换为,接受字符串参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> head =soup.head
    >>> head
    <head><title>Page title</title></head>
    >>> head.parent
    <html><head><title>Page title</title></head><body><pid="firstpara"align="center">Thisisparagraph<b>one</b>.</p><pid="secondpara"align="blah">Thisisparagraph<b>two</b>.</p></body></html>
    >>> head.replaceWith('head was replace')
    >>> head
    <head><title>Page title</title></head>
    >>> head.parent
    >>> soup
    <html>head was replace<body><p id="firstpara"align="center">Thisisparagraph<b>one</b>.</p><pid="secondpara"align="blah">Thisisparagraph<b>two</b>.</p></body></html>
    >>>

    搜索方法

    搜索提供了两个方法,一个是 find,一个是findAll。这里的两个方法(findAll和 find)仅对Tag对象以及,顶层剖析对象有效,但 NavigableString不可用。

    findAll(nameattrsrecursivetextlimit**kwargs)

    接受一个参数,标记名

    寻找文档所有 P标记,返回一个列表

    1
    2
    3
    4
    >>> soup.findAll('p')
    [<pid="firstpara"align="center">Thisisparagraph<b>one</b>.</p>, <p id="secondpara"align="blah">Thisisparagraph<b>two</b>.</p>]
    >>>type(soup.findAll('p'))
    <type'list'>

    寻找 id="secondpara"的 p 标记,返回一个结果集

    1
    2
    3
    >>> pid =type(soup.findAll('p',id='firstpara'))
    >>> pid
    <class'BeautifulSoup.ResultSet'>

    传一个属性或多个属性对

    1
    2
    3
    4
    5
    >>> p2 =soup.findAll('p',{'align':'blah'})
    >>> p2
    [<pid="secondpara"align="blah">Thisisparagraph<b>two</b>.</p>]
    >>>type(p2)
    <class'BeautifulSoup.ResultSet'>

    利用正则表达式

    1
    2
    >>> soup.findAll(id=re.compile("para$"))
    [<pid="firstpara"align="center">Thisisparagraph<b>one</b>.</p>, <p id="secondpara"align="blah">Thisisparagraph<b>two</b>.</p>]

    读取和修改属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> p1 =soup.p
    >>> p1
    <pid="firstpara"align="center">Thisisparagraph<b>one</b>.</p>
    >>> p1['id']
    u'firstpara'
    >>> p1['id']='changeid'
    >>> p1
    <pid="changeid"align="center">Thisisparagraph<b>one</b>.</p>
    >>> p1['class']='new class'
    >>> p1
    <pid="changeid"align="center"class="new class">Thisisparagraph<b>one</b>.</p>
    >>>

    剖析树基本方法就这些,还有其他一些,以及如何配合正则表达式。具体请看官方文档

     

    3.2 BeautifulSoup.NavigableString对象方法

    NavigableString  对象方法比较简单,获取其内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> soup.title
    <title>Page title</title>
    >>> title =soup.title.next
    >>> title
    u'Page title'
    >>>type(title)
    <class'BeautifulSoup.NavigableString'>
    >>> title.string
    u'Page title'

     

    至于如何遍历树,进而分析文档,已经 XML 文档的分析方法,可以参考官方文档。


    转自:http://rsj217.diandian.com/post/2012-11-01/40041235132

  • 相关阅读:
    sql中的不常见查询
    sql中的常见报错;
    wcf_first
    均方值-数学期望-方差
    转:模块度(Modularity)与Fast Newman算法讲解与代码实现
    转:社区发现评估指标-NMI
    转:模块度(Modularity)与Fast Newman算法讲解与代码实现
    转:聚类评价指标
    转:聚类︱python实现 六大 分群质量评估指标(兰德系数、互信息、轮廓系数)
    转:用K-Means聚类分析做客户分群
  • 原文地址:https://www.cnblogs.com/catkins/p/5270448.html
Copyright © 2011-2022 走看看