よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

Pythonでライブドア天気APIから今日と明日の天気予報を取得する


はじめに


戦時中の大日本帝国は防空、国防上のインテリジェンスの観点から国内で嘘の天気予報を流したり、または天気予報の報道自体を禁止したりしておりました。
古代、稲作や漁の豊作祈願、航海の安全を亀の甲らや皿を割ることによって占うより遥か以前から、天気をみることは人間の生活に予報以上の重要な意味があったかと思います。現代の私個人的には単に天災による防災や、外出に傘を持つかどうかの判断材料ぐらいにしか気にしませんけど。

そういう訳でございまして、本日はライブドア、もとい、生扉の天気予報API…えいぴいあいを使っての天気情報取得にチャレ、いや挑戦致したいと存じます。



目次




動作環境


Androidスマホ
termux
Python3.7
JupyterNotebook



2020/8/4追記 ライブドア天気終了のお知らせ


天気情報 ヘルプ - livedoor ヘルプ
2020/7/31をもってライブドア天気の終了となったようです。それに伴い、この投稿で使うライブドア天気APIも使えなくなりました。
一応参考の為に投稿は残しておきます。



ライブドアの天気API


無料で使える天気APIは幾つかありますが、登録不要で気軽に使えるライブドアのものを試します。


以下のurlをブラウザで開くと下の画像のように表示されます。

http://weather.livedoor.com/forecast/rss/primary_area.xml


f:id:chayarokurokuro:20191003101907j:plain


city title="地名" id="番号"がズラリと書いてあります。
このid番号をパラメーターとして、天気APIのurl

http://weather.livedoor.com/forecast/webservice/json/v1


に接続すると、パラメーターで与えた土地の天気情報がjson形式のデータで得られます。



ライブラリにrequestsを使いますのでまだの場合はpip install requestsでインストールしておきます。



沖縄の天気予報を取得するコード


昨日だか、50年ぶりの大雨だとかニュースで流れていましたので、沖縄の那覇の天気を取得してみます。
那覇id="471010"のようです。

import requests

# ライブドア天気APIのurl
url = "http://weather.livedoor.com/forecast/webservice/json/v1"

# 沖縄那覇のidパラメータ(辞書型で)
id = {"city":"471010"}

# 取得される天気データ
data = requests.get(url,params=id).json()

# 取得したデータの表示
print(data)
print(type(data))
{'pinpointLocations': [{'link': 'http://weather.livedoor.com/area/forecast/4720100', 'name': '那覇市'}, {'link': 'http://weather.livedoor.com/area/forecast/4720500', 'name': '宜野湾市'}, {'link': 'http://weather.livedoor.com/area/forecast/4720800', 'name': '浦添市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721000', 'name': '糸満市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721100', 'name': '沖縄市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721200', 'name': '豊見城市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721300', 'name': 'うるま市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721500', 'name': '南城市'}, {'link': 'http://weather.livedoor.com/area/forecast/4732400', 'name': '読谷村'}, {'link': 'http://weather.livedoor.com/area/forecast/4732500', 'name': '嘉手納町'}, {'link': 'http://weather.livedoor.com/area/forecast/4732600', 'name': '北谷町'}, {'link': 'http://weather.livedoor.com/area/forecast/4732700', 'name': '北中城村'}, {'link': 'http://weather.livedoor.com/area/forecast/4732800', 'name': '中城村'}, {'link': 'http://weather.livedoor.com/area/forecast/4732900', 'name': '西原町'}, {'link': 'http://weather.livedoor.com/area/forecast/4734800', 'name': '与那原町'}, {'link': 'http://weather.livedoor.com/area/forecast/4735000', 'name': '南風原町'}, {'link': 'http://weather.livedoor.com/area/forecast/4735300', 'name': '渡嘉敷村'}, {'link': 'http://weather.livedoor.com/area/forecast/4735400', 'name': '座間味村'}, {'link': 'http://weather.livedoor.com/area/forecast/4735500', 'name': '粟国村'}, {'link': 'http://weather.livedoor.com/area/forecast/4735600', 'name': '渡名喜村'}, {'link': 'http://weather.livedoor.com/area/forecast/4736200', 'name': '八重瀬町'}], 'link': 'http://weather.livedoor.com/area/forecast/471010', 'forecasts': [{'dateLabel': '今日', 'telop': '晴時々曇', 'date': '2019-10-03', 'temperature': {'min': None, 'max': {'celsius': '31', 'fahrenheit': '87.8'}}, 'image': {'width': 50, 'url': 'http://weather.livedoor.com/img/icon/2.gif', 'title': '晴時々曇', 'height': 31}}, {'dateLabel': '明日', 'telop': '晴時々曇', 'date': '2019-10-04', 'temperature': {'min': {'celsius': '25', 'fahrenheit': '77.0'}, 'max': {'celsius': '30', 'fahrenheit': '86.0'}}, 'image': {'width': 50, 'url': 'http://weather.livedoor.com/img/icon/2.gif', 'title': '晴時々曇', 'height': 31}}], 'location': {'city': '那覇', 'area': '沖縄', 'prefecture': '沖縄県'}, 'publicTime': '2019-10-03T05:00:00+0900', 'copyright': {'provider': [{'link': 'http://tenki.jp/', 'name': '日本気象協会'}], 'link': 'http://weather.livedoor.com/', 'title': '(C) LINE Corporation', 'image': {'width': 118, 'link': 'http://weather.livedoor.com/', 'url': 'http://weather.livedoor.com/img/cmn/livedoor.gif', 'title': 'livedoor 天気情報', 'height': 26}}, 'title': '沖縄県 那覇 の天気', 'description': {'text': ' 沖縄地方は高気圧に覆われておおむね晴れていますが、にわか雨の所もあります。\n\n 3日から4日の沖縄地方は、高気圧に覆われておおむね晴れますが、所によりにわか雨があるでしょう。沖縄本島地方では3日は所により雷を伴う見込みです。\n\n 沖縄本島地方では、3日夕方まで発達した積乱雲の下での落雷や突風、急な強い雨に注意してください。\n\n 沖縄地方の沿岸の海域では、うねりを伴い波がやや高いでしょう。\n\n 沖縄地方では、3日は高温が予想されるため、熱中症など健康管理に注意してください。', 'publicTime': '2019-10-03T07:43:00+0900'}}
<class 'dict'>

