PythonでのJSON利用例 データ加工に利用する(追記あり)

「人が見やすい」と「コンピューターが扱いやすい」は違う

前回のエントリ

で作成したデータ「rj」(以降「rj」)

>>> print(rj)
{
    "consolidated_weather": [
        {
            "id": 6102397261709312,
            "weather_state_name": "Light Rain",
            "weather_state_abbr": "lr",
            "wind_direction_compass": "NNE",
            "created": "2021-06-20T12:36:47.257802Z",
            "applicable_date": "2021-06-20",
            "min_temp": 19.935,
            "max_temp": 27.22,
            "the_temp": 26.630000000000003,
            "wind_speed": 7.182764119594899,
            "wind_direction": 28.500000000000007,
            "air_pressure": 998.0,
            "humidity": 70,
            "visibility": 12.777877197168536,
            "predictability": 75
        },
        {
            "id": 4728843366563840,
            "weather_state_name": "Light Rain",
            "weather_state_abbr": "lr",
            "wind_direction_compass": "SE",
            "created": "2021-06-20T12:36:50.227358Z",
            "applicable_date": "2021-06-21",
            "min_temp": 20.95,
            "max_temp": 26.695,
            "the_temp": 26.189999999999998,
            "wind_speed": 6.865762760969273,
            "wind_direction": 135.31537751253472,
            "air_pressure": 1005.0,
            "humidity": 61,
            "visibility": 13.416957468384634,
            "predictability": 75
        },
        {
            "id": 6154227517751296,
            "weather_state_name": "Light Rain",
            "weather_state_abbr": "lr",
            "wind_direction_compass": "SSE",
            "created": "2021-06-20T12:36:53.134335Z",
            "applicable_date": "2021-06-22",
            "min_temp": 20.275,
            "max_temp": 26.965,
            "the_temp": 25.47,
            "wind_speed": 6.456194872952625,
            "wind_direction": 153.04371766880197,
            "air_pressure": 1008.0,
            "humidity": 65,
            "visibility": 12.072310208383044,
            "predictability": 75
        },
        {
            "id": 6213293283737600,
            "weather_state_name": "Light Rain",
            "weather_state_abbr": "lr",
            "wind_direction_compass": "ENE",
            "created": "2021-06-20T12:36:56.308709Z",
            "applicable_date": "2021-06-23",
            "min_temp": 20.47,
            "max_temp": 26.265,
            "the_temp": 25.56,
            "wind_speed": 7.1646883915294675,
            "wind_direction": 74.16831695049069,
            "air_pressure": 1009.5,
            "humidity": 61,
            "visibility": 11.8169266483735,
            "predictability": 75
        },
        {
            "id": 4857742415101952,
            "weather_state_name": "Showers",
            "weather_state_abbr": "s",
            "wind_direction_compass": "ENE",
            "created": "2021-06-20T12:36:59.730423Z",
            "applicable_date": "2021-06-24",
            "min_temp": 19.854999999999997,
            "max_temp": 27.475,
            "the_temp": 26.450000000000003,
            "wind_speed": 6.2296495297303744,
            "wind_direction": 65.59226935085387,
            "air_pressure": 1011.0,
            "humidity": 59,
            "visibility": 12.645214447625865,
            "predictability": 73
        },
        {
            "id": 4946185220521984,
            "weather_state_name": "Heavy Rain",
            "weather_state_abbr": "hr",
            "wind_direction_compass": "NNE",
            "created": "2021-06-20T12:37:02.334879Z",
            "applicable_date": "2021-06-25",
            "min_temp": 18.965,
            "max_temp": 23.72,
            "the_temp": 18.94,
            "wind_speed": 6.0477083830430285,
            "wind_direction": 27.0,
            "air_pressure": 1010.0,
            "humidity": 87,
            "visibility": 8.288470333253798,
            "predictability": 77
        }
    ],
    "time": "2021-06-20T23:46:38.256891+09:00",
    "sun_rise": "2021-06-20T04:25:30.740096+09:00",
    "sun_set": "2021-06-20T18:59:53.501819+09:00",
    "timezone_name": "JST",
    "parent": {
        "title": "Japan",
        "location_type": "Country",
        "woeid": 23424856,
        "latt_long": "37.487598,139.838287"
    },
    "sources": [
        {
            "title": "BBC",
            "slug": "bbc",
            "url": "http://www.bbc.co.uk/weather/",
            "crawl_rate": 360
        },
        {
            "title": "Forecast.io",
            "slug": "forecast-io",
            "url": "http://forecast.io/",
            "crawl_rate": 480
        },
        {
            "title": "HAMweather",
            "slug": "hamweather",
            "url": "http://www.hamweather.com/",
            "crawl_rate": 360
        },
        {
            "title": "Met Office",
            "slug": "met-office",
            "url": "http://www.metoffice.gov.uk/",
            "crawl_rate": 180
        },
        {
            "title": "OpenWeatherMap",
            "slug": "openweathermap",
            "url": "http://openweathermap.org/",
            "crawl_rate": 360
        },
        {
            "title": "Weather Underground",
            "slug": "wunderground",
            "url": "https://www.wunderground.com/?apiref=fc30dc3cd224e19b",
            "crawl_rate": 720
        },
        {
            "title": "World Weather Online",
            "slug": "world-weather-online",
            "url": "http://www.worldweatheronline.com/",
            "crawl_rate": 360
        }
    ],
    "title": "Tokyo",
    "location_type": "City",
    "woeid": 1118370,
    "latt_long": "35.670479,139.740921",
    "timezone": "Asia/Tokyo"
}

