note.nkmk.me

PythonでRESAS APIを使ってデータをダウンロード

Date: 2018-06-10 / tags: Python, pandas, スクレイピング
このエントリーをはてなブックマークに追加

RESASは「Regional Economy Society Analyzing System(地域経済分析システム)」の略。市区町村別の産業・経済の情報が提供されており、APIを利用して生データをダウンロードできる。

ここでは、PythonからRESAS APIを利用してデータをJSONやCSV形式でダウンロードする方法を説明する。

  • RESAS APIの基本的な使い方
    • APIキーを取得
    • 仕様と使い方
    • RESAS-API一覧
  • 例: 都道府県コード
    • データを取得
    • JSONで保存
    • pandas.DataFrameに変換
    • CSVで保存
  • 例: 市区町村コード
    • 都道府県を指定して個別にダウンロード
    • 全都道府県のデータを一括ダウンロード
      • pandas.DataFrameに変換して連結
      • CSVで保存
      • JSONで保存
  • 例: 一人当たり地方税

政府統計の総合窓口e-StatのAPIをPythonから利用する方法は以下の記事を参照。日本全体や都道府県別のデータが主だがRESASより種類が豊富。

スポンサーリンク

RESAS APIの基本的な使い方

APIキーを取得

RESAS APIを利用するにはAPIキーが必要。以下のページから利用登録する。

利用登録完了後、RESAS-APIトップページからログインすると、マイページにAPIキーが記載されている。

仕様と使い方

仕様は以下のページを参照。

リクエストヘッダーX-API-KEYにAPIキーを設定し、そのほかのパラメータはクエリ文字列で指定してアクセスする。シンプルなGETメソッドで特に難しいことはない。

詳細は以降の具体例で説明する。

なお、呼び出し回数制限があるので注意。

RESAS-API一覧

利用できるデータの一覧は以下のページを参照。

企業数や従業員数などの産業関係のデータから一人当たり賃金、有効求人倍率などの雇用関係のデータまでいろいろある。

例: 都道府県コード

具体例として、都道府県コードをRESAS APIで取得する。都道府県コードはRESAS APIでほかのデータを取得する際に対象の都道府県を指定するためにも使われる。

データを取得

各種ライブラリをインポート。pprintは出力を見やすくするためだけに使用しているのでデータの取得には不要。pandas以外は標準ライブラリに含まれている。pandasのみ別途インストールが必要。

サードパーティモジュールのRequestsを使ってもいいが、ここでは標準ライブラリのurllib.requestを使っている。

import json
import urllib.request
import pprint
import pandas as pd

利用登録して取得したAPIキーを記載したファイルapi_key.jsonを用意する。以下のサンプルのようにリクエストヘッダー名X-API-KEYをキーとする。

with open('setting/api_key_sample.json') as f:
    print(f.read())
# {"X-API-KEY":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}

これをjson.load()で辞書(dict型オブジェクト)として読み込む。

with open('setting/api_key_sample.json') as f:
    api_key_sample = json.load(f)

print(api_key_sample)
# {'X-API-KEY': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}

print(type(api_key_sample))
# <class 'dict'>

なお、リクエストヘッダー名X-API-KEYをキーとする辞書が作成できれば別の方法でも問題ない。

リクエストヘッダーを含むURLリクエストを行うために、引数にURLとリクエストヘッダー名X-API-KEYをキーとする辞書を指定してurllib.request.Request()でリクエストオブジェクトを生成する。

with open('setting/api_key.json') as f:
    api_key = json.load(f)

url = 'https://opendata.resas-portal.go.jp/api/v1/prefectures'

req = urllib.request.Request(url, headers=api_key)

print(type(req))
# <class 'urllib.request.Request'>

そのリクエストオブジェクトでURLを開きデータを取得。取得できるのはバイト列(bytes型オブジェクト)。

with urllib.request.urlopen(req) as response:
    data = response.read()

print(type(data))
# <class 'bytes'>

バイト列をdecode()メソッドで文字列にデコードし、json.loads()で辞書に変換する。Python3.6以降はjson.loads()に直接バイト列を指定できるようになったのでdecode()は不要。

d = json.loads(data.decode())

