自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何快速?gòu)纳顚忧短?JSON 中找到特定的 Key

開(kāi)發(fā) 前端
在爬蟲(chóng)開(kāi)發(fā)的過(guò)程中,我們經(jīng)常遇到一些 Ajax 加載的接口會(huì)返回 JSON 數(shù)據(jù)。

[[376428]]

在爬蟲(chóng)開(kāi)發(fā)的過(guò)程中,我們經(jīng)常遇到一些 Ajax 加載的接口會(huì)返回 JSON 數(shù)據(jù)。如下圖所示,是 Twitter 的用戶(hù)時(shí)間線(xiàn)接口,返回了一段3000多行的深層嵌套 JSON:

其中的cursor這個(gè)字段,是請(qǐng)求下一頁(yè)的必要字段,我必須把它的 value 值讀取出來(lái),拼接到請(qǐng)求 URL 中,才能請(qǐng)求下一頁(yè)的內(nèi)容。

現(xiàn)在問(wèn)題來(lái)了,cursor字段在這個(gè) JSON 里面的哪個(gè)位置?從最外層開(kāi)始,我應(yīng)該怎么樣才能讀取到最里面的這個(gè)cursor中的value字段的值?

我知道已經(jīng)有一些第三方庫(kù)可以直接根據(jù)字段名讀取 JSON 內(nèi)部任意深度的值,不過(guò)用別人的東西總沒(méi)有自己寫(xiě)一個(gè)輪子來(lái)得過(guò)癮。所以今天我們自己來(lái)手寫(xiě)一個(gè)模塊,我把他叫做JsonPathFinder,傳入一個(gè) JSON 字符串和需要讀取的字段名,返回從最外層開(kāi)始直到這個(gè)字段的路徑。

效果演示

我們用 Python 之父龜叔的 Twitter 時(shí)間線(xiàn)來(lái)作為演示,運(yùn)行以后,效果如下圖所示:

可以看到,從最外層開(kāi)始一路讀到cursor字段,需要經(jīng)過(guò)非常多的字段名,對(duì)應(yīng)到 JSON 中,如下圖所示:

由于entries 字段列表中一共有20個(gè)元素,所以這里的18、19實(shí)際上對(duì)應(yīng)了倒數(shù)第二條和倒數(shù)第一條數(shù)據(jù)。其中,倒數(shù)第二條的 cursor 對(duì)應(yīng)的是本頁(yè)第一條推文,而倒數(shù)第一條對(duì)應(yīng)的是本頁(yè)最后一條推文。所以當(dāng)我們要往后翻頁(yè)的時(shí)候,應(yīng)該用的是倒數(shù)第一條的 cursor。

我們?cè)囍鴣?lái)讀取一下結(jié)果:

非常輕松地獲取到了數(shù)據(jù)。不需要再肉眼在 JSON 中尋找字段了。

原理分析

JsonPathFinder 的原理并不復(fù)雜,全部代碼加上空行,一共只有32行,如下圖所示:

因?yàn)橐粋€(gè)字段在 JSON 中可能出現(xiàn)很多次,所以find_one方法返回從外層到目標(biāo)字段的第一條路徑。而find_all方法返回從外層到目標(biāo)字段的所有路徑。

而核心算法,就是iter_node方法。在把 JSON 字符串轉(zhuǎn)成 Python 的字典或者列表以后,這個(gè)方法使用深度優(yōu)先遍歷整個(gè)數(shù)據(jù),記錄它走過(guò)的每一個(gè)字段,如果遇到列表就把列表的索引作為 Key。直到遍歷到目標(biāo)字段,或者某個(gè)字段的值不是列表也不是字典時(shí)結(jié)束本條路徑,繼續(xù)遍歷下個(gè)節(jié)點(diǎn)。

代碼第10-15行,分別對(duì)列表和字典進(jìn)行處理。對(duì)于字典來(lái)說(shuō),我們分離 key 和 value,寫(xiě)作:

  1. for key, value in xxx.items(): 
  2.    ... 

對(duì)于列表,我們分離索引和元素,寫(xiě)作:

  1. for index, element in enumerate(xxx): 
  2.    ... 

所以如在第11和第13行,使用生成器推導(dǎo)式分別處理字典和列表,這樣得到的key_value_iter生成器對(duì)象,就可以在第16行被相同的 for 循環(huán)迭代。

