对于非编程人员来说,Python很大的一个用途,是从网上爬取各种各样的数据,那么必定会遇到需要解析HTML、XML和Json数据的问题。那么什么是解析呢?简单地说,就是将这些数据转化成编程语言中更易于使用的数据结构,比如转化成python中的字典。当解析完成之后,我们也常常使用某个格式比如CSV去保存,以便使用某个工具比如excel查看。因此,今天打算分享如何处理csv和json格式的数据,为了内容不过于冗长,HTML和XML数据的解析会留在下一片文章讲。
csv数据解析
csv数据一般是以都逗号分隔的文本数据。csv模块提供了两个很重要的类DictReader和DictWriter,分别用于从CSV文件读取数据和往文件写入数据。下面将举例子说明它们的用法。
首先,我们从网上爬取一个CSV文件,比如说,股票中航电子(600372)的历史交易数据:
>>> import urllib2
>>> url = 'http://ichart.finance.yahoo.com/table.csv?s={code}'
>>> url_ = url.format(code='600372.SS')
>>> content = urllib2.urlopen(url_).read()
>>> len(content)
213513
>>> with open("600372.csv", "wb") as f:
... f.write(content)
这样我们得到了一个名为600372.csv的数据文件,文件的内容看起来是这样子的:
$ head -5 600372.csv
Date,Open,High,Low,Close,Volume,Adj Close
2017-04-17,20.01,20.10,19.42,19.64,9288600,19.64
2017-04-14,20.36,20.54,20.00,20.06,11605500,20.06
2017-04-13,20.25,20.54,20.11,20.30,9833900,20.30
2017-04-12,20.52,20.80,20.22,20.45,19406000,20.45
从首行可以看出,这个文件包含了5列,分别是交易日期、开盘价、最高价、最低价、收盘价、交易量和调整后的收盘价。
读取
我们可以使用csv模块对这个文件进行读取。首先导入csv模块:
>>> import csv
然后读取文件:
>>> reader = csv.DictReader(open("600372.csv", "rb"))
通过reader我们可以读取文件的每一行,现在我们使用next函数读取其中的一行看看是什么结果:
>>> row = next(reader)
>>> row
{'Volume': '9288600', 'Adj Close': '19.64', 'High': '20.10', 'Low': '19.42', 'Date': '2017-04-17', 'Close': '19.64', 'Open': '20.01'}
可以看到是一个python字典,因此我们可以通过列名获取对应的数值:
>>> row['Volume']
'9288600'
>>> row.get('Close')
'19.64'
>>> row.keys()
['Volume', 'Adj Close', 'High', 'Low', 'Date', 'Close', 'Open']
你可以使用for去遍历所有的行:
>>> rows =[ row for row in reader ]
>>> len(rows)
3860
一共是3860行。
写入
如果我们想把某些数据,以CSV格式保存起来,我们可以使用csv的DictWriter类,它提供了下面三个方法:
writeheader #写进行首
writerow #写进一行
writerows #写进多行
分别用于往文件写入由列名构成的首行、写进一行和一次写入多行。
比如说,我们想从上面的文件中,提取交易日期、开盘价、最高价、最低价和收盘价,并且保存为CSV文件600372_price.csv:
>>> cols = ['Date', 'Open', 'High', 'Low', 'Close']
>>> f = open("600372_price.csv", "wb")
>>> writer = csv.DictWriter(f, cols)
我们得先调用writeheader写进由列名构成的首行:
>>> writer.writeheader()
接下来,写入其他数据行,比如可以从上面的rows挑取前5行,然后使用字典的pop办法把Volume和Adj Close这两行删除:
>>> rows_ = rows[0:5]
>>> rows_
[{'Volume': '11605500', 'Adj Close': '20.06', 'High': '20.54', 'Low': '20.00', 'Date': '2017-04-14', 'Close': '20.06', 'Open': '20.36'}, {'Volume': '9833900', 'Adj Close': '20.30', 'High': '20.54', 'Low': '20.11', 'Date': '2017-04-13', 'Close': '20.30', 'Open': '20.25'}, {'Volume': '19406000', 'Adj Close': '20.45', 'High': '20.80', 'Low': '20.22', 'Date': '2017-04-12', 'Close': '20.45', 'Open': '20.52'}, {'Volume': '32033200', 'Adj Close': '20.55', 'High': '20.88', 'Low': '19.43', 'Date': '2017-04-11', 'Close': '20.55', 'Open': '19.50'}, {'Volume': '6355000', 'Adj Close': '19.49', 'High': '19.78', 'Low': '19.43', 'Date': '2017-04-10', 'Close': '19.49', 'Open': '19.78'}]
>>> for row_ in rows_:
... row_.pop("Volume")
... row_.pop("Adj Close")
...
'11605500'
'20.06'
'9833900'
'20.30'
'19406000'
'20.45'
'32033200'
'20.55'
'6355000'
'19.49'
查看经过处理后的那5行数据:
>>> rows_
[{'High': '20.54', 'Low': '20.00', 'Date': '2017-04-14', 'Close': '20.06', 'Open': '20.36'},
{'High': '20.54', 'Low': '20.11', 'Date': '2017-04-13', 'Close': '20.30', 'Open': '20.25'},
{'High': '20.80', 'Low': '20.22', 'Date': '2017-04-12', 'Close': '20.45', 'Open': '20.52'},
{'High': '20.88', 'Low': '19.43', 'Date': '2017-04-11', 'Close': '20.55', 'Open': '19.50'},
{'High': '19.78', 'Low': '19.43', 'Date': '2017-04-10', 'Close': '19.49', 'Open': '19.78'}]
如果一次只需要写入一行,可以调用writerow,比如rows_的第一行:
>>> writer.writerow(rows_[0])
如果一次需要写入多行,可以调用writerows,比如rows_的最后4行:
>>> writer.writerows(rows_[1:5])
>>> f.flush()
>>> f.close()
$ cat 600372_price.csv
Date,Open,High,Low,Close
2017-04-14,20.36,20.54,20.00,20.06
2017-04-13,20.25,20.54,20.11,20.30
2017-04-12,20.52,20.80,20.22,20.45
2017-04-11,19.50,20.88,19.43,20.55
2017-04-10,19.78,19.78,19.43,19.49
Json数据解析
Json (JavaScript Object Notation)是一种轻量级的数据交换格式,在ajax技术中被大量用于浏览器和web服务器之间交换数据。
比如说,我们可以通过urllib2获取股票600372过去5个交易日平均每分钟的成交量:
>>> import urllib2
>>> rsp = urllib2.urlopen("http://finance.sina.com.cn/realstock/lastfive/sh600372.js?_=18").read()
>>> rsp
'var lastfivesh600372 = {"lastfive":[{"d":"2017-04-18","c":"684.73"},{"d":"2017-04-17","c":"660.28"},{"d":"2017-04-14","c":"634.68"},{"d":"2017-04-13","c":"601.49"},{"d":"2017-04-12","c":"509.16"}]}\n/* SH5/ham/vo6kcdzbT7zzLiGYatY/MRHKyZKrdIyDbRf8yfgSKBX2ZSu81ygGR0VHZtPf91SELL4iEL5WOqRJyOS6T1O7DF9rX+r1Yard5UuwWQoRRmvLCZdnqusDGBdpYTDNVJsZrlC3retd+Io3De38n/9TiuEwjEq09jL7zwJCuxR7rBgx4U+TY6GBUv/muLhrbGO9SBw= */'
我们可以提取其中格式为json的那段字符串:
>>> rsp_ = rsp.split('=')[1].split('\n')[0].strip()
>>> rsp_
'{"lastfive":[{"d":"2017-04-18","c":"684.73"},{"d":"2017-04-17","c":"660.28"},{"d":"2017-04-14","c":"634.68"},{"d":"2017-04-13","c":"601.49"},{"d":"2017-04-12","c":"509.16"}]}'
接着导入json模块处理上面这段字符串:
>>> import json
json模块提供4个办法实现json数据格式和python字典互相转换:
loads
dumps
load
dump
首先,调用json的loads方法,可以把JSON格式的字符串转换成python字典:
>>> data = json.loads(rsp_)
>>> data
{u'lastfive': [{u'c': u'684.73', u'd': u'2017-04-18'}, {u'c': u'660.28', u'd': u'2017-04-17'}, {u'c': u'634.68', u'd': u'2017-04-14'}, {u'c': u'601.49', u'd': u'2017-04-13'}, {u'c': u'509.16', u'd': u'2017-04-12'}]}
>>> data['lastfive']
[{u'c': u'684.73', u'd': u'2017-04-18'}, {u'c': u'660.28', u'd': u'2017-04-17'}, {u'c': u'634.68', u'd': u'2017-04-14'}, {u'c': u'601.49', u'd': u'2017-04-13'}, {u'c': u'509.16', u'd': u'2017-04-12'}]
>>> date1 = data['lastfive'][0]
>>> date1
{u'c': u'684.73', u'd': u'2017-04-18'}
>>> date1['c']
u'684.73'
其次,调用json的dumps方法,可以把python字典转换成JSON格式的字符串:
>>> json.dumps(data)
'{"lastfive": [{"c": "684.73", "d": "2017-04-18"}, {"c": "660.28", "d": "2017-04-17"}, {"c": "634.68", "d": "2017-04-14"}, {"c": "601.49", "d": "2017-04-13"}, {"c": "509.16", "d": "2017-04-12"}]}'
对应于loads和dumps,另外两个方法load和dump,分别用于从文件中读取json数据和往文件中写入json数据,比如说你想把一个python字典以json字符串的形式保存到文件中:
>>> with open("600372.json", "wb") as f:
... json.dump(data, f)
现在来看一下文件600372.json的内容:
$ cat 600372.json
{"lastfive": [{"c": "684.73", "d": "2017-04-18"}, {"c": "660.28", "d": "2017-04-17"}, {"c": "634.68", "d": "2017-04-14"}, {"c": "601.49", "d": "2017-04-13"}, {"c": "509.16", "d": "2017-04-12"}]}
反过来,如果你想把json数据从文件中读取出来,并且转换成python字典:
>>> with open("600372.json", "rb") as f:
... print json.load(f)
...
{u'lastfive': [{u'c': u'684.73', u'd': u'2017-04-18'}, {u'c': u'660.28', u'd': u'2017-04-17'}, {u'c': u'634.68', u'd': u'2017-04-14'}, {u'c': u'601.49', u'd': u'2017-04-13'}, {u'c': u'509.16', u'd': u'2017-04-12'}]}
最后使用csv模块将数据保存到CSV文件中:
>>> columns = ['d', 'c']
>>> fp = open("lastfive.csv", "wb")
>>> wt = csv.DictWriter(fp, columns)
>>> wt.writeheader()
>>> wt.writerows(data['lastfive'])
>>> fp.close()
检查输出结果:
$ cat lastfive.csv
d,c
2017-04-18,684.73
2017-04-17,660.28
2017-04-14,634.68
2017-04-13,601.49
2017-04-12,509.16
以上为原创文章,欢迎大家的评论和交流!