专栏首页数据小魔方左手用R右手Python系列之——json序列化与反序列化

左手用R右手Python系列之——json序列化与反序列化

json格式数据作为如今越来越流行的数据交换格式,几乎已经成为web端数据交互的标准,主流的数据科学语言R,Python都中都有非常完善的半结构化数据与json数据进行通讯。本篇文章将会通过简单案例介绍R语言与Python中与json数据进行序列化与反序列化的常用函数。

json的数据以键值对形式存在,在R语言中,符合此标准的就是基础数据对象中的list(严格来说,R语言中所有数据对象都可以表示为list,但是可以保存递归结构只有list一种)。

在R语言中,涉及到json数据处理的,主要是list转换为json和json转换为普通的list。前者被称为序列化,后者被称为反序列化。(也可以理解为编码或者解码的过程)虽然R语言中有三个包可以处理json序列化与反序列化过程(rjson、RJSONIO、jsonlite),但是实际应用最多,功能相对完善的,要数最后一个jsonlite包,这里仅以jsonlite包为例进行讲解。

library("jsonlite")
library("magrittr")
library("RCurl")
mylist <- list(
             "name"="Raiders of the Lost Ark",
             "year"=1981,
             "actors"=list(
             "Indiana Jones" = "Harrison Ford",
             "Dr. Ren Belloq"= "Paul Freeman" 
                      ),
             "producers"= c("Frank Marshall", "George Lucas", "Howard Kazanjian"),
             "budget" = 18000000,
            "academy_award_ve"= TRUE
            )

jsonlite包中的toJSON函数负责将R语言中的数据对象(主要是list)进行序列化。序列化之前需要声明一点,llist必须提供命名,因为json需要严格的键值对结构。

toJSON函数有两个需要强调的参数。

第一个是auto_unbox参数,这个参数控制json对象中值(value)在长度为1时,是否强制转换为数组。如果value对象长度唯一,通常不需要数组化,(因为R语言中没有标量,长度为一的字符或者数值都是原子型向量,默认也会被转换为数组【长度为1】)在大多数场合下,需要指定参数auto_unbox为TRUE。

auto_unbox参数默认为FALSE时:

toJSON(mylist)
{"name":["Raiders of the Lost Ark"],"year":[1981],"actors":{"Indiana Jones":["Harrison Ford"],"Dr. Ren Belloq":["Paul Freeman"]},"producers":["Frank Marshall","George Lucas","Howard Kazanjian"],"budget":[18000000],"academy_award_ve":[true]}

auto_unbox参数指定为TRUE时:

toJSON(mylist,auto_unbox = TRUE)
{"name":"Raiders of the Lost Ark","year":1981,"actors":{"Indiana Jones":"Harrison Ford","Dr. Ren Belloq":"Paul Freeman"},"producers":["Frank Marshall","George Lucas","Howard Kazanjian"],"budget":18000000,"academy_award_ve":true}

prettty参数用于控制输出格式是否进行排版美化(换行渲染)

toJSON(mylist,auto_unbox = TRUE,pretty = TRUE)
    {
    "name" : "Raiders of the Lost Ark",
    "year" : 1981,
    "actors" : {
        "Indiana Jones": "Harrison Ford", 
        "Dr. Ren Belloq": "Paul Freeman" 
        },
    "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"],
    "budget" : 18000000,
    "academy_award_ve": true
    }

但是pretty参数仅仅是一个美化参数,仅仅为了更好地进行可视化输出,对于json内容并没有任何影响,在使用时(特别是WEB上传json参数时,通常没有必要设置)。

反序列化:

这里的反序列化就是指如何将一组json字符串反序列化为R语言中的list结构,这种需求在网络数据抓取中使用的及其频繁。

第一种情况:当json字符串来自于手动创建的字符串时:

myjson <-  '{"name":"Raiders of the Lost Ark","year":1981,"actors":{"Indiana Jones":"Harrison Ford","Dr. Ren Belloq":"Paul Freeman"},"producers":["Frank Marshall","George Lucas","Howard Kazanjian"],"budget":18000000,"academy_award_ve":true}'
fromJSON(myjson)
$name
[1] "Raiders of the Lost Ark"
$year
[1] 1981
$actors
$actors$`Indiana Jones`
[1] "Harrison Ford"
$actors$`Dr. Ren Belloq`
[1] "Paul Freeman"
$producers
[1] "Frank Marshall"   "George Lucas"     "Howard Kazanjian"

$budget
[1] 18000000

$academy_award_ve
[1] TRUE

因为json字符串中规定使用英文双引号来包裹所有key键名和字符串格式的value值,所有自己手动建立的包含有json字符串向量时,要使用英文单引号进行表示。这样不至于引起R语言中符号逻辑的混乱。

如果非要使用双引号来建立时,则必须在json字符串内部的所有双引号前使用“\”进行转义,否则R语言无法识别。

