Google Colaboratoryを使って、BODIK APIを使ったPythonプログラムを書いてみます。

課題1:BODIK APIを呼び出してみる

問題:BODIK APIを使って、AEDを検索してみる。

基本情報

  • PythonからWebAPIを呼び出す方法はいくつかありますが、ここでは「requests」を使います。
  • BODIK APIの検索結果はJSON形式で取得できます。
  • 検索結果は辞書形式データの配列になっています。
  • Pythonで配列の各要素を調べる場合、「for ... in ...」を使います。

swaggerで試す

最初に、WAPIのswagger(https://wapi.bodik.jp/docs)でAPIを試してみましょう。

AED(GET /aed)のエンドポイントを表示し、「try it out」のボタンを押して、下の方にある青い「Execute」ボタンを押します。

検索結果が表示されます。「Request URL」のところを確認します。

「Request URL」は「?」の前方がAPIのURL部分、後方がパラメータになります。

    URL部分       パラメータ部分
https://wapi.bodik.jp/aed?select_type=data&maxResults=10&distance=2000

URL部分

https://wapi.bodik.jp/aed

これを分解すると
 BODIK APIのURL:https://wapi.bodik.jp
 データセット名:aed

パラメータ部分:複数のパラメータが「&」で結合されています。

select_type=data&maxResults=10&distance=2000

これを分解すると
 select_type=data
 maxResults=10
 distance=2000

pythonで記述

では、Pythonで「BODIK API」を呼び出してみましょう。

「python requests」で検索すると、requestsの使い方を説明したサイトが見つかりますので、参考にしてください。

ライブラリのimport

まず、必要なライブラリを宣言します

import requests
import json

Pythonで「requests」ライブラリを使ってWebAPIを呼び出すときは、次のような流れになります。

url = 'https://xxxxxxxx?a=123&b=456&c=789'   # WebAPIのURLを用意する
response = requests.get(url)          # requestsのgetメソッドを実行する
data = response.json()             # 結果のJSONを取り出す

この流れに合わせて、BODIK APIを呼び出してみましょう。

WebAPIのURLを用意する

WebAPIのURLは、APIサーバーのURLとパラメータの組み合わせになります。Pythonで文字列を組み立てる方法はいくつかありますが、「f文字列」が便利です。

api_server = 'https://wapi.bodik.jp'
apiname = 'aed'
url = f'{api_server}/{apiname}'

requestsのgetメソッドを実行

response = requests.get(url)

結果のJSONを取り出す

「response」のjsonメソッドを呼び出すと、APIの実行結果をJSONで取り出すことができます。取り出したデータは、print関数で表示することができます。

data = response.json()
print(data)

プログラム(Ver1)

まとめると次のようになります。

import requests
import json

api_server = 'https://wapi.bodik.jp'
apiname = 'aed'
url = f'{api_server}/{apiname}'
response = requests.get(url)
data = response.json()
print(data)

このプログラムを実行すると、「data」の内容が表示されます。

「data」の中は次のような形式になっています。

{
  'metadata': {
    'api': 'aed',
    'selectType': 'DATA',
    'totalCount': 27430,
    'count': 10
  },
  'resultsets': {
    'type': 'FeatureCollection',
    'features': [
      {
        'type': 'Feature',
        'properties': {
          'municipalityCode': '12301',
          'ID': '',
          'municipalityName': '北海道三笠市',
           ・・・・・・・
        }
      }
   ・・・・・・・・
    ]
  }
}

BODIK APIの実行結果の構造は、次のようになります。

data = {
  metadata
  resultsets: {
    features: [    配列
      feature   辞書
      feature   辞書
      ・・・・
    ]
  }
}

featureは次のようになります。

feature = {
  properties,     # 各種属性情報
  geometry        # 位置情報
}

このデータ構造をpythonで解析するには、次のようなプログラムを書きます。

features = data['resultsets']['features']    # featuresは配列
for feature in features:                     # 配列は、「for .. in」で回す
  properties = feature['properties']         # propertiesは辞書
  print(properties)                          # 表示する

プログラム(Ver2)

まとめると次のようになります。

import requests
import json

api_server = 'https://wapi.bodik.jp'
apiname = 'aed'
url = f'{api_server}/{apiname}'
response = requests.get(url)
data = response.json()
features = data['resultsets']['features']
for feature in features:
  properties = feature['properties']
  print(properties)

辞書である「properties」をそのまま表示してもわかりにくいですね。このようなときは、json.dumpsメソッドを使って、辞書を整形します。

プログラム(Ver3)

import requests
import json

api_server = 'https://wapi.bodik.jp'
apiname = 'aed'
url = f'{api_server}/{apiname}'
response = requests.get(url)
data = response.json()
features = data['resultsets']['features']
for feature in features:
  properties = feature['properties']
  print(json.dumps(properties, indent=2))

日本語部分がおかしな表示になっているので、対応します。

プログラム(Ver4)

import requests
import json

api_server = 'https://wapi.bodik.jp'
apiname = 'aed'
url = f'{api_server}/{apiname}'
response = requests.get(url)
data = response.json()
features = data['resultsets']['features']
for feature in features:
  properties = feature['properties']
  print(json.dumps(properties, indent=2, ensure_ascii=False))

プログラム(完成版)

実際には、コメントとエラー処理を入れて、完成です。

import requests
import json

try:
  # BODIK APIを呼び出す準備
  api_server = 'https://wapi.bodik.jp'
  apiname = 'aed'
  url = f'{api_server}/{apiname}'

  # BODIK APIを呼び出す
  response = requests.get(url, timeout=5.0)

  # APIの実行結果を確認する
  if response is not None and response.status_code == 200:
    # 結果をJSONで取得する
    data = response.json()

    # BODIK APIの検索結果を解析する
    if data is not None and 'resultsets' in data:
      resultsets = data['resultsets']
      if 'features' in resultsets:
        features = resultsets['features']
        for feature in features:
          properties = feature['properties']
          print(json.dumps(properties, indent=2, ensure_ascii=False))
      else:
        print('no features', resultsets)
    else:
      print('no resultsets', data)
  else:
    print('status_code', response)

except Exception as e:
  # 例外が発生
  print('Exception', e)

お疲れ様でした。