您的位置:首页 > Web前端 > JavaScript

解析Json数据的几种方法

2018-01-06 20:55 411 查看
Json解析
印象中,json都长得很乖巧,一个属性对应一个值,
key-value
,某天你的leader让你去爬数据,你爬到了这样的数据:

var hei ha {‘error’: 0, ‘errorMsg’: ‘SUCCESS’, uptime: ‘20180105121318000’, ‘preClose’: 33.459999084473, tick: [{‘date’: ‘20180105’, ‘time’: 113002000, ‘price’: 33.990001678467, ‘volume’: 37100, ‘bsflag’: “B”, “ccl”: 0}…]};

既有单引号又有双引号,且单引号在属性和值之间交叉,怎么搞?replace?sub?再一看一个词包含另一个词,如,uptime与time,error与errorMsg,再替换?还有很多呢?心态要崩。。。。

这就崩了?实际的爬虫中很多大网站都是这样的json串,如,百度,新浪等。

不怕,总会有人帮我们写好工具的[奸诈笑],只需import就好了,实在满足不了个性化需求就改改源码。。。

以下将介绍解析json的四个库;

完整示例代码:完整示例下载

环境:

OS:win10;

Python:3.6;

一、内置json模块
[b]♣ 内置json的简介[/b]

如果你是用Anaconda环境,会自带json模块。

自带的json模块对json数据的格式要求比较严格,要求:

必须出入str字段;

属性必须使用双引号
""
括起来,如,
{["key": value, "a": b]}


[b]♣ json模块的使用[/b]

示例1.1

使用标准数据格式。

import json
str1 = 'jQuery180({"errorNo": 0, "errorMsg": "SUCCESS", "latestTimelineStamp": "20180105121318000", "preClose": 33.459999084473, "tick": [{"date": 20180105, "time": 113002000, "price": 33.990001678467, "volume": 37100, "bsflag": "B", "ccl": 0}]});'
# 去除两边的无用数据
json_str1 = str1.strip("jQuery180();")
# 解析json字符串
json_data1 = json.loads(json_str1)
print("解析后的json数据:\n", json_data1)
print("取json数据:\n", json_data1['tick'])


运行结果:

解析后的json数据:
{'errorNo': 0, 'errorMsg': 'SUCCESS', 'latestTimelineStamp': '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}
取json数据:
[{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]


示例1.2

当数据中出现单引号时。

import json
str1 = "{'errorNo': 0, 'errorMsg': 'SUCCESS', 'latestTimelineStamp': '20180105
cfc3
121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105}]}"
# 解析json字符串
json_data1 = json.loads(str1)
print("解析后的json数据:\n", json_data1)
print("取json数据:\n", json_data1['tick'])


运行结果:

JSONDecodeError                           Traceback (most recent call last)
...
JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)


报错!

属性名称没有使用双引号,所以,并不好用嘛。下面介绍另一个json解析神器-Demjson。Demjson就可以自适应的解决这些问题。

二、Demjson模块
[b]♣ Demjson模块简介[/b]

Demjson模块,由Deron Meranda开发,demjson主页

demjson使用标准python库,不用再安装其他依赖模块;

demjson读取数据依然使用冒号做识别,要求json串中的引号必须成对出现。

[b]♣ demjson安装[/b]

简易安装:

pip install demjson


源码安装:

下载demjson:demjson下载地址

cd demjson文件目录


python setup.py install


[b]♣ demjson使用[/b]

示例2.1

带有单引号的json串;

import demjson
str1 = "{'errorNo': 0, 'errorMsg': 'SUCCESS', 'latestTimelineStamp': '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}"
json_data1 = demjson.decode(str1)
print("解析后的json数据:\n", json_data1)
print("取json数据:\n", json_data1['tick'])


运行结果:

