天気予報もつぶやかせてみた話。
何の話かと言いますと、ツイッターの話です。みなさんお待ちかねの「APIで色々やってみよう」シリーズです。え?誰も望んでいないですか、そうですか・・。
今回の記事は、読んでいる方がほとんど共感できないであろうニッチで意味不明な内容になると思います、申し訳ない。もしご興味のある方がいらっしゃれば、どうぞ。
というわけで最近ご無沙汰でしたが、趣味というか仕事の延長線上のような技術的な話。
以前、記事で書いたのですが、実は私が note で記事を更新(新規作成)すると、Twitter のほうにも「こんな記事書いたよ!」というツイートを自動で投稿するようにしました。具体的には、Python という言語でスクリプトを作りました。
その時の記事はこちら。
依然として業務で使っているというわけではないので、Python スキルは甚だ低いわけですが、ちょっと今回思い立って、機能追加してみました。後でコードも載せますが、レベルの低い実装なので笑わないでください。いや笑ってもいいですが、できればベストプラクティスを教えて・・。
本題
さて、本題。
どんな機能を追加するかと言いますと、今回は、天気予報。
現状、note に紐づけている私の Twitter アカウントは自動投稿だけさせているのですが、その内容は、
というものだけ。何とも寂しいわけです。
2.のほうについては、上に紹介した記事に詳しく書きましたが、Wikipedia の API を使って情報を取得しています。そして、そもそもツイートするのは出来事にするのか誕生日にするのか、そしてどの出来事にするか誰の誕生日にするか、というのはランダムで選ぶようにしてます。
ただ、これらは、つぶやく情報の有難みとしてはあんまり高くないわけで。そうするともう少し役に立ちそうな情報もつぶやいてみようと思い、じゃあ天気予報だろうということに勝手に落ち着きました。
やりたいこと
ツイートに追加するのは、こんな感じをイメージしてます。
天気というか気象の知識に関して私は皆無なので、あまりオツムの程度がバレないように、ざっくりした天気と気温くらいにとどめておこうと思っております。
で、そのデータをプログラムで取得するなら、たとえばスクレイピングさせたりとか色んな方法があると思いますが、ここは、当初の作りから方針を変えず、Python&API の鉄則でやっていこうかなと。
キミにきめた(API)
というわけで、巷には天気予報APIってどんなものがあるのかな、と探してみました。色んなサイトを見てみたけれども、商用だとか、条件指定を経度・緯度でしなければならないとかもあって「うーん」となりました。
結局、一番有名で、サービスとしても安定してそうな「Open Weather Map」に決定。リクエストパラメータも割と多様でしたので。
こちら、有償版と無償版のプランがある模様。どうやらそこまでたくさんリクエスト送らなければ無料のでもいけるようなので、一旦これで使ってみることにしました。公式サイトによれば、1分あたり60回までとか、ひと月あたり1,000,000回までとからしいので。まぁそこまではいかないでしょう。たぶん。
さて、このAPIを使用するには、キーを発行してもらう必要があります。
手順としては、まず、この OpenWeather のサイト上で、アカウント登録が必要。サイト内は全文英語なので一瞬ギョッとするけれども、普通にメールアドレスとパスワード入れてチェックボックスにチェック入れたり入れなかったりすれば、登録は問題なく完了。すぐにAPIキーも発行されますが、数分とか十数分くらい経たないとキーが Activate されなくて「あれっ、キー間違ったかな」と少し焦って何度もリクエスト送ってしまったのはここだけの話。気長に待ちましょう。
そうしたら、Python スクリプトのほうに、天気予報APIで情報取得する処理を実装。
今日の天気情報を取得する関数
いきなりコードをデデーンと載せますが、こんな感じにしました。
def get_today_weather(w_token):
# """"""""""""""""""""""""""""""""""""""
# """ 今日の天気情報を取得 """
# """"""""""""""""""""""""""""""""""""""
msg = None
try:
# 都市一覧のファイル(json.gz)をDLして辞書化
url = "http://bulk.openweathermap.org/sample/city.list.json.gz"
response = req.get(url)
if response.status_code == 200:
gzip_file = io.BytesIO(response.content)
with gzip.open(gzip_file, mode='rt', encoding='utf-8') as f:
json_data = f.read()
dic_city = json.loads(json_data)
# 対象の都市を日本に限定してリスト化してランダムに抽出
l_id_city = [d.get('id') for d in dic_city if d.get('country') == 'JP']
x = random.choice(l_id_city)
# OpenWeatherMap API で該当都市の現在の天気情報を取得
response = req.get(
"https://api.openweathermap.org/data/2.5/weather",
params={
"id":x,
"appid": w_token,
"units": "metric",
"lang": "ja",
},
)
# 戻り値を分解
ret_current = response.json()
tp = ret_current["main"]['temp']
city = ret_current["name"]
weather = ret_current["weather"][0]['description']
lat = ret_current["coord"]['lat'] # 緯度
lon = ret_current["coord"]['lon'] # 経度
# OpenWeatherMap API で該当都市の天気予報を取得
response = req.get(
"https://api.openweathermap.org/data/2.5/onecall",
params={
"appid": w_token,
"lon":lon,
"lat":lat,
"units": "metric",
"lang": "ja",
},
)
# 戻り値を分解(翌日以降の情報取得)
ret_forecast = response.json()
x = random.randint(1,7)
next_day = datetime.fromtimestamp(ret_forecast["daily"][x]['dt'])
next_weather = ret_forecast["daily"][x]["weather"][0]['description']
next_tp = ret_forecast["daily"][x]["temp"]["day"]
# 気温によって体感を分岐
def get_feel_msg(temp):
feel = None
if temp >= 28:
feel = "暑い"
elif temp >= 20 and temp < 28:
feel = "わりと暑い"
elif temp >= 15 and temp < 20:
feel = "涼しいほう"
elif temp >= 10 and temp < 15:
feel = "肌寒い"
elif temp < 10:
feel = "寒い"
return(feel)
# 適当なメッセージ生成
if city != None:
msg = "現在の " + city + " の天気:"+ weather +"/気温:" + str(tp) + "℃の模様。"
tp_msg = get_feel_msg(tp)
if tp_msg != None:
msg += "感覚的に" + tp_msg + "かもしれないです。"
msg += "\n\n" + str(next_day.month) + "/" + str(next_day.day) + " " + str(next_day.hour) + "時の時点では、"
msg += "天気:" + next_weather + "/気温:" + str(next_tp) + "℃みたい。"
tp_msg = get_feel_msg(next_tp)
if tp_msg != None:
msg += tp_msg + "かもですね。"
msg += "\n\n" + city + " はこの辺り。\n"
msg += 'https://maps.google.com/maps?q=' + str(lat) + "," + str(lon)
except Exception as e:
msg_err = f"Error Occurred: {e}"
print(msg_err)
msg = None
return (msg)
※これらのソースコードにより生じた如何なる損害についても、一切の責任は負いかねますので、あらかじめご了承ください。
解説
では以下解説します。
引数
都市一覧をWebから取得
都市一覧ファイルの読み込み
国内の都市だけリスト化
API実行(1回目、現在の天気)
API実行(2回目、未来の天気)
おまけ
最後に
※ちなみに、実際のコードでは、ちょこちょことエラーハンドリングとかログ出力してますが、読みにくくなるのでそこは今回記載を割愛しました。
結論
使いやすい。リファレンスも分かりやすくてあんまり悩むところがなかった。PyOWM というラッパーライブラリもあるみたいなので、手早く使いたい人はこっちを触ってみてもいいかも。私は勉強のために、敢えて生APIをいじいじしてみました。というのは建前で、最近仕事でコード書く機会が無かったので、久々に実装ができて純粋に楽しかった。
というわけで、誰の何の役にも立たない記事でした。まぁいつもの記事も役に立たないですけど。
自己満足で失礼。
Twitterアカウント
参考サイト
この記事が気に入ったらサポートをしてみませんか?