『退屈なことはPythonにやらせよう』でPythonの学習をしています。
今回は第14章jsonモジュールのプロジェクト【現在の天気予報データを取得する】でプログラムを作成し実行してみました。
401 Client error
エラー発生
エラーが出る箇所がありまして、それは文字列でOpenWeatherMapのurlを指定するところ。書籍では
http://api.openweathermap.org/data/2.5/forecast/daily
となっていますが、このまま実行すると
401 Client Error
というエラーが出てしまいます。
エラーの原因は?
まずキーの打ち間違いを疑いましたが、何度見比べても間違いはなさそう。
誤植かな?と思い書籍の正誤表を確認。誤植ではないらしい。
OpenWeatherMapのサイトを確認。Freeプランで使用できるCurrent Weather 、3-hour Forecast 5 daysで「How to make an API call」を確認。
どの例を見ても「daily」というディレクトリにアクセスしていないみたい。
手持ちの書籍は2020年9月発行の第7刷。すでに情報が古いのかも?あるいは、わたしが自分では気づかないところでミスをしているか、ですね。
コードの修正
サイトの例を参考にしてurlの指定を
https://api.openweathermap.org/data/2.5/weather
に変更し、?以下のパラメーターにはq、appid、lang、unitsを指定。
url = "https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&lang=ja&units=metric".format(location, APPID)
・lang=jaで日本語化(“name”、”description”、が日本語に)。
・units=metricで気温を℃化。
パラメーターについては3-hour Forecast 5 daysのGeocodingAPIに説明があります。
一旦、IDLE Shellで実行してみます。
すると、今回はrequestsモジュールのResponseオブジェクトがエラーを返さない。text属性をjsonに渡してprint関数で表示してみると、天候のデータが表示されました!
プログラム作成Ⅰ(現在の天気・気温・温度を表示)
コーディング
天候データが取得できたので、プログラムにまとめます。
基本的には書籍と同じようにコーディングをして、最後のデータを出力するところを変更し、明日・明後日の天候ではなく、現在の天気・気温・湿度を表示してみます。
書籍とは返ってくるデータの構成が違うようなので調整。
(上記のprint関数で出力された内容を見て構成を判断しています)
・キー”list”が存在しない
・天候は”weather”のリストが格納する辞書内の”main”、”descritpion”に
・気温・湿度は”main”が指す辞書内の”temp”と”humidity”がそれぞれ
データをjson.loads関数で変換し、weather_dataという変数に代入すると
# 天候とその説明
print(weather_data["weather"][0]["main"] + '-' + weather_data["weather"][0]["description"])
# 気温
print("気温:{}度".format(weather_data["main"]["temp"]))
# 湿度
print("湿度:{}%".format(weather_data["main"]["humidity"]))
windowsのcmdからこのプログラムを実行すると、無事、現在の天候・気温・湿度を表示することができました!
C:\mydir>py quickWeather.py Tokyo JP
Tokyo,JP現在の天気:
Clouds-薄い雲
気温:30.96度
湿度:62%
問題点
しかし、このプログラムでは書籍のように明日・明後日の天気を調べることができません。
プログラム作成Ⅱ(今日・明日・明後日の天気を表示)
コーディング
書籍のようなプログラムにしたいので、3-hour Forecast 5 daysの例を参考にurlの指定を変更します。
https://api.openweathermap.org/data/2.5/forecast
url = "https://api.openweathermap.org/data/2.5/forecast?q={}&appid={}&lang=ja&units=metric&cnt=24".format(location, APPID)
書籍ではパラメーターcntは3で設定されています。これはおそらく3日分ということだと思うのですが、こちらのurlでは3時間ごとのデータが返ってくるのでcntは24に指定(3日分)。
json.loads関数で変換し、それをweather_dataという変数に代入すれば
weather_data["list"][0]["weather"][0]["description"]
で当日の天候の説明が、
weather_data["list"][8]["weather"][0]["description"]
で明日の天候の説明が返ってきます。該当箇所の数値を変更すれば、好きな、日付・時間帯のデータを選択できます…。
やろうとしていることは書籍と同じです。ただキー”list”が指す値であるリストのインデックスは調整しないと、ですね。
print("{}の天気:".format(location))
print()
# 今日の天気
print(weather_data["list"][0]["dt_txt"])
print(weather_data["list"][0]["weather"][0]["main"],'-',weather_data["list"][0]["weather"][0]["description"])
print()
# 明日の天気
print(weather_data["list"][8]["dt_txt"])
print(weather_data["list"][8]["weather"][0]["main"],'-',weather_data["list"][8]["weather"][0]["description"])
print()
# 明後日の天気
print(weather_data["list"][16]["dt_txt"])
print(weather_data["list"][16]["weather"][0]["main"],'-',weather_data["list"][16]["weather"][0]["description"])
プログラムにまとめて実行すると
C:\mydir>py quickWeather2.py Tokyo JP
Tokyo,JPの天気:
2022-09-06 00:00:00
Clouds - 雲
2022-09-07 00:00:00
Clear - 晴天
2022-09-08 00:00:00
Clouds - 厚い雲
うまくできました。2022年9月6日午前8時頃です。
補足
初めてこのプログラムを実行した際は、[“list”][0]には当日午前3時の、[“list”][8]にはその翌日午前3時の気象データが入っていました。
ですが、2回目に実行した際(上記の実行時)では、[“list”][0]には当日午前0時の、[“list”][8]にはその翌日午前0時のデータでした。
せっかくなので”dt_txt”で日付と時刻を表示してみよう、と思ってコードを修正し、日を空けて再実行したらそのような結果になりました。
データを問い合わせる時刻によって、格納される最初の時間帯が変更されるのかもしれない。すみませんが、ちょっとわかりません。
最後に
わたしなりに今できる解決方法です。PythonやOpenWeatherMapAPIの扱いに詳しければ、もっと良い解決方法が見つかるのかもしれません。
以上です。読んでくださった方、ありがとうございました。
著者名 | 書籍名 | 出版 | 発行年月日 | 参照頁 |
---|---|---|---|---|
著: Al Sweigart 訳: 相川愛三 | 『退屈なことはPythonにやらせよう』 | オライリー・ジャパン | 初版 2017/6/1 第7刷 2020/9/4 | 377~ |
サイト名 | ページタイトル | URL | 参考にした日付 |
---|---|---|---|
OpenWeatherMap | https://openweathermap.org/ | 2022/9/6 | |
Current weather data | https://openweathermap.org/current | 同上 | |
5 day weather forecast | https://openweathermap.org/forecast5 | 同上 | |
GitHub:『退屈なことはPythonにやらせよう』のリポジトリ | 『退屈なことはPythonにやらせよう』の正誤表 | https://github.com/oreilly-japan/automatestuff-ja/wiki/errata | 同上 |