解析后的json数据:
{'errorNo': 0, 'errorMsg': 'SUCCESS', 'latestTimelineStamp': '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}
取json数据:
[{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]


成功搞定单引号。

示例2.2

字符串中属性或值带有单引号或双引号,且还有的属性不带有引号。

import demjson
str1 = '''{'errorNo': 0, errorMsg: 'SUCCESS', "latestTimelineStamp": '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}'''
json_data1 = demjson.decode(str1)
print("解析后的json数据:\n", json_data1)
print("取json数据:\n", json_data1['tick'])


运行结果:

解析后的json数据:
{'errorNo': 0, 'errorMsg': 'SUCCESS', 'latestTimelineStamp': '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}
取json数据:
[{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]


面对单引号,双引号,没有引号,demjson依然能够解决问题,Damn good~ 哈哈♥♥

示例2.3

当json串中包含其他情况呢?如本文开头的那种糟糕情况,如,当json数据前包含一段其他代码,这可以使用strip去除,缺少单引号或双引号,demjson行吗?

import demjson
str1 = '''{errorNo': 0, errorMsg: 'SUCCESS', "latestTimelineStamp": '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}'''
json_data1 = demjson.decode(str1)
print("解析后的json数据:\n", json_data1)
print("取json数据:\n", json_data1['tick'])


运行结果:

解析后的json数据:
Traceback (most recent call last):
...
demjson.JSONDecodeError: Missing value for object property, expected ":"


demjson以冒号做分割,去匹配单引号或双引号识别属性和值;

当没有匹配上时,以冒号作为分割得到属性和值;

而面对这样的状况,demjson也是心累了,无能为力了,爱不动了…难道就到这里了吗?不,还有jsonlike,依然稀饭内。

三、jsonlike模块
[b]♣ 发现jsonlike模块[/b]

诚然,当json数据前包含一段其他代码,这可以使用strip去除,但如本文开头的那种糟糕情况,如,缺少单引号或双引号,替换?当json串很大且情况复杂时要替换到何时?发现错就替换一次?当你使用网站API满怀兴奋地拿到10000多条json数据时,你确定要自己替换???

曾几何时,当我碰到这种情况时,我选择了替换,那是个心酸心累的夜晚,一个人,替换这见鬼的不规则的字符,心中无数cn马奔腾。。。

去Google一下“the most powerful modules for json in python”,然而,并没有得到什么,试着搜索了其他,也没有什么,自己在pypi上搜json,发现一个玩意叫做
jsonlike
,听名字感觉这就是我要的啊,像json?ok,试试。

[b]♣ jsonlike简介[/b]

jsonlike由Shaun Viguerie开发,github地址

功能强大,可解析 类json串;

但需要安装依赖模块:

demjson==2.2.4

unwrapper==1.0.0

nose

sure

pyyaml

[b]♣ 安装jsonlike模块[/b]

简易安装:

pip install jsonlike


源码安装:

下载demjson:demjson下载地址

cd demjson文件目录


python setup.py install


注意安装依赖模块。

[b]♣ 使用jsonlike[/b]

示例3.1

字符串中属性或值带有单引号或双引号,且还有的属性不带有引号。此时,使用json.loads()会调用demjson。

import jsonlike
str1 = '''{'errorNo': 0, errorMsg: 'SUCCESS', "latestTimelineStamp": '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}'''
json_data1 = jsonlike.loads(str1)
print("解析后的json数据:\n", json_data1)
print("取json数据:\n", json_data1['tick'])


运行结果:

解析后的json数据:
{'errorNo': 0, 'errorMsg': 'SUCCESS', 'latestTimelineStamp': '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}
取json数据:
[{'date': 20180105, 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]


可以看出,jsonlike能够正确处理。

示例3.2

json串各种糟糕,且单引号和双引号不对称,json数据外还有一些无用字符;这时,jsonlike.loads()便无能为力,需要使用另一个方法unwrap_and_load。

import jsonlike
str1 = '''var hei ha {'error': 0, 'errorMsg': 'SUCCESS', uptime: '20180105121318000', 'preClose': 33.459999084473, tick: [{'date': '20180105', 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': "B", "ccl": 0}]};'''
json_data1 = jsonlike.unwrap_and_load(str1)
print("解析后的json数据:\n", json_data1)
print("取json数据:\n", json_data1['tick'])


运行结果:

解析后的json数据:
{'error': 0, 'errorMsg': 'SUCCESS', 'uptime': '20180105121318000', 'preClose': 33.459999084473, 'tick': [{'date': '20180105', 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]}
取json数据:
[{'date': '20180105', 'time': 113002000, 'price': 33.990001678467, 'volume': 37100, 'bsflag': 'B', 'ccl': 0}]


可以看出,’jsonlike.unwrap_and_load()`帮我们做了很多脏活累活,Damn Damn good~

总结
[b]♣ 选择合适的处理Json数据的方式[/b]

值得注意的是三个模块在适用性和效率上各不相同:

1. json处理规整数据的效率较高;

2. demjson处理json数据效率不高,甚至是慢;

3. jsonlike处理效率与demjson类似;

此外,还有simplejson等模块,再讲simplejson有点不伦不类,如果simplejson不引入C库,那么效率也是较差的。

json数据适用模块
格式规整内置json
格式不规整,但引号无缺失demjson
格式不规整,引号缺失,json串前后有其他字符jsonlike
本文完整示例:完整示例下载

能力有限,欢迎指错交流;

欢迎关注个人微信公众号WaltSmithML或新浪微博WaltSmith,公众号提供机器学习、深度学习、Hadoop、Spark、Python、数学知识等免费视频教程。本人主要方向为机器学习和深度学习。非常欢迎一起交流学习哈,除了学习,还可免费帮忙download论文或者书籍哈==============

♥♥♥微信公众号♥♥♥

♥♥♥♥

♥♥新浪微博♥♥
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: