Python

Python で 天気予報APIからお天気情報を取得してみよう

Pythonista で簡単なお天気アプリを作ってみたのですが,その前に天気予報 API からお天気情報を取得する方法を纏めてみました.

ちょっと前までは,無料で使える定番のAPIが livedoor から提供されてたようですが,2020 年 7 月に提供が終了した様子.

互換性のある API をこちらで提供してくださっているようなので,こちらを有り難く使わせていただきます.

こちらではAPI提供者の方のお話もあります.

地域 ID の辞書を作ってみる

なんか,偉そうに記事は書いてますが,プログラム自体は大学院の研究で画像処理とか機械学習で適当にPythonを使っていた程度.

API なんかは活用したことないので,ずぶの素人であります.

さてお天気APIですが,以下が天気情報が入った JSON ファイルをリクエストする時のベースのURLです.

https://weather.tsukumijima.net/api/forecast

この後に,どこの天気を所得したいかの情報を付け加えます.例えば,東京 (ID = 130010) なら

https://weather.tsukumijima.net/api/forecast/city/130010

みたいに「ベースのURL + 都市のID」でお天気情報にアクセス出来ます.

さて,肝心のその ID はどこで調べるのかというと,こちらの xml ファイルで調べることが出来ます.

xml ファイルの一部

目視で手動でIDを調べても良いのですが,xml ファイルから {地名:ID} の辞書を作ってみました.(もっと良いやり方はあるのでしょうか)

使うライブラリは以下

import requests
import xml.etree.ElementTree as ET

requests は HTTP ライブラリ,xml.etree.ElementTree モジュールはXML データを解析したり作ったりするためのもの.

url 先の xml ファイルを取得してきます.

xml_url = 'https://weather.tsukumijima.net/primary_area.xml'
xml_file = requests.get(xml_url).text

url 先から,requests.get でレスポンスを受け,それを .text によってテキスト形式で受け取ります.

xml とは階層構造を持った形式で,木構造で表せますが,xml_file はテキスト形式で受けとったのでただの文字の羅列となっています.(printするとわかります)

root = ET.fromstring(xml_file)

ET.fromstring() で文字列状態の xml_file を階層構造を持った形式として扱えるようになります.

この xml では,city タグ内に目的の ID があります.

そこで city タグの付いた要素全てを取得するために,イテレータを使います.

root.iter('city')
#<_elementtree._element_iterator at 0x7ff48e607b30>

とすると,'city'タグのついた,要素を全て取得してくれます.これを for 文で回して属性をみてみると,

for att in(root.iter('city')):
    print(att.attrib)

#{'title': '稚内', 'id': '011000', 'source': 'http://weather.livedoor.com/forecast/rss/area/011000.xml'}
#{'title': '旭川', 'id': '012010', 'source': 'http://weather.livedoor.com/forecast/rss/area/012010.xml'}
#{'title': '留萌', 'id': '012020', 'source': 'http://weather.livedoor.com/forecast/rss/area/012020.xml'}
....

.attrib で属性を取得できます.「title」と「id」と「source」の3つがありますが,この内,地名と ID を対応させた辞書を作りたいです.

city_id_dict={}
for value in root.iter('city'):
    city_id_dict[value.attrib['title']] = value.attrib['id']

とすると,地名とIDの対応が取れた辞書が完成します.

print(city_id_dict['名古屋'])
#230010

例えば,’名古屋' と入れれば,名古屋の ID が帰ってきます.

辞書を作るところまでをまとめるとこんな感じ

import requests
import xml.etree.ElementTree as ET

xml_url = 'https://weather.tsukumijima.net/primary_area.xml'
xml_file = requests.get(xml_url).text
root = ET.fromstring(xml_file)

city_id_dict={}
for value in root.iter('city'):
    city_id_dict[value.attrib['title']] = value.attrib['id']

そんなに難しいことは多分してないです.

お天気情報を取得してみよう

では,先程のIDを使って,天気情報を取得してみましょう.

例えば,大阪の url は,先の辞書を使うとこんな感じで書けます.

