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 から天気取得できそうだ。