在Python里玩轉(zhuǎn)JSON數(shù)據(jù)
Json簡介
Json(JavaScript Object Notation)
很多網(wǎng)站都會用到Json格式來進(jìn)行數(shù)據(jù)的傳輸和交換,就像之前我們發(fā)過?網(wǎng)易云音樂接口API,其返回的數(shù)據(jù)都是Json格式的。

這因?yàn)镴son是一種輕量級的數(shù)據(jù)交換格式,具有數(shù)據(jù)格式簡單,讀寫方便易懂等很多優(yōu)點(diǎn)。用它來進(jìn)行前后端的數(shù)據(jù)傳輸,大大的簡化了服務(wù)器和客戶端的開發(fā)工作量。
而且相對于XML來說,更加的輕量級,更方便解析。
在Json中,遵循“key-value”的這樣一種方式。
比如最簡單的這種:“{"name" : "zhuxiao5"}”,跟python 里的字典似的,也是一個Json格式的數(shù)據(jù)。
復(fù)雜一點(diǎn)的比如這種(后文會多次使用到這個例子):
{
????"animals":?{
????????"dog":?[
????????????{
????????????????"name":?"Rufus",
????????????????"age":15
????????????},
????????????{
????????????????"name":?"Marty",
????????????????"age":?null
????????????}
????????]
????}
}以上圖為例,再多說幾句Json格式的特點(diǎn)
對象通過鍵值對表現(xiàn);
鍵通過雙引號包裹,后面跟冒號“:”,然后跟該鍵的值;
值可以是字符串、數(shù)字、數(shù)組等數(shù)據(jù)類型;
對象與對象之間用逗號隔開;
“{}”用來表達(dá)對象;
“[]”用來表達(dá)數(shù)組;
Python中的Json模塊
Python中也自帶了Json模塊,其中json.dumps()、json.loads()較為常用。
?
json.dumps() 是將 python 對象轉(zhuǎn)化為 json。
json.loads() 是將 json 轉(zhuǎn)化為 python 對象。

#json.dumps(),json.loads()
import?json
dict_data?=?{"a":?1,?"b":?2}
#?將dict格式數(shù)據(jù)轉(zhuǎn)換成json格式字符串
dump_data?=?json.dumps(dict_data)
#?將json格式字符串轉(zhuǎn)換成對應(yīng)的python值
load_data?=?json.loads(dump_data)
#?打印轉(zhuǎn)換結(jié)果
print(type(dict_data),dict_data)
print(type(dump_data),dump_data)
print(type(load_data),load_data)運(yùn)行結(jié)果:
<class?'dict'>?{'a':?1,?'b':?2}
<class?'str'>?? {"a":?1,?"b":?2}
<class?'dict'>?{'a':?1,?'b':?2}在例子中一開始的變量 dict_data 是一個字典,json.dumps() 后,將dict格式數(shù)據(jù)轉(zhuǎn)換成json格式字符串。這時候雖然都是{'a': 1, 'b': 2},但是格式卻前后不一樣。隨后又通過 json.loads(),重新將json格式字符串轉(zhuǎn)換成字典。
在線解析Json
在實(shí)際應(yīng)用中,要提取json數(shù)據(jù),就要了解返回json數(shù)據(jù)的結(jié)構(gòu)。
可是Json格式的數(shù)據(jù)往往是這樣的。


大家別擔(dān)心,我們可以將數(shù)據(jù)復(fù)制到一些json插件或在線解析!
比如這個插件:

此時再打開剛才的網(wǎng)址

是不是清晰了很多呢?
如果用python來獲取里面的數(shù)據(jù)怎么做的?
先利用 json.loads()?來將 Json?轉(zhuǎn)成字典,再用 get() 函數(shù)直到得到我們想要的list 對象,那么對于 list 里面的數(shù)據(jù)我們用個 for 循環(huán)就行啦~
額,有點(diǎn)繞。

