【WebAPI】OpenWeatherMapで3時間ごとの天気を取りたい【json】

# はじめに

リビングに3.5インチLCDモニタを付けたラズパイ3B+を置いてアレコレしたいなぁと考えてるのですが、普段は何か情報を表示させておきたい。そうだ時計と地元の3時間ごとの天気予報を表示させよう！と思い立ったので調査しました。（[アプリの完成品はこんな感じです](https://github.com/marksard/ClockWithWeatherForecast)）  



# サービスの調査

最初はRSSとかで提供されてたりしないかなーと思って探ってみたのですが、yahooやlivedoorではrssでもwebAPIでも3時間ごとの天気を取得する術がないっぽい。で、海外のドメジャーなOpenWeatherMapを利用することにしました。  

# 登録してAPIキーもらう

https://openweathermap.org/

メルアドとパス入れると登録完了するはず。  
APIキーを貰えまずが登録直後はエラーになります。10分から1時間くらいとあるので気長に待ちましょう。  

# プログラム

みんな大好きPythonです。

```python

#! /usr/bin/python3
# -*- coding: utf-8 -*-
import json
import datetime
import os
import requests
import sys

from pytz import timezone

API_KEY = '*************************'
ZIP = '***-****,JP'
API_URL = 'http://api.openweathermap.org/data/2.5/forecast?zip={0}&units=metric&lang=ja&APPID={1}'


def getWeatherForecast():
    url = API_URL.format(ZIP, API_KEY)
    response = requests.get(url)
    forecastData = json.loads(response.text)

    if not ('list' in forecastData):
        print('error')
        return

    # print(forecastData)

    for item in forecastData['list']:
        forecastDatetime = timezone(
            'Asia/Tokyo').localize(datetime.datetime.fromtimestamp(item['dt']))
        weatherDescription = item['weather'][0]['description']
        temperature = item['main']['temp']
        rainfall = 0
        if 'rain' in item and '3h' in item['rain']:
            rainfall = item['rain']['3h']
        print('日時:{0} 天気:{1} 気温(℃):{2} 雨量(mm):{3}'.format(
            forecastDatetime, weatherDescription, temperature, rainfall))


getWeatherForecast()

```

# 解説

```python

API_KEY = '*************************'
ZIP = '***-****,JP'
API_URL = 'http://api.openweathermap.org/data/2.5/forecast?zip={0}&units=metric&lang=ja&APPID={1}'


def getWeatherForecast():
    url = API_URL.format(ZIP, API_KEY)
    response = requests.get(url)
    forecastData = json.loads(response.text)

```

API_URLを分解すると、  

* forecast: 3時間ごとのデータを取得するときに指定する
* zip: 郵便番号で地域を指定する
    * ZIPの```***-****```とあるところを好きな郵便番号を入れてください。
* units: 気温の単位を指定する
    * metric（摂氏℃になる）を指定しています。
* lang: 表記言語を指定する
    * ja（日本）を指定しています。weather.descriptionの部分が日本語になります。
* APPID: Api keyを指定する
    * API_KEYの```********```の代わりに取得したキーを入れてください。

で、httpのリクエストを投げて返ってきたjson形式の応答データをpythonオブジェクトにしてます。  
＃一言で書いてるけどすごく扱いやすくてびっくりした

```python
# print(forecastData)

for item in forecastData['list']:
    forecastDatetime = timezone(
        'Asia/Tokyo').localize(datetime.datetime.fromtimestamp(item['dt']))
    weatherDescription = item['weather'][0]['description']
    temperature = item['main']['temp']
    rainfall = 0
    if 'rain' in item and '3h' in item['rain']:
        rainfall = item['rain']['3h']
    print('日時:{0} 天気:{1} 気温(℃):{2} 雨量(mm):{3}'.format(
        forecastDatetime, weatherDescription, temperature, rainfall))
```

forecastDataをそのままコンソールに出力させるといろいろなデータが乗っかってます。  
[APIリファレンス](https://openweathermap.org/forecast5)を読んで欲しいデータを調べて、ここでは日時、天気、気温、雨量を並べて出力しています。  

時刻ですが、dtフィールドにはUTCが入ってるのでJSTに変換しています（pythonの時刻の扱いよくわからんので帳尻あわせ的コードなの申し訳ない…)  
雨量は降る予報でないとフィールドすらないので'rain'と'3h'がある場合のみ取り出しています。

# 結果
大阪城（540-0002）近辺の今日以降の天気予報です。

```
日時:2018-05-21 15:00:00+09:00 天気:雲 気温(℃):24.69 雨量(mm):0
日時:2018-05-21 18:00:00+09:00 天気:薄い雲 気温(℃):21.35 雨量(mm):0
日時:2018-05-21 21:00:00+09:00 天気:晴天 気温(℃):14.93 雨量(mm):0
日時:2018-05-22 00:00:00+09:00 天気:晴天 気温(℃):11.44 雨量(mm):0
日時:2018-05-22 03:00:00+09:00 天気:晴天 気温(℃):9.36 雨量(mm):0
日時:2018-05-22 06:00:00+09:00 天気:晴天 気温(℃):10.66 雨量(mm):0
日時:2018-05-22 09:00:00+09:00 天気:晴天 気温(℃):20.24 雨量(mm):0
日時:2018-05-22 12:00:00+09:00 天気:晴天 気温(℃):22.92 雨量(mm):0
日時:2018-05-22 15:00:00+09:00 天気:厚い雲 気温(℃):22.87 雨量(mm):0
日時:2018-05-22 18:00:00+09:00 天気:曇りがち 気温(℃):19.59 雨量(mm):0
日時:2018-05-22 21:00:00+09:00 天気:雲 気温(℃):15.97 雨量(mm):0
日時:2018-05-23 00:00:00+09:00 天気:雲 気温(℃):15 雨量(mm):0
日時:2018-05-23 03:00:00+09:00 天気:曇りがち 気温(℃):15.43 雨量(mm):0
日時:2018-05-23 06:00:00+09:00 天気:厚い雲 気温(℃):16.81 雨量(mm):0
日時:2018-05-23 09:00:00+09:00 天気:小雨 気温(℃):18.94 雨量(mm):0.41
日時:2018-05-23 12:00:00+09:00 天気:適度な雨 気温(℃):18.44 雨量(mm):3.13
日時:2018-05-23 15:00:00+09:00 天気:適度な雨 気温(℃):17.75 雨量(mm):10.72
日時:2018-05-23 18:00:00+09:00 天気:強い雨 気温(℃):17.8 雨量(mm):13.01
日時:2018-05-23 21:00:00+09:00 天気:強い雨 気温(℃):18.46 雨量(mm):19.7
日時:2018-05-24 00:00:00+09:00 天気:強い雨 気温(℃):19.61 雨量(mm):28.42
日時:2018-05-24 03:00:00+09:00 天気:適度な雨 気温(℃):19.38 雨量(mm):9.94
日時:2018-05-24 06:00:00+09:00 天気:小雨 気温(℃):17.33 雨量(mm):0.060000000000002
日時:2018-05-24 09:00:00+09:00 天気:小雨 気温(℃):18.78 雨量(mm):0.090000000000003
日時:2018-05-24 12:00:00+09:00 天気:雲 気温(℃):21.61 雨量(mm):0
日時:2018-05-24 15:00:00+09:00 天気:薄い雲 気温(℃):22.15 雨量(mm):0
日時:2018-05-24 18:00:00+09:00 天気:薄い雲 気温(℃):20.76 雨量(mm):0
日時:2018-05-24 21:00:00+09:00 天気:晴天 気温(℃):14.73 雨量(mm):0
日時:2018-05-25 00:00:00+09:00 天気:晴天 気温(℃):10.53 雨量(mm):0
日時:2018-05-25 03:00:00+09:00 天気:晴天 気温(℃):8.48 雨量(mm):0
日時:2018-05-25 06:00:00+09:00 天気:晴天 気温(℃):9.4 雨量(mm):0
日時:2018-05-25 09:00:00+09:00 天気:晴天 気温(℃):18.3 雨量(mm):0
日時:2018-05-25 12:00:00+09:00 天気:晴天 気温(℃):21.28 雨量(mm):0
日時:2018-05-25 15:00:00+09:00 天気:晴天 気温(℃):21.75 雨量(mm):0
日時:2018-05-25 18:00:00+09:00 天気:晴天 気温(℃):19.81 雨量(mm):0
日時:2018-05-25 21:00:00+09:00 天気:晴天 気温(℃):14.14 雨量(mm):0
日時:2018-05-26 00:00:00+09:00 天気:晴天 気温(℃):12.11 雨量(mm):0
日時:2018-05-26 03:00:00+09:00 天気:薄い雲 気温(℃):11.29 雨量(mm):0
日時:2018-05-26 06:00:00+09:00 天気:晴天 気温(℃):12.9 雨量(mm):0
```

3時間ごとの天気を5日ぶん取れます。  
天気についてはWeather descriptionに日本語で入ってますが日本人的には違和感ありますね。[weather conditions](https://openweathermap.org/weather-conditions)を見ると細かい区分が書いてますが、向こうはどうも「晴れ！」「それ以外は曇り系の何か！」て感じの区分で、日本人的になじみのある「はれ時々曇り」とか「はれのち曇り」「雨のち曇り」みたいなどっちやねん！ていうのが無いみたいです。薄曇り→はれ時々曇り、曇りがち→曇り時々はれみたいな感じでこの辺は意訳する必要があるのかなと思います。アイコン表示するならidのが処理しやすそうです。