Python 网络抓取和文本挖掘-2 XML 和 JSON

XML和JSON是两个重要的网络数据交换标准。

1. XML (eXtensible Markup language, 可扩展标记语言)

    以下是书中附带的一个XML示例文档。

<?xml version="1.0" encoding="ISO-8859-1"?>
<bond_movies>
   <movie id="1">
      <name>Dr. No</name>
      <year>1962</year>
      <actors bond="Sean Connery" villain="Joseph Wiseman"/>
      <budget>1.1M</budget>
      <boxoffice>59.5M</boxoffice>
   </movie>
   <movie id="2">
      <name>Live and Let Die</name>
      <year>1973</year>
      <actors bond="Roger Moore" villain="Yaphet Kotto"/>
      <budget>7M</budget>
      <boxoffice>126.4M</boxoffice>
   </movie>
   <movie id="3">
      <name>Skyfall</name>
      <year>2012</year>
      <actors bond="Daniel Craig" villain="Javier Bardem"/>
      <budget>175M</budget>
      <boxoffice>1108.6M</boxoffice>
   </movie>      
</bond_movies>

    XML是纯文本格式,XML有一套语法规则和关机元素,一个XML文档永远 以声明XML文档的一行代码开头。

    XML文件必须有且仅有一个根元素,它包裹整个文档,如例子里的根元素<bond_movies> </bond_movies>。

    一个XML元素包括标签和内容,标签包括起始标签和终止标签,起始标签中和可以包含属性,属性和内容一样可以用来存放数据(信息),XML的属性值必须加引号  ;起始标签也可以用一个/,自己闭合,即不用终止标签;XML可以自己选择元素的名字,只要符合命名规则就可以(不能以数字或xml开头 、不能包括空格、区分大小写);内容中遇到特殊字符,须使用预先定义的转义字符串来代替,但如果数据中需要转义的字符太多时 ,可放到<! [CDATA[ ]] > 部件中,这样就不会被解析。。

     

     一个XML文件是一个有层次的树形结构,元素里还可以包含其它元素;元素可以嵌套,但必须是严格嵌套,不允许交叉嵌套。

     XML文档结构可以由用户自定义(标签名和层次结构的深度),用户可用文档类型定义(DTD)来描述;由于XML是可自定义的,就可能存在同样的元素名用于表达不同内容的情况,处理这种情况需要用到命名空间技术。

2. Python 解析XML文件

    1) DOM   

    定义一个类Movie存放电影信息,与例子中xml文件相对应。用xml.dom.minidom对文档进行解析,用到的方法包括:parse、hasChildNodes、getAttribute、getElementsBuTagName和data属性。需要注意的是要用nodeType==Node.ELEMENT_NODE进行判断过滤掉Text node。 

class Movie(object):
    def __init__(self, id=None, name=None, year=None, actors=None, budget=None, boxoffice=None):
        self.__id__ = id
        self.__name__ = name
        self.__year__ = year
        self.__actors__ = actors
        self.__budget__ = budget
        self.__boxoffice__ = boxoffice

    def get_id(self):
        return self.__id__

    def get_name(self):
        return self.__name__

    def get_year(self):
        return self.__year__

    def get_actors(self):
        return self.__actors__

    def get_budget(self):
        return self.__budget__

    def get_boxoffice(self):
        return self.__boxoffice__

    def to_txt(self,separator=','):
        bond = self.__actors__['bond']
        villain = self.__actors__['villain']
        line = str(self.__id__) + separator + \
               self.__name__ + separator + \
               str(self.__year__)  + separator + \
               self.__budget__ + separator + \
               self.__boxoffice__ + separator + \
               bond + separator + villain
        return line

from xml.dom import minidom as mdom
from xml.dom.minidom import Node


def get_movies_by_dom(xmlfile):
    movies = []
    doc = mdom.parse(xmlfile)
    root = None
    if doc.hasChildNodes():
        root = doc.childNodes[0]
    else:
        return movies

    for mve in root.childNodes:
        if mve.nodeType == Node.ELEMENT_NODE:
            id = mve.getAttribute('id')
            node = mve.getElementsByTagName("name")
            name = node[0].childNodes[0].data
            node = mve.getElementsByTagName("year")
            year = node[0].childNodes[0].data
            node = mve.getElementsByTagName("actors")
            bond = node[0].getAttribute('bond')
            villain = node[0].getAttribute('villain')
            actors = {'bond':bond, 'villain':villain}
            node = mve.getElementsByTagName("budget")
            budget = node[0].childNodes[0].data
            node = mve.getElementsByTagName("boxoffice")
            boxoffice = node[0].childNodes[0].data
            mv = Movie(id, name, year, actors, budget, boxoffice)
            movies.append(mv)
    return movies