お、いろいろ出て来ましたよ。



キーを取り出す


スマホでやってるもんで、激しく見にくい(笑)とりあえずキーだけ取り出す。

key_list = data.keys()
print(key_list)
dict_keys(['pinpointLocations', 'link', 'forecasts', 'location', 'publicTime', 'copyright', 'title', 'description'])

キーが8個ありますね。



キーとバリューを取り出す


今度はキーとバリューのセットで。

item_list = data.items()

for k, v in item_list:
    print(k,v)
    print("###########################")
pinpointLocations [{'link': 'http://weather.livedoor.com/area/forecast/4720100', 'name': '那覇市'}, {'link': 'http://weather.livedoor.com/area/forecast/4720500', 'name': '宜野湾市'}, {'link': 'http://weather.livedoor.com/area/forecast/4720800', 'name': '浦添市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721000', 'name': '糸満市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721100', 'name': '沖縄市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721200', 'name': '豊見城市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721300', 'name': 'うるま市'}, {'link': 'http://weather.livedoor.com/area/forecast/4721500', 'name': '南城市'}, {'link': 'http://weather.livedoor.com/area/forecast/4732400', 'name': '読谷村'}, {'link': 'http://weather.livedoor.com/area/forecast/4732500', 'name': '嘉手納町'}, {'link': 'http://weather.livedoor.com/area/forecast/4732600', 'name': '北谷町'}, {'link': 'http://weather.livedoor.com/area/forecast/4732700', 'name': '北中城村'}, {'link': 'http://weather.livedoor.com/area/forecast/4732800', 'name': '中城村'}, {'link': 'http://weather.livedoor.com/area/forecast/4732900', 'name': '西原町'}, {'link': 'http://weather.livedoor.com/area/forecast/4734800', 'name': '与那原町'}, {'link': 'http://weather.livedoor.com/area/forecast/4735000', 'name': '南風原町'}, {'link': 'http://weather.livedoor.com/area/forecast/4735300', 'name': '渡嘉敷村'}, {'link': 'http://weather.livedoor.com/area/forecast/4735400', 'name': '座間味村'}, {'link': 'http://weather.livedoor.com/area/forecast/4735500', 'name': '粟国村'}, {'link': 'http://weather.livedoor.com/area/forecast/4735600', 'name': '渡名喜村'}, {'link': 'http://weather.livedoor.com/area/forecast/4736200', 'name': '八重瀬町'}]
###########################
link http://weather.livedoor.com/area/forecast/471010
###########################
forecasts [{'dateLabel': '今日', 'telop': '晴時々曇', 'date': '2019-10-03', 'temperature': {'min': None, 'max': {'celsius': '31', 'fahrenheit': '87.8'}}, 'image': {'width': 50, 'url': 'http://weather.livedoor.com/img/icon/2.gif', 'title': '晴時々曇', 'height': 31}}, {'dateLabel': '明日', 'telop': '晴時々曇', 'date': '2019-10-04', 'temperature': {'min': {'celsius': '25', 'fahrenheit': '77.0'}, 'max': {'celsius': '30', 'fahrenheit': '86.0'}}, 'image': {'width': 50, 'url': 'http://weather.livedoor.com/img/icon/2.gif', 'title': '晴時々曇', 'height': 31}}]
###########################
location {'city': '那覇', 'area': '沖縄', 'prefecture': '沖縄県'}
###########################
publicTime 2019-10-03T05:00:00+0900
###########################
copyright {'provider': [{'link': 'http://tenki.jp/', 'name': '日本気象協会'}], 'link': 'http://weather.livedoor.com/', 'title': '(C) LINE Corporation', 'image': {'width': 118, 'link': 'http://weather.livedoor.com/', 'url': 'http://weather.livedoor.com/img/cmn/livedoor.gif', 'title': 'livedoor 天気情報', 'height': 26}}
###########################
title 沖縄県 那覇 の天気
###########################
description {'text': ' 沖縄地方は高気圧に覆われておおむね晴れていますが、にわか雨の所もあります。\n\n 3日から4日の沖縄地方は、高気圧に覆われておおむね晴れますが、所によりにわか雨があるでしょう。沖縄本島地方では3日は所により雷を伴う見込みです。\n\n 沖縄本島地方では、3日夕方まで発達した積乱雲の下での落雷や突風、急な強い雨に注意してください。\n\n 沖縄地方の沿岸の海域では、うねりを伴い波がやや高いでしょう。\n\n 沖縄地方では、3日は高温が予想されるため、熱中症など健康管理に注意してください。', 'publicTime': '2019-10-03T07:43:00+0900'}
###########################

