0
0

深さ優先探索と幅優先探索でJSONの構造解析

Last updated at Posted at 2024-04-17

外部のオープンデータを活用する上でWebAPIを活用することは多いと思います。特にその中ではJSONやXMLが多く、PythonでJSONやXMLを利用する際には辞書形式に直して活用します。
※なお、幅優先探索については深さ優先探索を作った後にChatGPTに教わって作りました

深さ優先探索の関数

第一引数は辞書データ、第二引数は文字列として初期値は何も入っていませんが、辞書に使う変数名を入れるとその後辞書をピンポイントで必要な所をコピーペーストする時に便利なので辞書に使う変数を第二引数に入れて関数を使うことをお勧めします。

def depth(jsn, var=""):
    if isinstance(jsn, dict):
        for row in jsn:
            depth(jsn[row], var=var+"[\""+row+"\"]")
    elif isinstance(jsn, list) and jsn != []:
        for i in range(len(jsn)):
            depth(jsn[i], var=var+"["+str(i)+"]")
    else:
        print(var+"="+str(jsn))
        pass

ここで、辞書データを扱う場合は変数型が「辞書」「リスト」の時にキーとキーを記録した文字列を使って更に深く解析をしていき、それとは違う変数型の場合には記録したキーを出力するようにします。

幅優先探索(参考:生成AI)

第一引数と第二引数の仕様は深さ優先探索と同じになります。

from collections import deque
def width(jsn, var=""):
    queue = deque([(jsn, var)])
    while queue:
        node, var = queue.popleft()
        if isinstance(node, dict):
            for key in node:
                queue.append((node[key], var+"[\""+key+"\"]"))
        elif isinstance(node, list) and node != []:
            for i in range(len(node)):
                queue.append((node[i], var+"["+str(i)+"]"))
        else:
            print(var+"="+str(node))
            pass

ではここからは関数を実装した上での使い方の一例です。

import json
import requests

def depth(jsn, var=""):
    if isinstance(jsn, dict):
        for row in jsn:
            depth(jsn[row], var=var+"[\""+row+"\"]")
    elif isinstance(jsn, list) and jsn != []:
        for i in range(len(jsn)):
            depth(jsn[i], var=var+"["+str(i)+"]")
    else:
        print(var+"="+str(jsn))
        pass

url = "https://hoge.com/data.json" #ここにJSONのあるURLを入れる
res = requests.get(url)
data = json.loads(res.text)
depth(data, "data") #深さ優先探索
print()

一例としてこちらのページを解析した場合についてを紹介します。

data[0]["publishingOffice"]=気象庁
data[0]["reportDatetime"]=2024-04-17T17:00:00+09:00
data[0]["timeSeries"][0]["timeDefines"][0]=2024-04-17T17:00:00+09:00
data[0]["timeSeries"][0]["timeDefines"][1]=2024-04-18T00:00:00+09:00
data[0]["timeSeries"][0]["timeDefines"][2]=2024-04-19T00:00:00+09:00
data[0]["timeSeries"][0]["areas"][0]["area"]["name"]=東京地方
data[0]["timeSeries"][0]["areas"][0]["area"]["code"]=130010
data[0]["timeSeries"][0]["areas"][0]["weatherCodes"][0]=200
data[0]["timeSeries"][0]["areas"][0]["weatherCodes"][1]=212
data[0]["timeSeries"][0]["areas"][0]["weatherCodes"][2]=101
<中略>
data[1]["precipAverage"]["areas"][0]["min"]=11.5
data[1]["precipAverage"]["areas"][0]["max"]=30.9
data[1]["precipAverage"]["areas"][1]["area"]["name"]=八丈島
data[1]["precipAverage"]["areas"][1]["area"]["code"]=44263
data[1]["precipAverage"]["areas"][1]["min"]=28.3
data[1]["precipAverage"]["areas"][1]["max"]=58.3
data[1]["precipAverage"]["areas"][2]["area"]["name"]=父島
data[1]["precipAverage"]["areas"][2]["area"]["code"]=44301
data[1]["precipAverage"]["areas"][2]["min"]=7.6
data[1]["precipAverage"]["areas"][2]["max"]=28.1

これによって数値や文字列に至るまでのキーが分かるようになります。
また所感ですが、JSONからデータベースか何かを作る際には深さ優先探索で出力してみると解析が早くなるような気がします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0