pprint.pprint(d)
# {'message': None,
#  'result': [{'prefCode': 1, 'prefName': '北海道'},
#             {'prefCode': 2, 'prefName': '青森県'},
#             {'prefCode': 3, 'prefName': '岩手県'},
#             {'prefCode': 4, 'prefName': '宮城県'},
#             {'prefCode': 5, 'prefName': '秋田県'},
#             {'prefCode': 6, 'prefName': '山形県'},
#             {'prefCode': 7, 'prefName': '福島県'},
#             {'prefCode': 8, 'prefName': '茨城県'},
#             {'prefCode': 9, 'prefName': '栃木県'},
#             {'prefCode': 10, 'prefName': '群馬県'},
#             {'prefCode': 11, 'prefName': '埼玉県'},
#             {'prefCode': 12, 'prefName': '千葉県'},
#             {'prefCode': 13, 'prefName': '東京都'},
#             {'prefCode': 14, 'prefName': '神奈川県'},
#             {'prefCode': 15, 'prefName': '新潟県'},
#             {'prefCode': 16, 'prefName': '富山県'},
#             {'prefCode': 17, 'prefName': '石川県'},
#             {'prefCode': 18, 'prefName': '福井県'},
#             {'prefCode': 19, 'prefName': '山梨県'},
#             {'prefCode': 20, 'prefName': '長野県'},
#             {'prefCode': 21, 'prefName': '岐阜県'},
#             {'prefCode': 22, 'prefName': '静岡県'},
#             {'prefCode': 23, 'prefName': '愛知県'},
#             {'prefCode': 24, 'prefName': '三重県'},
#             {'prefCode': 25, 'prefName': '滋賀県'},
#             {'prefCode': 26, 'prefName': '京都府'},
#             {'prefCode': 27, 'prefName': '大阪府'},
#             {'prefCode': 28, 'prefName': '兵庫県'},
#             {'prefCode': 29, 'prefName': '奈良県'},
#             {'prefCode': 30, 'prefName': '和歌山県'},
#             {'prefCode': 31, 'prefName': '鳥取県'},
#             {'prefCode': 32, 'prefName': '島根県'},
#             {'prefCode': 33, 'prefName': '岡山県'},
#             {'prefCode': 34, 'prefName': '広島県'},
#             {'prefCode': 35, 'prefName': '山口県'},
#             {'prefCode': 36, 'prefName': '徳島県'},
#             {'prefCode': 37, 'prefName': '香川県'},
#             {'prefCode': 38, 'prefName': '愛媛県'},
#             {'prefCode': 39, 'prefName': '高知県'},
#             {'prefCode': 40, 'prefName': '福岡県'},
#             {'prefCode': 41, 'prefName': '佐賀県'},
#             {'prefCode': 42, 'prefName': '長崎県'},
#             {'prefCode': 43, 'prefName': '熊本県'},
#             {'prefCode': 44, 'prefName': '大分県'},
#             {'prefCode': 45, 'prefName': '宮崎県'},
#             {'prefCode': 46, 'prefName': '鹿児島県'},
#             {'prefCode': 47, 'prefName': '沖縄県'}]}

JSONで保存

json.dump()でJSON形式で保存できる。

上で取得したバイト列をdecode()メソッドでデコードした文字列をそのままファイルに保存してもいいが、json.loads()で辞書に変換してからjson.dump()で保存すると、引数indentでインデントを指定したり、引数ensure_asciiでUnicodeエスケープするかどうかを指定できて便利。

with open('download/pref_code_list.json', 'w') as f:
    json.dump(d, f, ensure_ascii=False, indent=4)

デフォルトではJSONの仕様に則って日本語などが\uXXXXのようなUnicodeエスケープシーケンスで保存され、文字化けしたように見えるので注意。引数ensure_ascii=Falseとするとエスケープされずに保存される。

データ部分(レコード部分)のみを保存したい場合はjson.dump()の引数をd['result']とする。

pandas.DataFrameに変換

辞書のリストとなっているデータ部分(レコード部分)はpandas.io.json.json_normalize()pandas.DataFrameに変換できる。

df = pd.io.json.json_normalize(d['result'])
print(df.head())
#    prefCode prefName
# 0         1      北海道
# 1         2      青森県
# 2         3      岩手県
# 3         4      宮城県
# 4         5      秋田県

実際にデータを利用する際は、都道府県コードから都道府県名を取得したり、都道府県名から都道府県コードを取得したりしたい。

このために、set_index()indexを指定したうえで、列をpandas.Seriesとして抽出する。

s_code = df.set_index('prefCode')['prefName']
print(s_code.head())
# prefCode
# 1    北海道
# 2    青森県
# 3    岩手県
# 4    宮城県
# 5    秋田県
# Name: prefName, dtype: object