import os
base_url ='https://weather.tsukumijima.net/api/forecast/'
os.path.join(base_url,'city',city_id_dict['大阪'])
#'https://weather.tsukumijima.net/api/forecast/city/270000'

'https://weather.tsukumijima.net/api/forecast/city/270000' で大阪の天気情報アクセスできます.

json_file = requests.get(os.path.join(base_url,'city',city_id_dict['大阪'])).json()

これで,大阪の天気情報の json ファイルを取得できました.本当に取得できているか,中身を見てみましょう.

import pprint
pprint.pprint(json_file, depth=2, compact=True)

#{'copyright': {'image': {...},
#               'link': 'https://weather.tsukumijima.net/',
#               'provider': [...],
#               'title': '(C) 天気予報 API(livedoor 天気互換)'},
# 'description': {'publicTime': '2021-02-06T11:38:00+09:00',
#                 'publicTime_format': '2021/02/06 11:38:00',
#                 'text': '大阪府では、7日まで空気の乾燥した状態が続くため、火の取り扱いに注意してください。\n'
....

と何かしら中身はありそうです.

json ファイルの詳細な構成はこちらに記載がありますので,ここではお天気アプリに使えそうな部分を見ていきます.

json_file['forecasts'][0]
'''
{'date': '2021-02-06',
 'dateLabel': '今日',
 'telop': '晴れ',
 'temperature': {'min': None, 'max': {'celsius': '14', 'fahrenheit': '57.2'}},
 'chanceOfRain': {'00-06': '--%',
  '06-12': '--%',
  '12-18': '0%',
  '18-24': '0%',
  'T00_06': '--%',
  'T06_12': '--%',
  'T12_18': '0%',
  'T18_24': '0%'},
 'image': {'title': '晴れ',
  'url': 'https://weather.tsukumijima.net/icon/1.gif',
  'width': 50,
  'height': 31}}
'''

json_file['forecasts'] で予報を取得できます.今日,明日,明後日の三日分のリストになってるので,今日なら[0] 明日なら [1] 明後日なら [2] で日にちを指定して取得できます.

本日の全日の天気予報ならば,

json_file['forecasts'][0]['telop']
#'晴れ'

という感じで取得できます.超簡単な天気アプリなら,これだけで出来ちゃいそうですね.

天気の概要はこんな感じで取得できます.

print(json_file['description']['text'])
'''
大阪府では、7日まで空気の乾燥した状態が続くため、火の取り扱いに注意してください。

大阪府は、高気圧に覆われて晴れています。

6日の大阪府は、高気圧に覆われて晴れる見込みです。

7日の大阪府は、気圧の谷や寒気の影響でおおむね曇るでしょう。

【近畿地方】
...
'''

気温や,6時間毎の降水確率なども取得できます.

まとめ

import requests
import xml.etree.ElementTree as ET
import os

city_name = '大阪'

xml_url = 'https://weather.tsukumijima.net/primary_area.xml'
base_url ='https://weather.tsukumijima.net/api/forecast/'

xml_file = requests.get(xml_url).text
root = ET.fromstring(xml_file)
city_id_dict={}
for value in root.iter('city'):
    city_id_dict[value.attrib['title']] = value.attrib['id']
    
json_file = requests.get(os.path.join(base_url,'city',city_id_dict[city_name])).json()
print(city_name + 'の今日の天気は, ' + json_file['forecasts'][0]['telop'] + 'です.')
print(json_file['description']['text'])


#おまけ
import matplotlib.pyplot as plt
img = requests.get(json_file['forecasts'][0]['image']['url'])
file_name = 'forecast.gif'
with open(file_name, "wb") as f_img:
    f_img.write(img.content)
plt.imshow(plt.imread(file_name))

今日のプログラムをまとめるとこんな感じ.

地名と ID の対応を辞書として作り,city_name の天気予報をするまでの一連の流れです.

おまけでは,その日の天気の画像を出力しています.

これらを使って次は Pythonista で簡単な天気アプリを作ってみます.

-Python