還是文章一開始的例子,我們想獲取其中所有狗狗的名字:
{
????"animals":?{
????????"dog":?[
????????????{
????????????????"name":?"Rufus",
????????????????"age":15
????????????},
????????????{
????????????????"name":?"Marty",
????????????????"age":?null
????????????}
????????]
????}
}我們可以這樣做:
load_data?=?json.loads(dump_data)
data?=?load_data.get("animals").get("dog")
result1?=?[]
for?i?in?data:
????result1.append(i.get("name"))
print(result1)
運(yùn)行結(jié)果:
['Rufus',?'Marty']
這樣確實(shí)可以獲得我們想要的結(jié)果。
PS:類似的在線解析網(wǎng)站也有很多,比如 https://www.json.cn。
JsonPath
不知道大家還記不記得,在一開始介紹Json時,我提到了它相對于XML來說,更加的輕量級,更方便解析。
既然 XML 人家都有 XPATH ,那么Json有沒有類似的工具呢?

JsonPath 是一種信息抽取類庫,是從Json文檔中抽取指定信息的工具。
JsonPath 對于 Json 來說,相當(dāng)于 XPATH 對于 XML。
Json結(jié)構(gòu)清晰,可讀性高,復(fù)雜度低,非常容易匹配,下表是JsonPath的用法。


沒錯,還是這個例子,我們這次嘗試用JsonPath獲取其中所有狗狗的名字:
{
????"animals":?{
????????"dog":?[
????????????{
????????????????"name":?"Rufus",
????????????????"age":15
????????????},
????????????{
????????????????"name":?"Marty",
????????????????"age":?null
????????????}
????????]
????}
}我們可以這樣做:
load_data?=?json.loads(dump_data)
jobs=load_data['animals']['dog']
result2?=?[]
for?i?in?data:
#?從根節(jié)點(diǎn)開始,匹配name節(jié)點(diǎn)
????result2.append(jsonpath.jsonpath(i,'$..name')[0])
print(result2)
其中 $..name 代表從根節(jié)點(diǎn)開始,匹配name節(jié)點(diǎn)
運(yùn)行結(jié)果:
['Rufus',?'Marty']利用 JsonPath 同樣可以獲得我們想要的結(jié)果。
我們在后續(xù)實(shí)例演練中將繼續(xù)采用 JsonPath 來抽取數(shù)據(jù)。
實(shí)例演練
示例:我們利用?網(wǎng)易云音樂評論API?來生成Json數(shù)據(jù),并從中獲取熱評數(shù)據(jù)。
http://music.163.com/api/v1/resource/comments/R_SO_4_483671599?limit=10&offset=0
?
在瀏覽器(已安裝Json解析插件)中打開:


標(biāo)紅區(qū)域的數(shù)據(jù)是我們本次想要獲取的。

def?get_comments(url):
????data?=?[]
????doc?=?get_json(url)
????jobs=doc['hotComments']
????for?job?in?jobs:
????????dic?=?{}
????????#從根節(jié)點(diǎn)開始,匹配content節(jié)點(diǎn)
????????dic['content']=jsonpath.jsonpath(job,'$..content')[0]?#評論
????????dic['time']=?stampToTime(jsonpath.jsonpath(job,'$..time')[0])?#時間
????????dic['userId']=jsonpath.jsonpath(job['user'],'$..userId')[0]??#用戶ID
????????dic['nickname']=jsonpath.jsonpath(job['user'],'$..nickname')[0]#用戶名
????????dic['likedCount']=jsonpath.jsonpath(job,'$..likedCount')[0]?#贊數(shù)
????????data.append(dic)
????return?pd.DataFrame(data)
final_result?=?get_comments('http://music.163.com/api/v1/resource/comments/R_SO_4_483671599?limit=10&offset=0')
運(yùn)行結(jié)果:

成功獲取√
希望本文能讓大家以后玩轉(zhuǎn)Json數(shù)據(jù)更輕松~
本文所有案例的代碼已上傳,公眾號對話頁回復(fù)?json 可獲得相關(guān)代碼。
_往期文章推薦_