一番初めのpinpointLocationsはピンポイントな地名とurlしか載ってませんね。

天気予報っぽい事が書かれてあるのはforecastsか一番最後のdescriptionかな。



簡単そうなdescriptionキーから先に行こう。文章で現在の天気と予報が書いてあるようです。そこだけ取り出してみましょうか。



descriptionキー


data["description"]
{'text': ' 沖縄地方は高気圧に覆われておおむね晴れていますが、にわか雨の所もあります。\n\n 3日から4日の沖縄地方は、高気圧に覆われておおむね晴れますが、所によりにわか雨があるでしょう。沖縄本島地方では3日は所により雷を伴う見込みです。\n\n 沖縄本島地方では、3日夕方まで発達した積乱雲の下での落雷や突風、急な強い雨に注意してください。\n\n 沖縄地方の沿岸の海域では、うねりを伴い波がやや高いでしょう。\n\n 沖縄地方では、3日は高温が予想されるため、熱中症など健康管理に注意してください。',
 'publicTime': '2019-10-03T07:43:00+0900'}

これもまた辞書型になっている。publicTimeは公式発表の日時かな。テキストだけ取り出してみましょ。

テキスト天気予報 description-text


textData = data["description"]["text"]
print(textData)
 沖縄地方は高気圧に覆われておおむね晴れていますが、にわか雨の所もあります。

 3日から4日の沖縄地方は、高気圧に覆われておおむね晴れますが、所によりにわか雨があるでしょう。沖縄本島地方では3日は所により雷を伴う見込みです。

 沖縄本島地方では、3日夕方まで発達した積乱雲の下での落雷や突風、急な強い雨に注意してください。

 沖縄地方の沿岸の海域では、うねりを伴い波がやや高いでしょう。

 沖縄地方では、3日は高温が予想されるため、熱中症など健康管理に注意してください。

これを天気予報の福井さん(昭和の人間にはわかる)か、石原良純か、天達の声に変換させます。
ウソです。
次に行きましょ。forecastsキーを取り出してみる。



forecastsキー


data["forecasts"]
[{'dateLabel': '今日',
  'telop': '晴時々曇',
  'date': '2019-10-03',
  'temperature': {'min': None, 'max': {'celsius': '31', 'fahrenheit': '87.8'}},
  'image': {'width': 50,
   'url': 'http://weather.livedoor.com/img/icon/2.gif',
   'title': '晴時々曇',
   'height': 31}},
 {'dateLabel': '明日',
  'telop': '晴時々曇',
  'date': '2019-10-04',
  'temperature': {'min': {'celsius': '25', 'fahrenheit': '77.0'},
   'max': {'celsius': '30', 'fahrenheit': '86.0'}},
  'image': {'width': 50,
   'url': 'http://weather.livedoor.com/img/icon/2.gif',
   'title': '晴時々曇',
   'height': 31}}]

リストの中に辞書が入っているようだ。リストの要素を取り出してみる。


今日と明日の天気 forecasts-リスト


f_list = data["forecasts"]

for i in f_list:
    print(i)
    print("##########################")
{'dateLabel': '今日', 'telop': '晴時々曇', 'date': '2019-10-03', 'temperature': {'min': None, 'max': {'celsius': '31', 'fahrenheit': '87.8'}}, 'image': {'width': 50, 'url': 'http://weather.livedoor.com/img/icon/2.gif', 'title': '晴時々曇', 'height': 31}}
##########################
{'dateLabel': '明日', 'telop': '晴時々曇', 'date': '2019-10-04', 'temperature': {'min': {'celsius': '25', 'fahrenheit': '77.0'}, 'max': {'celsius': '30', 'fahrenheit': '86.0'}}, 'image': {'width': 50, 'url': 'http://weather.livedoor.com/img/icon/2.gif', 'title': '晴時々曇', 'height': 31}}
##########################