都道府県コードから都道府県名を取得できる。ただし、存在しない都道府県コードを指定するとエラーKeyError

print(s_code[13])
# 東京都

# print(s_code[100])
# KeyError: 100

pandas.Seriesto_dict()で辞書に変換できる。辞書のget()メソッドを使うと存在しない都道府県コードに対してNoneや指定したデフォルト値を返すようにできる。

d_code = df.set_index('prefCode')['prefName'].to_dict()

print(d_code[13])
# 東京都

# print(d_code[100])
# KeyError: 100

print(d_code.get(13))
# 東京都

print(d_code.get(100))
# None

場合によってはpandas.Seriesで例外処理をするより辞書に変換してget()メソッドを使ったほうが楽。

都道府県名から都道府県コードを取得するのも同様の方法で可能。

s_name = df.set_index('prefName')['prefCode']
print(s_name.head())
# prefName
# 北海道    1
# 青森県    2
# 岩手県    3
# 宮城県    4
# 秋田県    5
# Name: prefCode, dtype: int64

print(s_name['東京都'])
# 13

d_name = df.set_index('prefName')['prefCode'].to_dict()

print(d_name['東京都'])
# 13

print(d_name.get('東京都'))
# 13

CSVで保存

pandas.DataFrameto_csv()メソッドでCSVファイルとして保存できる。

df.to_csv('download/pref_code_list.csv', index=None)

CSVファイルをpandas.DataFrameとして読み出したい場合はpandas.read_csv()関数を使う。

df_from_csv = pd.read_csv('download/pref_code_list.csv')
print(df_from_csv.head())
#    prefCode prefName
# 0         1      北海道
# 1         2      青森県
# 2         3      岩手県
# 3         4      宮城県
# 4         5      秋田県

例: 市区町村コード

次の具体例として、市区町村コードをRESAS APIで取得する。

都道府県を指定して個別にダウンロード

都道府県を指定して個別にダウンロードする場合は、上の都道府県コードの例とほぼ同じ。

パラメータとして都道府県コードを指定する必要がある。urllib.parse.urlencode()に辞書を渡してクエリ文字列を取得する。パラメータが複数ある場合やURLエンコード(パーセントエンコード)が必要な場合も、urllib.parse.urlencode()が処理してくれる。

import json
import urllib.parse
import urllib.request
import pprint
import pandas as pd

url_base = 'https://opendata.resas-portal.go.jp/api/v1/cities'

p = {'prefCode': 13}
url = url_base + '?' + urllib.parse.urlencode(p)
print(url)
# https://opendata.resas-portal.go.jp/api/v1/cities?prefCode=13

この例の場合は都道府県コードを数値で指定するだけなので、単純に文字列を連結してもOK。

pref_code = 13
url = url_base + '?prefCode=' + str(pref_code)
print(url)
# https://opendata.resas-portal.go.jp/api/v1/cities?prefCode=13

あとの流れは上の都道府県コードの例と同じ。

with open('setting/api_key.json') as f:
    api_key = json.load(f)

req = urllib.request.Request(url, headers=api_key)

with urllib.request.urlopen(req) as response:
    data = response.read()

d = json.loads(data.decode())

