【Python】JSONデータの使い方(jsonモジュール)

JSONは Web APIなどのデータ交換形式としても広く使われているデータ形式です。Python標準の組込みモジュールであるjsonを使ってJSONデータを扱うことができます。本記事では、

  • Web APIからのレスポンスを文字列として取得し、それをPythonオブジェクトへ変換
  • PythonオブジェクトからJSON形式でファイル保存
  • 日本語(非ASCII文字)のUnicodeエスケープ

等について整理しました。
また最後に、実際のWeb APIを使った具体例も記載しました。
# 2019/8/12 更新

確認した環境

  • OS:Ubuntu16.04LTS
  • Python 3.7.2@Anaconda

JSONについて

JSONとは?

  • “JavaScript Object Notation”の略。javascriptの仕様の一部として作られた軽量なデータ形式
  • JavaScript専用のデータ形式ではなく、様々なソフトウェア、プログラミング言語間におけるデータ交換に使えるよう設計されている
  • Web APIなどのデータ交換形式としても広く使われている

データフォーマット

JSON公式?から引用します。

JSONは2つの構造を基にしています。

  • 名前/値のペアの集まり。様々な言語で、これはオブジェクト、レコード、構造体、ディクショナリ、ハッシュテーブル、キーのあるリスト、連想配列として実現されています。
  • 値の順序付きリスト。ほとんどの言語で、これは配列として実現されています。

引用元:https://www.json.org/json-ja.html

もう少し具体的に書くと、、、

  • 配列:
  • 値を(,)(カンマ)で区切って、[](角かっこ)でくくる。

    ["aaa", "bbb", "ccc"]
  • オブジェクト:
  • キーと値のペアを”:”(コロン)でペアにして、これらのペアを’,'(コンマ)で区切って全体を{}でくくる。

    {"Item": "Book", "price": 1200}

    ここで、キーは文字列に限ることに注意。つまり、

    {item: "Book", price: 1200}

    という表記は、キーが変数に見えてしまうのでJSONとしては不正となります。

尚、JSONでは文字列はダブルクォーテーション(“)で囲うこと。シングルクォーテーション(‘)だと以下のようなエラーになります。

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 3 (char 2)

JSONモジュールの使いかた

PythonでJSONデータを扱うには、jsonモジュールが便利です。

但し、JSONはPythonでサポートしている全てのデータ型を使える訳ではありません。使えるデータ型は以下に限定されることに注意です。

  • 文字列
  • 整数
  • 浮動小数点
  • ブール値
  • リスト
  • 辞書
  • None

文字列をPythonオブジェクトへ変換

(JSONドキュメントを含んだ)文字列をPythonオブジェクトへ変換するには、loads()を使います。
例を以下に示します。

# JSON形式を含んだ文字列
>>> j = '[{"name": "Taro", "age": 14, "check": true}, {"name": "Jiro", "age": 23, "check": false}, {"name": "Tom", "age": 16, "check": false}]'

# jsonモジュールをimport
>>> import json

# 文字列をPythonオブジェクトへ変換
>>> json_data = json.loads(j)

# Pythonオブジェクト(辞書とリストの組み合わせ)
>>> json_data
[{'name': 'Taro', 'age': 14, 'check': True}, {'name': 'Jiro', 'age': 23, 'check': False}, {'name': 'Tom', 'age': 16, 'check': False}]

辞書とリストの組み合わせなので、Pythonコードの中で任意のデータを取得することが出来ます。

PythonオブジェクトをJSON形式のstrオブジェクトに変換

Pythonオブジェクト(例えば辞書とリストの組み合わせ)を、JSON形式のstrオブジェクトに変換するには、dumps()メソッドを使います。
使い方の例を以下に示します。

# 変換するデータ(リストと辞書の組み合わせ)
>>> data_python = [{'name': 'Taro', 'age': 14, 'check': True}, {'name': 'Jiro', 'age': 23, 'check': False}, {'name': 'Tom', 'age': 16, 'check': False}]

# jsonモジュールをimport
>>> import json

# dumps関数でJSONデータに変換
>>> data_json = json.dumps(data_python)

# JSONデータ
>>> data_json
'[{"name": "Taro", "age": 14, "check": true}, {"name": "Jiro", "age": 23, "check": false}, {"name": "Tom", "age": 16, "check": false}]'

jsonデータを見やすく整形する

dumps関数にindentパラメータを設定すると、print文で表示した時に見やすくなります。

>>> data_json = json.dumps(data_python, indent=4)
>>> print(data_json)
[
    {
        "name": "Taro",
        "age": 14,
        "check": true
    },
    {
        "name": "Jiro",
        "age": 23,
        "check": false
    },
    {
        "name": "Tom",
        "age": 16,
        "check": false
    }
]

日本語文字が含まれている場合

dumps()では、デフォルトでは日本語のような非ASCII文字はUnicodeエスケープされます。
つまり、例えば日本語文字のりんご\u308a\u3093\u3054といった表記で出力されます。