我們知道,在 Python 里面可以迭代的對(duì)象除了字典和列表以外,還有很多其他的對(duì)象,不過(guò)我這里只處理了字典和列表。大家也可以試一試修改10-15行的條件判斷,增加對(duì)其他可迭代對(duì)象的處理邏輯。

代碼第16-22行,對(duì)處理以后的 key-value 進(jìn)行迭代。首先記錄到當(dāng)前字段為止的迭代路徑到current_path列表中。然后判斷當(dāng)前字段是不是目標(biāo)字段。如果是,那么把當(dāng)前的路徑通過(guò) yield 拋出來(lái)。如果當(dāng)前路徑的值是列表或者字典,那么把這個(gè)值遞歸傳入 iter_node 方法,進(jìn)一步檢查內(nèi)部還有沒(méi)有目標(biāo)字段。需要注意的是,無(wú)論當(dāng)前字段是不是目標(biāo)字段,只要它的值是列表或者字典,都需要繼續(xù)迭代。因?yàn)榧词巩?dāng)前字段的名字是目標(biāo)字段,但也許它內(nèi)部還有某個(gè)子孫字段的字段名也是目標(biāo)字段名。

對(duì)于普通函數(shù)來(lái)說(shuō),要遞歸調(diào)用,直接return 當(dāng)前函數(shù)(參數(shù))就可以了。但是對(duì)于生成器來(lái)說(shuō),要遞歸調(diào)用,就需要使用yield from 當(dāng)前函數(shù)名(參數(shù))。

由于iter_node方法返回的是一個(gè)生成器對(duì)象,在 find_one和find_all方法中,for 循環(huán)每一次迭代,都能拿到一條從20行拋出來(lái)的到目標(biāo)字段的路徑。而在find_one方法中,當(dāng)我們拿到第一條路徑時(shí),不再繼續(xù)迭代,那么就可以節(jié)省大量的時(shí)間,減少迭代次數(shù)。

正確使用

有了這個(gè)工具以后,我們可以直接用它來(lái)解析數(shù)據(jù),也可以用來(lái)輔助分析數(shù)據(jù)。例如,Twitter 時(shí)間線(xiàn)的正文是在full_text中,我可以直接用 JsonPathFinder 獲取所有的正文:

但有時(shí)候,我們除了獲取正文外,還需要每一條推文的其他信息,如下圖所示:

可以看到, 這種情況下,我們可以先獲取從外層到full_text的路徑列表,然后再人工對(duì)列表進(jìn)行一些加工,輔助開(kāi)發(fā):

從打印出來(lái)的路徑列表里面可以看到,我們只需要獲取globalObjects->tweets就可以了。它的值是20個(gè)字典,每個(gè)字典的 Key 是推文的 ID,Value 是推文的詳情。這個(gè)時(shí)候,我們?cè)偃斯とバ薷囊幌麓a,也能方便地提取一條推文的全部字段。

 

責(zé)任編輯:趙寧寧 來(lái)源: 未聞Code
相關(guān)推薦

2020-10-12 11:16:32

數(shù)組特定值元素

2018-05-28 11:10:08

Linux命令IP地址

2014-06-06 10:01:21

百度

2018-10-17 09:20:31

Linux命令重復(fù)文件

2020-04-08 10:42:14

多云云計(jì)算云開(kāi)發(fā)

2021-03-21 07:23:18

微軟MSERT工具現(xiàn)web shell

2009-08-10 19:30:09

運(yùn)維知識(shí)庫(kù)IT運(yùn)維管理廣通信達(dá)科技

2022-05-27 11:59:22

Linux內(nèi)存CPU

2017-02-17 09:14:14

Hadoop

2023-09-04 10:10:47

插件頁(yè)面元素

2022-12-12 11:14:06

LinuxID

2025-02-13 08:00:00

AI罕見(jiàn)病患者人工智能

2020-03-31 17:05:39

Redis熱 key代理

2023-04-24 13:37:04

Unity游戲開(kāi)發(fā)

2021-02-03 10:43:54

Linux系統(tǒng)磁盤(pán)

2022-07-06 23:34:00

LinuxIP

2021-11-06 23:19:39

Python電腦文件

2022-10-25 07:32:02

2013-07-25 09:34:13

微軟云平臺(tái)Windows Azu

2022-02-15 22:32:19

GC虛擬機(jī)對(duì)象
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)