myjson <-  "{\"name\":\"Raiders of the Lost Ark\",\"year\":1981,\"actors\":{\"Indiana Jones\":\"Harrison Ford\",\"Dr. Ren Belloq\":\"Paul Freeman\"},\"producers\":[\"Frank Marshall\",\"George Lucas\",\"Howard Kazanjian\"],\"budget\":18000000,\"academy_award_ve\":true}"
fromJSON(myjson)
$name
[1] "Raiders of the Lost Ark"
$year
[1] 1981

$actors$actors
$`Indiana Jones`
[1] "Harrison Ford"

$actors$`Dr. Ren Belloq`
[1] "Paul Freeman"

$producers
[1] "Frank Marshall"   "George Lucas"     "Howard Kazanjian"

$budget
[1] 18000000

$academy_award_ve
[1] TRUE

如果看过之前的几篇关于web抓取的文章,你已经好奇为啥web返回的json原始字符串向量里面存在大量的“\”和“\r\n”。

url <- "http://www.r-datacollection.com/materials/ch-3-xml/peanuts.json"
getURL(url)
  "[\r\n   {\r\n      \"name\":\"van Pelt, Lucy\",\r\n      \"sex\":\"female\",\r\n      \"age\":32\r\n   },\r\n   {\r\n      \"name\":\"Peppermint, Patty\",\r\n      \"sex\":\"female\",\r\n      \"age\":null\r\n   },\r\n   {\r\n      \"name\":\"Brown, Charlie\",\r\n      \"sex\":\"male\",\r\n      \"age\":27\r\n   }\r\n]"
getURL(url) %>% cat()

[
   {      "name":"van Pelt, Lucy",      "sex":"female",      "age":32
   },
   {      "name":"Peppermint, Patty",      "sex":"female",      "age":null
   },
   {      "name":"Brown, Charlie",      "sex":"male",      "age":27
   }
]

实际上这里很好解释,从web端返回的json数据内部所有的分隔符都是双引号,而反会的整个json字串整体作为一个长度为1的原子型字符串向量,但是在R语言中,字符串向量默认使用双引号进行分割,这样就导致json内层的双引号与外侧字符串向量的分割符出现冲突,如果不做任何更改,这样的格式是R语言无法识别的。

fromJSON("{"name":"duyu"}")
Error: unexpected symbol in "fromJSON("{"name"

fromJSON("{\"name\":\"duyu\"}")
$name
[1] "duyu"

所以R语言自动给内层的json分隔符【也就是内层的所有双引号全部都加了转义符,至于”\r\n”,那仅仅是一个换行符,用于优化json排版,使用cat函数可以渲染出最终的效果】。这才是在R语言中,json返回值中出现大量反斜杠的原因。

Python:

Python中主要使用json包进行json的序列化与反序列化。

json序列化:

import json
mydict = {
             "name":"Raiders of the Lost Ark",
             "year":1981,
             "actors":{
                      "Indiana Jones" :"Harrison Ford",
                      "Dr. Ren Belloq": "Paul Freeman" 
                      },
         "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"],
         "budget" : 18000000,
         "academy_award_ve": True
            }
json.dumps(mydict)
'{"name": "Raiders of the Lost Ark", "year": 1981, "actors": {"Indiana Jones": "Harrison Ford", "Dr. Ren Belloq": "Paul Freeman"}, "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"], "budget": 18000000, "academy_award_ve": true}'

序列化的场景主要用在web请求,如果要求参数提交以json格式提交的话,就需要序列化之后进行提交。(仔细观察你会发现json的数据格式与Python中的dict出奇的一致,确实挺像,但是很多细节明显不一样,比如布尔值,py中是True,json中是true)

反序列化同样涉及到自建json字符串。与R语言中情形一样,使用英文单引号作为字符串分隔符,内层的json字符串对象则必须使用双引号作为分割符号。这样不会导致内外层符号混乱。

myjson = '{"name": "Raiders of the Lost Ark", "year": 1981, "actors": {"Indiana Jones": "Harrison Ford", "Dr. Ren Belloq": "Paul Freeman"}, "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"], "budget": 18000000, "academy_award_ve": true}'
json.loads(myjson)
{'academy_award_ve': True,  'actors': {'Dr. Ren Belloq': 'Paul Freeman',   'Indiana Jones': 'Harrison Ford'},  'budget': 18000000,  'name': 'Raiders of the Lost Ark',  'producers': ['Frank Marshall', 'George Lucas', 'Howard Kazanjian'],  'year': 1981}

但是你如果再建立字符串时,坚持使用双引号作为分隔符,为了防止符号混乱,同样需要使用右斜杠转义。

myjson = "{\"name\": \"Raiders of the Lost Ark\", \"year\": 1981, \"actors\": {\"Indiana Jones\": \"Harrison Ford\", \"Dr. Ren Belloq\": \"Paul Freeman\"}, \"producers\": [\"Frank Marshall\", \"George Lucas\", \"Howard Kazanjian\"], \"budget\": 18000000, \"academy_award_ve\": true}"
json.loads(myjson)
{'academy_award_ve': True,  'actors': {'Dr. Ren Belloq': 'Paul Freeman',   'Indiana Jones': 'Harrison Ford'},  'budget': 18000000,  'name': 'Raiders of the Lost Ark',  'producers': ['Frank Marshall', 'George Lucas', 'Howard Kazanjian'],  'year': 1981}