はPython上でprintした際に人が見やすい様、インデントや改行を入れたjson形式のデータ、要は文字列です。

これは勿論「人が見やすい為」のインデント、改行追加。

コンピューターにとっては、ここで入れた様な余分なインデント、改行は邪魔なデータでありデータ全体が扱いにくくなります。

更にindexで認識すると分かりますが、文字列であるが故に、一文字ずつのデータとして認識されています。

これではコンピューターにとっては使い勝手が悪い。

例えば「rj」のデータをindexを使ってrj[0]〜rj[8]まで(1番最初=[0]から9個目=[8]まで)抜き出すとこんな感じになってしまいます。(説明不足の為この部分追記:2021/7/17)

>>> rj[0], rj[1], rj[2], rj[3], rj[4], rj[5], rj[6], rj[7], rj[8]
('{', '\n', ' ', ' ', ' ', ' ', '"', 'c', 'o')

こんな形のデータを手渡されても、コンピューターサイドでは手に余ります。
幾つ目に何のデータがあるのか、等中身を人の目で見ないと分からないからです。(説明不足の為この部分追記:2021/7/17)

Decodeしてコンピューターが扱いやすい型にする

よって、json形式のデータをDecodeしてPythonのdictionary型にすればコンピューターが扱いやすくなります。
Decodeしたデータを変数「rd」に格納します(以降「rd」)。

>>> rd = json.loads(rj)
>>> rd
{'consolidated_weather': [{'id': 5486406878101504, 'weather_state_name': 'Light Rain', 'weather_state_abbr': 'lr', 'wind_direction_compass': 'SSE', 'created': '2021-06-21T06:36:46.637102Z', 'applicable_date': '2021-06-21', 'min_temp': 20.595, 'max_temp': 26.695, 'the_temp': 26.045, 'wind_speed': 7.95009805644105, 'wind_direction': 156.44796048484977, 'air_pressure': 1005.0, 'humidity': 68, 'visibility': 12.068581981229618, 'predictability': 75}, {'id': 5333248344326144, 'weather_state_name': 'Showers', 'weather_state_abbr': 's', 'wind_direction_compass': 'SE', 'created': '2021-06-21T06:36:49.772136Z', 'applicable_date': '2021-06-22', 'min_temp': 19.835, 'max_temp': 26.515, 'the_temp': 25.53, 'wind_speed': 5.71505747563297, 'wind_direction': 138.19101390897248, 'air_pressure': 1007.5, 'humidity': 64, 'visibility': 11.610010041358468, 'predictability': 73}, {'id': 4813211925741568, 'weather_state_name': 'Showers', 'weather_state_abbr': 's', 'wind_direction_compass': 'ENE', 'created': '2021-06-21T06:36:52.631305Z', 'applicable_date': '2021-06-23', 'min_temp': 20.38, 'max_temp': 26.89, 'the_temp': 25.23, 'wind_speed': 6.839094457549247, 'wind_direction': 78.51644999392776, 'air_pressure': 1009.5, 'humidity': 61, 'visibility': 10.983357193987114, 'predictability': 73}, {'id': 4828055601152000, 'weather_state_name': 'Showers', 'weather_state_abbr': 's', 'wind_direction_compass': 'ESE', 'created': '2021-06-21T06:36:55.560879Z', 'applicable_date': '2021-06-24', 'min_temp': 19.975, 'max_temp': 28.69, 'the_temp': 26.34, 'wind_speed': 6.292572242546196, 'wind_direction': 101.85121745253474, 'air_pressure': 1010.5, 'humidity': 57, 'visibility': 10.98677473554442, 'predictability': 73}, {'id': 5486327656087552, 'weather_state_name': 'Showers', 'weather_state_abbr': 's', 'wind_direction_compass': 'ENE', 'created': '2021-06-21T06:36:59.135161Z', 'applicable_date': '2021-06-25', 'min_temp': 20.64, 'max_temp': 27.89, 'the_temp': 26.060000000000002, 'wind_speed': 6.714723829237254, 'wind_direction': 69.7846135012515, 'air_pressure': 1011.5, 'humidity': 60, 'visibility': 10.537523363556826, 'predictability': 73}, {'id': 4900854793502720, 'weather_state_name': 'Heavy Cloud', 'weather_state_abbr': 'hc', 'wind_direction_compass': 'ESE', 'created': '2021-06-21T06:37:02.126462Z', 'applicable_date': '2021-06-26', 'min_temp': 21.740000000000002, 'max_temp': 29.34, 'the_temp': 27.6, 'wind_speed': 5.437992523661815, 'wind_direction': 103.50000000000001, 'air_pressure': 1010.0, 'humidity': 54, 'visibility': 9.999726596675416, 'predictability': 71}], 'time': '2021-06-21T16:05:03.891720+09:00', 'sun_rise': '2021-06-21T04:25:44.015676+09:00', 'sun_set': '2021-06-21T19:00:06.878838+09:00', 'timezone_name': 'JST', 'parent': {'title': 'Japan', 'location_type': 'Country', 'woeid': 23424856, 'latt_long': '37.487598,139.838287'}, 'sources': [{'title': 'BBC', 'slug': 'bbc', 'url': 'http://www.bbc.co.uk/weather/', 'crawl_rate': 360}, {'title': 'Forecast.io', 'slug': 'forecast-io', 'url': 'http://forecast.io/', 'crawl_rate': 480}, {'title': 'HAMweather', 'slug': 'hamweather', 'url': 'http://www.hamweather.com/', 'crawl_rate': 360}, {'title': 'Met Office', 'slug': 'met-office', 'url': 'http://www.metoffice.gov.uk/', 'crawl_rate': 180}, {'title': 'OpenWeatherMap', 'slug': 'openweathermap', 'url': 'http://openweathermap.org/', 'crawl_rate': 360}, {'title': 'Weather Underground', 'slug': 'wunderground', 'url': 'https://www.wunderground.com/?apiref=fc30dc3cd224e19b', 'crawl_rate': 720}, {'title': 'World Weather Online', 'slug': 'world-weather-online', 'url': 'http://www.worldweatheronline.com/', 'crawl_rate': 360}], 'title': 'Tokyo', 'location_type': 'City', 'woeid': 1118370, 'latt_long': '35.670479,139.740921', 'timezone': 'Asia/Tokyo'}

