Python | POI データを取得して、地点の天気を得る

https://github.com/daisuke-t-jp/overpass_weather

今回作成したプロジェクトは GitHub に置いた。



概要

OpenWeatherMap API を使うと、呼び出し頻度の制限はあるが、無料で天気情報を取得できる。

https://openweathermap.org/

この取得する天気情報を、意味のある集まりにしたい。たとえば、全国の公共施設の天気、駅の天気などだ。

こういった地点の情報(POI)は、OSM から node として無料で取得できる。そして OSM のデータは Overpass という APIプログラマブルに取得できる。

https://wiki.openstreetmap.org/wiki/JA:Overpass_API

上記から今回は、以下の流れを試す。

  • ステップ1
    • Overpass API で、POI データを取得。
  • ステップ2
    • OpenWeatherMap API で、POI の天気を取得する。

Overpass API

Overpass API は、サーバにクエリをリクエストして、マッチした OSM データをレスポンスを受け取る使い方になる。

たとえば、世界の大聖堂(カテドラル)を抽出したい場合のクエリは以下。

[out:json];
node["building"="cathedral"];
out body;

日本全国の公共施設を抽出したい場合は以下。

[out:json];
area["name"~"日本"];
node(area)["amenity"="townhall"];
out body;

このクエリを簡単に試すには、以下のサイトを使うと良い。

https://overpass-turbo.eu/

Python から Overpass API を使用するには、以下の overpy ライブラリを使う。

https://pypi.org/project/overpy/

OpenWeatherMap

Overpass API で得た POI の緯度経度から、OpenWeatherMap API で得るには下の格好になる。

https://api.openweathermap.org/data/2.5/weather?appid=APP_KEY&lat=35.658316&lon=139.741423

API キーが必要になるため、事前に取得する。

ここで気をつけたいのが、無料アカウントでは、1分に60回までリクエストが制限されているので、リクエストごとに1秒のウェイトを挟むことで、制限を避ける。

実行例

上記を踏まえて作成した Python スクリプト(overpass_weather)を試してみる。

詳しくは README.md を参照することだが、流れを書くと

Git clone してきて

$ git clone https://github.com/daisuke-t-jp/overpass_weather

必要なパッケージをインストールする

$ pip3 install overpy
$ pip3 install attrdict

overpass_weather を import して、こんなスクリプトを実行すると

#!/usr/bin/python
# coding: UTF-8

import sys
import logging
import enum

sys.path.append('../')
import overpass_weahter

def test_dump_weather(weather):
    osm = weather[overpass_weahter.KEY_OSM]
    openweathermap_weather = weather[overpass_weahter.KEY_OPENWEATHERMAP_CURRENT_WEATHER_DATA]
    
    logging.debug('osm_id[{0}] name[{1}] lat[{2}] lon[{3}] temp[{4}] pressure[{5}] humidity[{6}]'.format(
        osm[overpass_weahter.KEY_ID],
        osm[overpass_weahter.KEY_NAME],
        osm[overpass_weahter.KEY_LAT],
        osm[overpass_weahter.KEY_LON],
        openweathermap_weather['main']['temp'],
        openweathermap_weather['main']['pressure'],
        openweathermap_weather['main']['humidity']))
    
    return

def test_overpass_api():    
    try:
        weathers = overpass_weahter.weathers_with_overpass_api("""
                                            [out:json];
                                            node["building"="cathedral"];
                                            out body;
                                            """,
                                            OPENWEATHERMAP_API_KEY,
                                            0.1)
        for weather in weathers:
            test_dump_weather(weather)
        
    except Exception as exp: 
        logging.error('exception[{0}]'.format(exp))

    return

こんな風に POI と関連する天気を得られた。

2020-03-09 23:56:06,709 DEBUG test.py:27 - test_dump_weather() : osm_id[100090862] name[Dom St. Blasien] lat[47.7600646] lon[8.1300061] temp[280.04] pressure[1017] humidity[71]
2020-03-09 23:56:06,709 DEBUG test.py:27 - test_dump_weather() : osm_id[474375860] name[Собор Успения Пресвятой Богородицы] lat[50.9799235] lon[39.3167911] temp[286.99] pressure[1019] humidity[66]
2020-03-09 23:56:06,709 DEBUG test.py:27 - test_dump_weather() : osm_id[592838468] name[N/A] lat[4.8092301] lon[-74.3537103] temp[289.15] pressure[1030] humidity[67]
...

さらに、Overpass API はレスポンスに時間がかかる、また負荷によりエラーが発生しやすいため、事前に Overpass API のレスポンスを JSON ファイルにしたものでも実行できるようにした。

def test_overpass_file():
    weathers = overpass_weahter.weathers_with_overpass_file('overpass_building_cathedral.json', OPENWEATHERMAP_API_KEY, 0.1)

テスト目的ならば、こちらがやりやすい。 また、この方法だとたまに Overpass API でローカルの JSON 更新して対応していくことで、安定して更新された POI から天気取得できそうだ。