pprint.pprint(d, width=100)
# {'message': None,
#  'result': [{'bigCityFlag': '3', 'cityCode': '13101', 'cityName': '千代田区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13102', 'cityName': '中央区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13103', 'cityName': '港区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13104', 'cityName': '新宿区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13105', 'cityName': '文京区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13106', 'cityName': '台東区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13107', 'cityName': '墨田区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13108', 'cityName': '江東区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13109', 'cityName': '品川区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13110', 'cityName': '目黒区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13111', 'cityName': '大田区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13112', 'cityName': '世田谷区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13113', 'cityName': '渋谷区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13114', 'cityName': '中野区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13115', 'cityName': '杉並区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13116', 'cityName': '豊島区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13117', 'cityName': '北区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13118', 'cityName': '荒川区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13119', 'cityName': '板橋区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13120', 'cityName': '練馬区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13121', 'cityName': '足立区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13122', 'cityName': '葛飾区', 'prefCode': 13},
#             {'bigCityFlag': '3', 'cityCode': '13123', 'cityName': '江戸川区', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13201', 'cityName': '八王子市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13202', 'cityName': '立川市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13203', 'cityName': '武蔵野市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13204', 'cityName': '三鷹市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13205', 'cityName': '青梅市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13206', 'cityName': '府中市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13207', 'cityName': '昭島市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13208', 'cityName': '調布市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13209', 'cityName': '町田市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13210', 'cityName': '小金井市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13211', 'cityName': '小平市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13212', 'cityName': '日野市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13213', 'cityName': '東村山市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13214', 'cityName': '国分寺市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13215', 'cityName': '国立市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13218', 'cityName': '福生市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13219', 'cityName': '狛江市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13220', 'cityName': '東大和市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13221', 'cityName': '清瀬市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13222', 'cityName': '東久留米市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13223', 'cityName': '武蔵村山市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13224', 'cityName': '多摩市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13225', 'cityName': '稲城市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13227', 'cityName': '羽村市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13228', 'cityName': 'あきる野市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13229', 'cityName': '西東京市', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13303', 'cityName': '瑞穂町', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13305', 'cityName': '日の出町', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13307', 'cityName': '檜原村', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13308', 'cityName': '奥多摩町', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13361', 'cityName': '大島町', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13362', 'cityName': '利島村', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13363', 'cityName': '新島村', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13364', 'cityName': '神津島村', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13381', 'cityName': '三宅村', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13382', 'cityName': '御蔵島村', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13401', 'cityName': '八丈町', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13402', 'cityName': '青ヶ島村', 'prefCode': 13},
#             {'bigCityFlag': '0', 'cityCode': '13421', 'cityName': '小笠原村', 'prefCode': 13}]}

JSONで保存したい場合はjson.dump()、CSVで保存したい場合はpandas.io.json.json_normalize()pandas.DataFrameに変換してからto_csv()を使う。

全都道府県のデータを一括ダウンロード

個別の都道府県のデータではなく、全都道府県の市区町村のデータ一覧を取得する方法を説明する。

pandas.DataFrameに変換して連結

空のリストを作成し、全都道府県(都道府県コード1〜47)までのデータをpandas.DataFrameに変換して格納、pandas.concat()関数で連結する。

l = []
url_base = 'https://opendata.resas-portal.go.jp/api/v1/cities'

for pref_code in range(1, 48):
    url = url_base + '?prefCode=' + str(pref_code)
    req = urllib.request.Request(url, headers=api_key)
    with urllib.request.urlopen(req) as response:
        data = response.read()
    d = json.loads(data.decode())
    l.append(pd.io.json.json_normalize(d['result']))

df_all = pd.concat(l, ignore_index=True)

全都道府県のデータを取得するのに1分ほどかかる。

1920行のpandas.DataFrameが生成される。都道府県コードを表すprefCode列のみが数値型。

print(df_all.head())
#   bigCityFlag cityCode cityName  prefCode
# 0           2    01100      札幌市         1
# 1           1    01101   札幌市中央区         1
# 2           1    01102    札幌市北区         1
# 3           1    01103    札幌市東区         1
# 4           1    01104   札幌市白石区         1

print(df_all.shape)
# (1920, 4)

print(df_all.dtypes)
# bigCityFlag    object
# cityCode       object
# cityName       object
# prefCode        int64
# dtype: object

特別区・行政区フラグbigCityFlagを使って政令指定都市の市の一覧を取得したり、特定の都道府県の政令指定都市の区の一覧を取得したりできる。

print(df_all.query('bigCityFlag == "2"'))
#      bigCityFlag cityCode cityName  prefCode
# 0              2    01100      札幌市         1
# 265            2    04100      仙台市         4
# 529            2    11100    さいたま市        11
# 602            2    12100      千葉市        12
# 724            2    14100      横浜市        14
# 743            2    14130      川崎市        14
# 751            2    14150     相模原市        14
# 785            2    15100      新潟市        15
# 1020           2    22100      静岡市        22
# 1024           2    22130      浜松市        22
# 1065           2    23100     名古屋市        23
# 1183           2    26100      京都市        26
# 1220           2    27100      大阪市        27
# 1245           2    27140       堺市        27
# 1294           2    28100      神戸市        28
# 1451           2    33100      岡山市        33
# 1482           2    34100      広島市        34
# 1627           2    40100     北九州市        40
# 1635           2    40130      福岡市        40
# 1742           2    43100      熊本市        43