「rd」はPythonのdictionary形式ですので、扱いやすくなります。

>>> rd['consolidated_weather'][0]
{'id': 5486406878101504, 'weather_state_name': 'Light Rain', 'weather_state_abbr': 'lr', 'wind_direction_compass': 'SSE', 'created': '2021-06-21T06:36:46.637102Z', 'applicable_date': '2021-06-21', 'min_temp': 20.595, 'max_temp': 26.695, 'the_temp': 26.045, 'wind_speed': 7.95009805644105, 'wind_direction': 156.44796048484977, 'air_pressure': 1005.0, 'humidity': 68, 'visibility': 12.068581981229618, 'predictability': 75}
>>> rd['sources'][0]
{'title': 'BBC', 'slug': 'bbc', 'url': 'http://www.bbc.co.uk/weather/', 'crawl_rate': 360}

key「consolidated_weather」の一括りのデータから、1つ目(index = 0:id =5486406878101504)を出力、key「sources」の一括りのデータから、1つ目(”title”: “BBC”)のデータを出力、の様にデータとして扱うことが出来ます。

この性質を利用すると、その日毎の天気を出力する事もできます。
2行目が長すぎてPythonicなコードの書き方じゃない!と怒られそうですが、ここでは行を変えない方が分かり易そうなので、一旦そのままにしておきます。

>>> for i in range(len(rd['consolidated_weather'])):
...     print(rd['consolidated_weather'][i]['applicable_date'], ' : ' ,rd['consolidated_weather'][i]['weather_state_name'])
... 
2021-06-21  :  Light Rain
2021-06-22  :  Showers
2021-06-23  :  Showers
2021-06-24  :  Showers
2021-06-25  :  Showers
2021-06-26  :  Heavy Cloud

と言う事で、コンピューターの使い勝手を良くする為にはDecodeしてPythonのdictionary形式にする。

ちなみに、今回「rj」からDecodeした「rd」は、元のjson形式のデータからr.json()でDecodeした「rt」と同じです。

>>> rt = r.json()
>>> rd == rt
True

このDecodeとEncodeの関係は先のエントリ

で見た様に、データの型によってはずれが起きる危険性がありそうです。

よって、基本は元の元のjson形式ファイルと、このjson形式データからDecodeしたPython dictionary型ファイルとで作業し、Encode, Decodeをぐるぐる回さない方が良い、と言うのが現時点の理解。

基本は外部からデータを受領する際にはJSON形式で受領
Pythonで扱い易いdictionary形にDecodeした上で加工、利用
外部にデータを送る際には、JSON形式にEncode
と言う使い方と理解。

あくまでも他アプリとの間を繋ぐ役割のものなので、無闇にEncode, Decodeをぐるぐる回すものではない。

これは当然の事なのでしょうが、訳も無くそこにPythonデータがあるとEncodeしたくなり、JSON形式のデータがあるとDecodeをしたくなる自分への自戒として。
(最後の自分なりのまとめを修正:2021/7/17)