if __name__ == '__main__':
    movies = get_movies_by_dom('bond.xml')
    for mv in movies:
        print mv.to_txt()

    2)SAX 

       dom解析xml是将整个文档树加载到内存中,因此在解析大文件时需要考虑使用sax进行解析。需要引入xml.sax中的parse函数和xml.sax.handler中的ContentHandler。MyContentHandler继承ContentHandler,定义__movies__(列表)、__movie__和__tag_name__三个属性,记录解析过程的状态信息。当startElemet的节点标签名为movie时创建一个movie对象,当endElemet的节点标签名为movie时,表示<movie>...</movie>完成了,将__movie__添加到__movies__列表。

# -*- coding:utf-8 -*-


class Movie(object):
    def __init__(self, id=None, name=None, year=None, actors=None, budget=None, boxoffice=None):
        self.__id__ = id
        self.__name__ = name
        self.__year__ = year
        self.__actors__ = actors
        self.__budget__ = budget
        self.__boxoffice__ = boxoffice

    def get_id(self):
        return self.__id__

    def get_name(self):
        return self.__name__

    def get_year(self):
        return self.__year__

    def get_actors(self):
        return self.__actors__

    def get_budget(self):
        return self.__budget__

    def get_boxoffice(self):
        return self.__boxoffice__

    def set_id(self, id):
        self.__id__ = id

    def set_name(self, name):
        self.__name__ = name

    def set_year(self, year):
        self.__year__ = year

    def set_actors(self, actors):
        self.__actors__ = actors

    def set_budget(self, budget):
        self.__budget__ = budget

    def set_boxoffice(self, boxoffice):
        self.__boxoffice__ = boxoffice



    def to_txt(self,separator=','):
        bond = self.__actors__['bond']
        villain = self.__actors__['villain']
        line = str(self.__id__) + separator + \
               self.__name__ + separator + \
               str(self.__year__)  + separator + \
               self.__budget__ + separator + \
               self.__boxoffice__ + separator + \
               bond + separator + villain
        return line


from xml  import sax
from xml.sax.handler import  ContentHandler


class MovieContentHandler(ContentHandler):
    def __init__(self):
        ContentHandler.__init__(self)
        self.__movies__ = []
        self.__movie__ = None
        self.__tag_name__ = None

    def get_movies(self):
        return self.__movies__

    def startDocument(self):
        self.__movies__ = []

    def endDocument(self):
        pass

    def startElement(self, name, attrs):
        if name == 'movie':
            self.__movie__ = Movie()
            self.__movie__.set_id(attrs['id'])
        elif name == 'actors':
            self.__movie__.set_actors({'bond': attrs['bond'], 'villain': attrs['villain']})
        self.__tag_name__ = name

    def endElement(self, name):
        if name == 'movie':
            self.__movies__.append(self.__movie__)
            self.__movie__ = None
        self.__tag_name__ = ''

    def characters(self, content):
        if self.__tag_name__ == 'name':
            self.__movie__.set_name(content)
        elif self.__tag_name__ == 'year':
            self.__movie__.set_year(content)
        elif self.__tag_name__ == 'budget':
            self.__movie__.set_budget(content)
        elif self.__tag_name__ == 'boxoffice':
            self.__movie__.set_boxoffice(content)


if __name__ == '__main__':
    mh = MovieContentHandler()
    sax.parse('bond.xml', mh)
    movies = mh.get_movies()
    for movie in movies:
        print movie.to_txt()



    3)ElementTree


import xml.etree.ElementTree as ET
def get_moives_by_et(xmlfile):
    movies = []
    doc = ET.parse(xmlfile)
    root = doc.getroot()
    for child in root:
        id = child.attrib['id']
        name = child.find('name').text
        year = child.find('year').text
        actors = child.find('actors').attrib
        budget = child.find('budget').text
        boxoffice = child.find('boxoffice').text
        movie = Movie(id, name, year, actors, budget, boxoffice)
        movies.append(movie)
    return movies


if __name__ == '__main__':
    movies = get_moives_by_et('bond.xml')
    for movie in movies:
        print movie.to_txt()

  3. JSON

JSON是一种源于JavaScript编程语言的数据格式,数据保持在键值对(Key/Value pair)里,键和值用冒号(:)隔开,键值对用逗号(,)隔开,不同类型的括号(大括号和方括号)能够描述层级结构。如果用Python的数据结构来描述的话,大括号({})对应字典,中括号([])对应列表。相比与XML,JSON不能添加注释、不能区分缺失的值和空值、没有命名空间、没有DTD。JSON是一种通用的数据交换标准。JSON在python 操作比较简单,掌握load、loads、dump和dumps几个方法就够用了,要注意的是ensuer_ascii 参数的使用。

import json
if __name__ == '__main__':
    f = open('indy.json')
    data = json.load(f)
    print json.dumps(data, ensure_ascii=False,)
    f.close()




    

  


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值