print(df_all.query('bigCityFlag == "1" & prefCode == 14'))
#     bigCityFlag cityCode  cityName  prefCode
# 725           1    14101    横浜市鶴見区        14
# 726           1    14102   横浜市神奈川区        14
# 727           1    14103     横浜市西区        14
# 728           1    14104     横浜市中区        14
# 729           1    14105     横浜市南区        14
# 730           1    14106  横浜市保土ケ谷区        14
# 731           1    14107    横浜市磯子区        14
# 732           1    14108    横浜市金沢区        14
# 733           1    14109    横浜市港北区        14
# 734           1    14110    横浜市戸塚区        14
# 735           1    14111    横浜市港南区        14
# 736           1    14112     横浜市旭区        14
# 737           1    14113     横浜市緑区        14
# 738           1    14114    横浜市瀬谷区        14
# 739           1    14115     横浜市栄区        14
# 740           1    14116     横浜市泉区        14
# 741           1    14117    横浜市青葉区        14
# 742           1    14118    横浜市都筑区        14
# 744           1    14131    川崎市川崎区        14
# 745           1    14132     川崎市幸区        14
# 746           1    14133    川崎市中原区        14
# 747           1    14134    川崎市高津区        14
# 748           1    14135    川崎市多摩区        14
# 749           1    14136    川崎市宮前区        14
# 750           1    14137    川崎市麻生区        14
# 752           1    14151    相模原市緑区        14
# 753           1    14152   相模原市中央区        14
# 754           1    14153    相模原市南区        14

市区町村コードから市区町村名を取得したり、市区町村名から市区町村コードを取得したりしたい場合は、上述の都道府県コードの例のようにset_index()indexを指定したうえで、列をpandas.Seriesとして抽出する。

s_code = df_all.set_index('cityCode')['cityName']
print(s_code.head())
# cityCode
# 01100       札幌市
# 01101    札幌市中央区
# 01102     札幌市北区
# 01103     札幌市東区
# 01104    札幌市白石区
# Name: cityName, dtype: object

print(s_code['14100'])
# 横浜市

s_name = df_all.set_index('cityName')['cityCode']
print(s_name.head())
# cityName
# 札幌市       01100
# 札幌市中央区    01101
# 札幌市北区     01102
# 札幌市東区     01103
# 札幌市白石区    01104
# Name: cityCode, dtype: object

print(s_name['横浜市'])
# 14100

CSVで保存

CSVファイルをとして保存するにはto_csv()メソッドを使う。

df_all.to_csv('download/city_code_list.csv', index=None)

JSONで保存

JSONファイルとして保存するにはto_json()メソッドを使う。

df_all.to_json('download/city_code_list.json', orient='records', force_ascii=False)

records形式では辞書のリストで保存される。

保存したJSONファイルの読み込み方法は以下の通り。

json.load()で読み込み。

with open('download/city_code_list.json') as f:
    data_json = json.load(f)

print(type(data_json))
# <class 'list'>

pprint.pprint(data_json[:5])
# [{'bigCityFlag': '2', 'cityCode': '01100', 'cityName': '札幌市', 'prefCode': 1},
#  {'bigCityFlag': '1', 'cityCode': '01101', 'cityName': '札幌市中央区', 'prefCode': 1},
#  {'bigCityFlag': '1', 'cityCode': '01102', 'cityName': '札幌市北区', 'prefCode': 1},
#  {'bigCityFlag': '1', 'cityCode': '01103', 'cityName': '札幌市東区', 'prefCode': 1},
#  {'bigCityFlag': '1', 'cityCode': '01104', 'cityName': '札幌市白石区', 'prefCode': 1}]

print(len(data_json))
# 1920

pandas.read_json()pandas.DataFrameとして読み込み。

df_from_json = pd.read_json('download/city_code_list.json')
print(df_from_json.head())
#    bigCityFlag  cityCode cityName  prefCode
# 0            2      1100      札幌市         1
# 1            1      1101   札幌市中央区         1
# 2            1      1102    札幌市北区         1
# 3            1      1103    札幌市東区         1
# 4            1      1104   札幌市白石区         1

print(df_from_json.shape)
# (1920, 4)

例: 一人当たり地方税

最後の例として、一人当たり地方税をRESAS APIで取得する。

パラメータとして都道府県コードと市区町村コードを指定する。

これまでの例との違いは、取得できるJSONのresultキーの値がレコード形式(辞書のリスト)ではない点。

import json
import urllib.parse
import urllib.request
import pprint
import pandas as pd

url_base = 'https://opendata.resas-portal.go.jp/api/v1/municipality/taxes/perYear'

