読者です 読者をやめる 読者になる 読者になる

Python3でJSONデータを解析する

ググって出てくるJSON解析の方法はPython2系ばっかりなので、Python3系でのやり方をまとめます。 JSONデータは「 pythonのurllib2でjsonを取得して解析する - 文系プログラマによるTIPSブログ 」でも使われているお天気Webサービスを使います。

APIから読み込む

JSON形式のデータはWEBAPIから呼ぶことが多いかと思います。Pythonの標準ライブラリurllibとjsonを使ってAPI経由でデータを取りに行きます。

import urllib
import json

url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=400040'
html = urllib.request.urlopen(url)
jsonfile = json.loads(html.read().decode('utf-8'))

これで変数jsonfile内にデータが格納されました。jsonfileを呼び出してやるとそれっぽいデータが返ってきます。 以下はiPython環境での出力サンプルです。

In [1]jsonfile
Out[1]: 
{'copyright': {'image': {'height': 26,
   'link': 'http://weather.livedoor.com/',
   'title': 'livedoor 天気情報',
   'url': 'http://weather.livedoor.com/img/cmn/livedoor.gif',
   'width': 118},
  'link': 'http://weather.livedoor.com/',
  'provider': [{'link': 'http://tenki.jp/', 'name': '日本気象協会'}],
  'title': '(C) LINE Corporation'},
 'description': {'publicTime': '2016-04-30T16:32:00+0900',
  'text': ' 九州北部地方は、高気圧に覆われ、晴れています。\n\n 30日の九州北部地方は、高気圧に覆われ、晴れでしょう。\n\n 5月1日の九州北部地方は、高気圧に覆われ、晴れでしょう。\n\n 波の高さは、対馬海峡では30日と5月1日は2メートルでしょう。九州\n西海上では30日と5月1日は1.5メートルでしょう。豊後水道では30\n日と5月1日は1メートルでしょう。\n 福岡県の内海では、30日と5月1日は0.5メートルでしょう。\n\n<天気変化等の留意点>\n 特にありません。'},
 'forecasts': [{'date': '2016-04-30',
   'dateLabel': '今日',
   'image': {'height': 31,
    'title': '晴れ',
    'url': 'http://weather.livedoor.com/img/icon/1.gif',
    'width': 50},
   'telop': '晴れ',
   'temperature': {'max': None, 'min': None}},
  {'date': '2016-05-01',
   'dateLabel': '明日',
   'image': {'height': 31,
    'title': '晴れ',
    'url': 'http://weather.livedoor.com/img/icon/1.gif',
    'width': 50},
   'telop': '晴れ',
   'temperature': {'max': {'celsius': '26', 'fahrenheit': '78.8'},
    'min': {'celsius': '12', 'fahrenheit': '53.6'}}},
  {'date': '2016-05-02',
   'dateLabel': '明後日',
   'image': {'height': 31,
    'title': '晴のち曇',
    'url': 'http://weather.livedoor.com/img/icon/5.gif',
    'width': 50},
   'telop': '晴のち曇',
   'temperature': {'max': None, 'min': None}}],
 'link': 'http://weather.livedoor.com/area/forecast/400040',
 'location': {'area': '九州', 'city': '久留米', 'prefecture': '福岡県'},
 'pinpointLocations': [{'link': 'http://weather.livedoor.com/area/forecast/4020200',
   'name': '大牟田市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4020300',
   'name': '久留米市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4020700', 'name': '柳川市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4021000', 'name': '八女市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4021100', 'name': '筑後市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4021200', 'name': '大川市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4021600', 'name': '小郡市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4022500',
   'name': 'うきは市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4022800', 'name': '朝倉市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4022900',
   'name': 'みやま市'},
  {'link': 'http://weather.livedoor.com/area/forecast/4044700', 'name': '筑前町'},
  {'link': 'http://weather.livedoor.com/area/forecast/4044800', 'name': '東峰村'},
  {'link': 'http://weather.livedoor.com/area/forecast/4050300',
   'name': '大刀洗町'},
  {'link': 'http://weather.livedoor.com/area/forecast/4052200', 'name': '大木町'},
  {'link': 'http://weather.livedoor.com/area/forecast/4054400',
   'name': '広川町'}],
 'publicTime': '2016-04-30T17:00:00+0900',
 'title': '福岡県 久留米 の天気'}

要素ごとにアクセスしようとおもったら、パースした後の変数に引数を渡します。

In [1]:jsonfile['description']
Out[1]: 
{'publicTime': '2016-04-30T16:32:00+0900',
 'text': ' 九州北部地方は、高気圧に覆われ、晴れています。\n\n 30日の九州北部地方は、高気圧に覆われ、晴れでしょう。\n\n 5月1日の九州北部地方は、高気圧に覆われ、晴れでしょう。\n\n 波の高さは、対馬海峡では30日と5月1日は2メートルでしょう。九州\n西海上では30日と5月1日は1.5メートルでしょう。豊後水道では30\n日と5月1日は1メートルでしょう。\n 福岡県の内海では、30日と5月1日は0.5メートルでしょう。\n\n<天気変化等の留意点>\n 特にありません。'}

はまりどころ

Python2系のurllib2ではエンコーディング処理までやってくれていたような気がします。 Python3のurllibではデコードしないとエラーが出ます。JSONのパース時にdecode('utf-8')でデコードします。

やりたいこと

これ使って総務省API(Ver2)を上手くたたく方法模索中。

追記

Pythonの2系ではurllib2を使ってURLを読み込むのが通例でした。

import urllib
import urllib2

url = urllib2.urlopen('http://www.hogehoge.com')

python3系ではurllib2の持っていた機能がurllibに統合され、urllib.requestから呼び出せるようになっているようです。