具体例で見てみます。

# 日本語が含まれたPythonオブジェクト
>>> data_python = [{'name': 'たろー', 'age': 14, 'check': True}, {'name': '次郎', 'age': 23, 'check': False}, {'name': 'Tom', 'age': 16, 'check': False}]

# dumps()でJSON形式に変換
>>> data_json = json.dumps(data_python, indent=4)

# 日本語の箇所がUnicodeエスケープされている(★部)
>>> print(data_json)
[
    {
        "name": "\u305f\u308d\u30fc", (★)
        "age": 14,
        "check": true
    },
    {
        "name": "\u6b21\u90ce", (★)
        "age": 23,
        "check": false
    },
    {
        "name": "Tom",
        "age": 16,
        "check": false
    }
]

これはdumps()の引数ensure_asciitrueとなっているためで、日本語を日本語として表記するには、この引数をFalseにしてやります。

# ensure_ascii = Falseに設定
>>> data_json = json.dumps(data_python, indent=4, ensure_ascii=False)
>>> print(data_json)
[
    {
        "name": "たろー",
        "age": 14,
        "check": true
    },
    {
        "name": "次郎",
        "age": 23,
        "check": false
    },
    {
        "name": "Tom",
        "age": 16,
        "check": false
    }
]

PythonオブジェクトをJSON形式でファイルへ保存する

dump()を使います。使い方は下記です。第3引数以降は細かいので割愛しています。

json.dump(obj, fp)

この関数は、PythonオブジェクトobjをJSON形式のfile-likeオブジェクトfpに格納します。
具体例を以下に示します。

>>> import json

>>> data_python = [{'name': 'たろー', 'age': 14, 'check': True}, {'name': '次郎', 'age': 23, 'check': False}, {'name': 'Tom', 'age': 16, 'check': False}]

>>> with open('sample.json', 'w') as fp:
...     json.dump(data_python, fp, indent=4, ensure_ascii=False)

出力結果を確認します。前項で述べたindentやensure_asciiの設定も反映されていますね。

~$ cat sample.json
[
    {
        "name": "たろー",
        "age": 14,
        "check": true
    },
    {
        "name": "次郎",
        "age": 23,
        "check": false
    },
    {
        "name": "Tom",
        "age": 16,
        "check": false
    }
]

実際にWeb APIにアクセスしてみる

簡単なWeb APIにアクセスしてJSONデータを使ってみたいと思います。
例として、お天気Webサービス(Livedoor Weather Web Service / LWWS)(http://weather.livedoor.com/weather_hacks/webservice)を試してみます。
このサービスは、現在全国142カ所の今日・明日・あさっての天気予報・予想気温と都道府県の天気概況情報を提供しています。
以下のコードは、このAPIを利用して神奈川県の天気予報を抽出するものです。こちらにもアップしています。

"""
web_api_weather.py
"""
import json
import requests

# JSONデータをリクエストする際のベースURL
base_url='http://weather.livedoor.com/forecast/webservice/json/v1?city={city}'

# 調べたい都市のID
city_id = '140010'

#APIのURL
url = base_url.format(city = city_id)

# APIへリクエストを送信
res = requests.get(url)

# アクセスチェック
res.raise_for_status()

# レスポンスのJSONデータをPythonオブジェクトへ変換
data = json.loads(res.text)

# 必要な情報を抽出
print("**** Weather Information@Kanagawa ****")
print("[TIME]")
print(data["description"]["publicTime"])
print("[INFOMATION]")
print(data["description"]["text"])
print("[FORECASTS]")
for i in range(3):
    print("DATE:{} / {}".format(data["forecasts"][i]["date"], data["forecasts"][i]["telop"]))

実行結果は以下です。

$ python3 web_api_weather.py
**** Weather Information@Kanagawa ****
[TIME]
2018-09-16T16:40:00+0900
[INFOMATION]
 東日本は、日本の南とアリューシャンの南の高気圧に挟まれ、気圧の谷と
なっています。

 神奈川県は、おおむね曇りとなっています。

 16日は、気圧の谷の影響により曇りで、夜は雨の降る所があるでしょう
。

 17日は、気圧の谷や湿った空気の影響により、曇り昼過ぎまで時々晴れ
で、午後は大気の状態が不安定となるため、夕方から雨の降る所がある見込
みです。

 神奈川県の海上では、16日から17日にかけて、うねりを伴って波がや
や高いでしょう。船舶は高波に注意してください。
[FORECASTS]
DATE:2018-09-16 / 曇り
DATE:2018-09-17 / 曇時々晴
DATE:2018-09-18 / 曇時々晴

まとめ

JSONをPythonで使う方法についてまとめました。
公開データをWebサイトからAPI経由で取得する場合など、有用な場面は多そうです。

Learn more...

書籍でもう少し詳しく学びたい場合はこちらもどうぞ。筆者もかなり参考にさせてもらっています!

[Sponsor link]