p = {'prefCode': 13, 'cityCode': 13103}
url = url_base + '?' + urllib.parse.urlencode(p)
print(url)
# https://opendata.resas-portal.go.jp/api/v1/municipality/taxes/perYear?prefCode=13&cityCode=13103

with open('setting/api_key.json') as f:
    api_key = json.load(f)

req = urllib.request.Request(url, headers=api_key)

with urllib.request.urlopen(req) as response:
    data = response.read()

d = json.loads(data.decode())

pprint.pprint(d)
# {'message': None,
#  'result': {'cityCode': '13103',
#             'cityName': '港区',
#             'data': [{'value': 335, 'year': 2008},
#                      {'value': 326, 'year': 2009},
#                      {'value': 286, 'year': 2010},
#                      {'value': 277, 'year': 2011},
#                      {'value': 254, 'year': 2012},
#                      {'value': 262, 'year': 2013},
#                      {'value': 304, 'year': 2014}],
#             'prefCode': 13,
#             'prefName': '東京都'}}

これをpandas.DataFrameに変換する場合、pandas.io.json.json_normalize()の引数にそのまま指定するとうまくいかない。

print(pd.io.json.json_normalize(d['result']))
#   cityCode cityName                                               data  \
# 0    13103       港区  [{'year': 2008, 'value': 335}, {'year': 2009, ...   
#    prefCode prefName  
# 0        13      東京都  

引数record_pathにレコード形式(辞書のリスト)のデータが格納されているキーを指定するとOK。

print(pd.io.json.json_normalize(d['result'], record_path='data'))
#    value  year
# 0    335  2008
# 1    326  2009
# 2    286  2010
# 3    277  2011
# 4    254  2012
# 5    262  2013
# 6    304  2014

複数の市区町村のデータを連結したい場合など、同階層の値も含むpandas.DataFrameを取得したい場合は引数metaを指定する。

print(pd.io.json.json_normalize(d['result'], record_path='data',
                                meta=['cityCode', 'cityName', 'prefCode', 'prefName']))
#    value  year cityCode cityName  prefCode prefName
# 0    335  2008    13103       港区        13      東京都
# 1    326  2009    13103       港区        13      東京都
# 2    286  2010    13103       港区        13      東京都
# 3    277  2011    13103       港区        13      東京都
# 4    254  2012    13103       港区        13      東京都
# 5    262  2013    13103       港区        13      東京都
# 6    304  2014    13103       港区        13      東京都

詳細は以下の記事を参照。

上で説明した全都道府県のデータを一括ダウンロードする場合は都道府県コード1〜47を連番で指定すればよかったが、複数の市区町村のデータを一括で取得したい場合は市区町村コードのリストが必要。

上で取得した市区町村コードを含むpandas.DataFrameから市区町村コードのリストを取得する例を示す。

query()メソッドで条件を満たす行を抽出。

df_city = pd.read_csv('download/city_code_list.csv')

print(df_city.query('prefCode == 40 & bigCityFlag == 1'))
#       bigCityFlag  cityCode  cityName  prefCode
# 1628            1     40101   北九州市門司区        40
# 1629            1     40103   北九州市若松区        40
# 1630            1     40105   北九州市戸畑区        40
# 1631            1     40106  北九州市小倉北区        40
# 1632            1     40107  北九州市小倉南区        40
# 1633            1     40108  北九州市八幡東区        40
# 1634            1     40109  北九州市八幡西区        40
# 1636            1     40131     福岡市東区        40
# 1637            1     40132    福岡市博多区        40
# 1638            1     40133    福岡市中央区        40
# 1639            1     40134     福岡市南区        40
# 1640            1     40135     福岡市西区        40
# 1641            1     40136    福岡市城南区        40
# 1642            1     40137    福岡市早良区        40

そこから市区町村コードの列を選択し、values属性でNumPy配列ndarrayを得る。

a = df_city.query('prefCode == 40 & bigCityFlag == 1')['cityCode'].values

print(a)
# [40101 40103 40105 40106 40107 40108 40109 40131 40132 40133 40134 40135
#  40136 40137]

print(type(a))
# <class 'numpy.ndarray'>

for code in a:
    print(code)
# 40101
# 40103
# 40105
# 40106
# 40107
# 40108
# 40109
# 40131
# 40132
# 40133
# 40134
# 40135
# 40136
# 40137

NumPy配列ndarrayをfor文で回し、各市区町村コードでAPIにアクセスすればOK。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事