【Python3】天気予報が変わったら、LINEに通知が来るBotを作ろう

tenki.jpの天気予報を利用した、天気急変お知らせシステムを作ったので投稿します。

#1.目的
朝の天気予報ではこの時間は晴れのはずだったのに、雨が降ってきて洗濯物がびしょ濡れ…
1時間ごとの天気予報が変わったら通知してくれれば気づけた…
このようなことがなくなればいいと思い、作りました。

#2.実装方法
A.ハードウェア
RaspberryPi(Pico以外)
少し動作が重いですが、本体とケース込みで3000円以下とコスパがよいZero WHがお勧めです。
https://akizukidenshi.com/catalog/g/gM-12958/

B.ソフトウェア
Python3
バージョンは3.8を利用しました。

LINE Notify
登録の仕方、メッセージの送信方法は以下の記事を参考にしました。
https://qiita.com/moriita/items/5b199ac6b14ceaa4f7c9


#3.実装時注意点
ファイルの入出力について

#4.実装方法
4-1.実装コード
今回は、モジュールを利用したく動作を2つのファイルに分けた。
A:1時間ごとの天気予報をスクレイピングして取得する。(get_weather_1hour.py)
B:取得した予報と今までのファイルを照らし合わせ、変わったらLINE Notifyで通知(return_weather.py)

※return_weather.pyとget_weather_1hour.pyは同じディレクトリにおいてください。

requestでhtmlファイルを取得、その後beautifulSoupでhtmlファイルから必要な情報を取り出しています。


                         
```python:get_weather_1_hour.py                            
import requests
from bs4 import BeautifulSoup
import datetime
import return_weather

def weather_1hour():
    #天気サイト
    url = "指定したい場所のURL"
    r = requests.get(url)
    soup = BeautifulSoup(r.content, 'html.parser')

    #天気の情報
    weather_status=[i.text for i in soup.find_all('td')[(34):(57)]]
    return_weather.check_weather(weather_status)
weather_1hour()
```



```python:return_weather.py                            
import requests
import datetime
def send_line(arglist):
    dt = datetime.datetime.now()
    
    #午前5時に今日24時間の天気を一斉送信
    if dt.hour == 5:
        notification_message = "\n今日の天気です。\n"
        for i in range (len(arglist)):
            notification_message += str(i)+"時:"+str(arglist[i])+"\n"
    else:
        notification_message = "\n以下の時刻の天気が変わりました\n"
    for n in range(len(arglist)):
        if len(arglist) == 0:
            print("天気は変わらないよ")
            break
        #午前5時に今日24時間の天気を一斉送信
        elif dt.hour == 5:
            print("gozen0")
            break
        else:
            notification_message += str(arglist[n])+"\n"
    if len(arglist) == 0:
        pass
    else:
        notification_message += "\n"+"\n"+"雨の場合は洗濯物を取り込んでおきましょう。"
        line_notify_token = 'GbuUVMoNfQcwVJc6jDLpZXTXwIdCyqXlXGKWDEBikQP'
        line_notify_api = 'https://notify-api.line.me/api/notify'
        headers = {'Authorization': f'Bearer {line_notify_token}'}
        data = {'message': f'message: {notification_message}'}
        requests.post(line_notify_api, headers = headers, data = data)

def check_weather(args):
    sendlist = []
    dt = datetime.datetime.now()
    path = 'test.txt'
    with open(path,encoding='utf-8') as f:
        #linesテスト
        lines = f.readlines()

        for i in range(len(lines)):
            #5時は更新しない
            if dt.hour == 5:
                sendlist = args
                break

            if i >=dt.hour:
                lines[i] = lines[i].replace("\n","")

        #変化なし
                if str(args[i]) == str(lines[i]):
                    pass
                else:
                    sendlist.append(str(i)+"時:"+str(lines[i])+"→"+args[i])
                    lines[i] = str(args[i])
                lines[i]= lines[i]+"\n"
        if (len(lines)) == 0:
            print("変化はありません")
        with open(path,mode="w",encoding='utf-8',newline='\n') as files:           
            if dt.hour == 5:
                #ファイルの中身を0バイトにする
                files.truncate(0)
                
                #ファイル書き込み
                files.writelines(sendlist)
            else:
                #変化分だけ書き込み
                files.writelines(lines)

    #LINE送信
    send_line(sendlist)
```

get_weather_1hour.pyを実行すると
![スクリーンショット 2021-08-29 075338.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702737/baf58835-0bf3-0128-7384-00971320223a.png)

このように、LINE Notifyから通知が来ました。

今回は簡単のため、get_weather_1hour.pyを実行しないと通知が来ないようにしています。
しかし、自動起動やcrontabなどを使うことで定期的に通知ができます。




#5.考察
発想から作成までに時間がかかってしまった。
#6.参考サイト
https://qiita.com/Yuu94/items/9ffdfcb2c26d6b33792e

Pythonでファイルを読み込む処理を作る際、参考にさせていただきました。

https://note.nkmk.me/python-string-line-break/

文字列に改行を入れる際に参考にさせていただきました。

https://teratail.com/questions/263025

ファイルの中身を0バイトにする処理を参考にさせていただきました。