今日と明日の天気っぽい情報が辞書型になっているのかな。
リストの先頭要素だけ見る。


今日の天気 forecasts-リスト[0]-items()


キーとバリューを取り出してみる。

f_list = data["forecasts"]

for f_k, f_v in f_list[0].items():
    print(f_k)
    print(f_v)
    print("##########################")
dateLabel
今日
##########################
telop
晴時々曇
##########################
date
2019-10-03
##########################
temperature
{'min': None, 'max': {'celsius': '31', 'fahrenheit': '87.8'}}
##########################
image
{'width': 50, 'url': 'http://weather.livedoor.com/img/icon/2.gif', 'title': '晴時々曇', 'height': 31}
##########################

最後のimageは画像の表示用だろうから無視する。
temperatureで更に最低と最高気温の辞書型。
ここまで深くなるとだいぶん分かり難い。しかし雨にも負けず風にも負けず、一気に最低と最高を別けて取り出す。


今日の気温 forecasts-リスト[0]-items-temperature


try:
    min_temp = data["forecasts"][0]["temperature"]["min"]["celsius"]
except:
    min_temp = "None"
    
try:    
    max_temp = data["forecasts"][0]["temperature"]["max"]["celsius"]
except:
    max_temp = "None"
    
print(min_temp)
print(max_temp)
None
31



地区 location


地名を取得する

data["location"]["city"]
'那覇'



まとめる


コードをまとめます。

import requests
import sys

city_id = "番号" # 那覇は471010


##### 天気データの取得関数 #####

def getData(city_id:str)->dict:
    
    # ライブドア天気APIのurl
    url = "http://weather.livedoor.com/forecast/webservice/json/v1"

    # 沖縄那覇のidパラメータ(辞書型で)
    id = {"city":city_id}

    # 取得される天気データ
    try:
        data = requests.get(url,params=id).json()
        # 取得したデータの表示
        return data 
    except:
        print("取得できませんでした。")
        # 終了する
        sys.exit()


##### 日付別天気予報取得関数 #####

def weatherForecasts(data:dict):  
    
    # 地名
    location = data["location"]["city"]
    print("《 {}の天気 》\n".format(location))
    
    # 予報リスト
    f_list = data["forecasts"]    
    for i in f_list:       
        # dateLavel (今日,明日)
        dateLabel = i["dateLabel"]
        
        # date (2019-10-3,2019-10-4)
        date = i["date"]
        
        # telop(晴時々曇、など)
        telop = i["telop"]
        
        # temperature(最低・最高気温)
        try:
            min_temp = i["temperature"]["min"]["celsius"]
        except:
            min_temp = "None"    
        try:    
            max_temp = i["temperature"]["max"]["celsius"]
        except:
            max_temp = "None"
        
        
        print("【{}の天気】\n 日付:{}\n 予報:{}\n 最低気温:{}\n 最高気温:{}\n ".format(dateLabel, date, telop, min_temp, max_temp))
        print("~~~~~~~~~~~~~~~~~~~~")
##### 天気予報文関数 #####

def weatherReport(date:dict):
    textData = data["description"]["text"]
    print(textData)
    
    
##### 実行 #####

id = "471010" #地方番号 変えればそこの天気予報が出ます。
data = getData(id)
weatherForecasts(data)
weatherReport(data)
《 那覇の天気 》

【今日の天気】
 日付:2019-10-03
 予報:晴時々曇
 最低気温:None
 最高気温:31

~~~~~~~~~~~~~~~~~~~~
【明日の天気】
 日付:2019-10-04
 予報:晴時々曇
 最低気温:25
 最高気温:30

~~~~~~~~~~~~~~~~~~~~
 沖縄地方は高気圧に覆われておおむね晴れていますが、にわか雨の所もあります。

 3日から4日の沖縄地方は、高気圧に覆われておおむね晴れますが、所によりにわか雨があるでしょう。沖縄本島地方では3日は所により雷を伴う見込みです。

 沖縄本島地方では、3日夕方まで発達した積乱雲の下での落雷や突風、急な強い雨に注意してください。

 沖縄地方の沿岸の海域では、うねりを伴い波がやや高いでしょう。

 沖縄地方では、3日は高温が予想されるため、熱中症など健康管理に注意してください。



最後にまとめたコードをファイルに保存し、ターミナルから実行して使います。
地区のid番号を書き換えればそこの天気予報が取得できます。
以上、気象情報をお伝えしました。