json数据通常来源于webd端的数据请求返回值,但是在Python中,返回值的原始向量,并不会出现像R语言中那种里面存在大量反斜杠的情况,原因在于,Python的字符串分割符默认使用英文单引号(R语言中默认使用英文双引号)。而web端返回的json值严格规定使用英文双引号作为分隔符,这样内层是双引号,外层默认是单引号,所以不会引起歧义,不需要使用反斜杠进行转义。

import requests
url = "http://www.r-datacollection.com/materials/ch-3-xml/peanuts.json"requests.get(url).text'[\r\n   {\r\n      "name":"van Pelt, Lucy",\r\n      "sex":"female",\r\n      "age":32\r\n   },\r\n   {\r\n      "name":"Peppermint, Patty",\r\n      "sex":"female",\r\n      "age":null\r\n   },\r\n   {\r\n      "name":"Brown, Charlie",\r\n      "sex":"male",\r\n      "age":27\r\n   }\r\n]'

可以看到返回值仅仅是包含有\r\n这种换行符(用于美化json排版)。

好在requests函数有一个默认的json方法用于直接处理json返回值。

requests.get(url).json()
[{'age': 32, 'name': 'van Pelt, Lucy', 'sex': 'female'},  {'age': None, 'name': 'Peppermint, Patty', 'sex': 'female'},  {'age': 27, 'name': 'Brown, Charlie', 'sex': 'male'}]

以上json方法调用直接回直接将json字符串转换为Python中的内建对象,dict,但是如果使用urllib包请求,可能就需要使用json库中的json.loads()函数进行反序列化了。

json.loads(requests.get(url).text)
[{'age': 32, 'name': 'van Pelt, Lucy', 'sex': 'female'},  {'age': None, 'name': 'Peppermint, Patty', 'sex': 'female'},  {'age': 27, 'name': 'Brown, Charlie', 'sex': 'male'}]

以上便是R语言与Python中内建非结构化数据对象(list、dict)与json之间的转化方法与核心要点及注意事项。这些函数一定要牢记,在遇到非结构化数据处理时经常用到。

往期案例数据请移步本人GitHub: https://github.com/ljtyduyu/DataWarehouse/tree/master/File

本文分享自微信公众号 - 数据小魔方(datamofang),作者:杜雨

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-11-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • R语言爬虫实战——知乎live课程数据爬取实战

    本文是一篇R语言爬虫实战练习篇,同样使用httr包来完成,结合cookies登录、表单提交、json数据包来完成整个数据爬取过程,无需书写复杂的xpath、cs...

    数据小磨坊
  • 左手用R右手Python系列11——相关性分析

    由于最近毕业论文缠身,一直都没有太多时间和精力撰写长篇的干货,但是呢学习的的脚步不能停止,今天跟大家盘点一下R语言与Python中到的相关性分析部分的常用函数。...

    数据小磨坊
  • R语言网络数据抓取的又一个难题,终于攻破了!

    单纯从数据抓取的逻辑来讲(不谈那些工程上的可用框架),个人觉得R语言中现有的请求库中,RCurl和httr完全可以对标Python中的urllib和reuqes...

    数据小磨坊
  • [日常] 跨语言的POST请求问题的解决

    部门对外提供了一个HTTP的POST接口,但是对方公司的程序员使用C语言进行的调用,PHP这边一直无法获取到参数.遇到这种情况是因为对方没有完全按照HTTP协议...

    陶士涵
  • python Json与pickle数据序列化

    在程序运行的过程中,所有的变量都是在内存中。一旦程序结束,变量所占用的内存就被操作系统全部回收。

    py3study
  • 如何解决ajax跨域问题

    由 于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决 ajax的...

    MonroeCode
  • Python爬取“Python小屋”公众号所有文章生成独立Word文档

    封面图片:《Python程序设计实验指导书》(ISBN:9787302525790),董付国,清华大学出版社

    Python小屋屋主
  • “AI+大数据”可提前一周预测传染病

    中青在线北京12月28日电(中国青年报·中青在线见习记者王林) 中国平安与重庆疾控中心27日联合宣布,其共同研发的“人工智能+大数据”疾病预测与筛查模型可提前一...

    企鹅号小编
  • ASP.NET应用下基于SessionState的“状态编程框架”解决方案

    在一个基于ASP.NET的Web应用程序中,我们通常使用SessionState保存基于某个客户端的状态信息。但是这种单纯使用SessionState的编程方式...

    蒋金楠
  • 华为荣耀正式进军电视行业,宣布推出新品类智慧屏,或搭载鸿蒙系统

    昨天下午,荣耀正式推出新品类——智慧屏,荣耀总裁赵明表示,“智慧屏将成为家庭影音的娱乐中心、信息共享中心、控制管理中心和多设备交互中心。”

    镁客网

扫码关注云+社区

领取腾讯云代金券