【LINE BOT】Pythonで天気予報BOTを作成する方法(後編)

概要

Pythonで天気予報BOTを作成してみた後編になる。
前編にてWEBスクレイピングで取得した天気予報情報をもとに、メッセージ配信を行う方法をまとめた。

また、グループチャットにBOTを招待してメッセージ送信する方法も紹介している。

あわせて読みたい

概要 Pythonで定時刻になると天気予報BOTから今日と明日の天気予報が配信されるBOTを作成した。 今日と明日の天気予報情報は、WEBスクレイピングで自動収集する。 当記事では天気予報サイトから欲しい情報をWEBスクレイピング[…]

【Pythonで天気予報BOTを作成する方法(前編)】アイキャッチ

 

BOTメッセージ作成

前回作成した天気予報の辞書データが格納されたリストをもとに、メッセージを作成する。

 

BOT配信メッセージ

タイトルとメッセージリストを、用意したメッセージのひな形にバインドする。

Jupyter Lab


# メッセージタイトル
msg_title = "★" + weather_title + "★\n"

# BOTメッセージフォーマット
msg_format = """
    ====={0}=====
    天気              : {1}
    最高気温(C)       : {2}
    最低気温(C)       : {3}
    降水確率[00-06]   : {4}
    降水確率[06-12]   : {5}
    降水確率[12-18]   : {6}
    降水確率[18-24]   : {7}
"""
msg = ""
for weather in weather_list:
    msg += msg_format.format(
        weather["date_info"], 
        weather["weather"], 
        weather["high_temperature"], 
        weather["low_temperature"], 
        weather["prob_midnight"], 
        weather["prob_morning"],  
        weather["prob_afternoon"], 
        weather["prob_night"]
    )
bot_msg = msg_title + msg
print(bot_msg)

# 出力
#★福山市の今日明日の天気★
#
#    =====今日 09月02日 (土)=====
#    天気              : 曇のち晴
#    最高気温(C)       : 32℃
#    最低気温(C)       : 25℃
#    降水確率[00-06]   : ---
#    降水確率[06-12]   : 20%
#    降水確率[12-18]   : 20%
#    降水確率[18-24]   : 10%
#
#    =====明日 09月03日 (日)=====
#    天気              : 晴
#    最高気温(C)       : 36℃
#    最低気温(C)       : 24℃
#    降水確率[00-06]   : 10%
#    降水確率[06-12]   : 10%
#    降水確率[12-18]   : 0%
#    降水確率[18-24]   : 10%

 

# BOTメッセージフォーマット
msg_format = """
====={0}=====
天気 : {1}
最高気温(C) : {2}
最低気温(C) : {3}
降水確率[00-06] : {4}
降水確率[06-12] : {5}
降水確率[12-18] : {6}
降水確率[18-24] : {7}
"""

天気予報情報をバインドさせるためのメッセージフォーマット。
バインドさせたい箇所に{n}を連番で記述する

 

msg = ""
for weather in weather_list:
    msg += msg_format.format(
      weather["date_info"],
      weather["weather"],
      weather["high_temperature"],
      weather["low_temperature"],
      weather["prob_midnight"],
      weather["prob_morning"],
      weather["prob_afternoon"],
      weather["prob_night"]
    )

formatメソッドの引数にバインドさせたい順で天気予報情報を設定する。
最終的に変数msgに戻り値を設定する。

msg_format変数に格納しているメッセージフォーマットは、formatメソッドを使用しても値が変更されない。
そのため、ループで回してformatメソッドを何回呼び出しても同じひな形を使用できる

 

Pythonファイルに移動

これまでJupyter Labを使用して開発してきたが、実際にメッセージ配信をするファイルはPythonファイル(拡張子が.py)になる
そのため、これまで記述してきた内容をPythonファイルに移植する

尚、そのまま移植してもわかりづらいため、機能ごとにメソッドを作成して移植した。

main.py


import json
from linebot import LineBotApi
from linebot.models import TextSendMessage
import requests
from bs4 import BeautifulSoup
import re

# 設定情報読み込み
with open("settings.json", encoding="utf-8") as f:
    res = json.load(f)
# 定数 ---------------
# チャネルアクセストークン
CH_TOKEN = res["CH_TOKEN"]
# ユーザーID
USER_ID = res["USER_ID"]
# 天気予報URL(福山)
URL = "https://tenki.jp/forecast/7/37/6710/34207/"

def get_page_info():
    """ 読み込みページ情報取得 """

    res = requests.get(URL)
    html = res.text.encode(res.encoding)
    soup = BeautifulSoup(html, 'lxml')

    return soup

def get_wether_info(soup):
    """ 今日明日の天気予報dict情報の取得 """

    # 今日明日の天気リスト
    weather_list = []

    # 今日の天気------------------------------------
    today_weather = {}
    section = soup.find("section", "today-weather")
    # 今日の日付
    today_section = section.find("h3", "left-style").contents
    today_weather["date_info"] = re.sub("\xa0", " ", f"{today_section[0]} {today_section[1].text}")
    # 今日の天気
    today_weather["weather"] = section.find("p", "weather-telop").text
    # 最高気温
    today_weather["high_temperature"] = section.find("dd", "high-temp temp").text
    # 最低気温
    today_weather["low_temperature"] = section.find("dd", "low-temp temp").text
    # 降水確率
    today_weather["prob_midnight"] = section.select('.rain-probability > td')[0].text
    today_weather["prob_morning"] = section.select('.rain-probability > td')[1].text
    today_weather["prob_afternoon"] = section.select('.rain-probability > td')[2].text
    today_weather["prob_night"] = section.select('.rain-probability > td')[3].text
    # 今日明日の天気リストの格納
    weather_list.append(today_weather)

    # 明日の天気------------------------------------
    tomorrow_weather = {}
    # 明日の天気セクション
    section = soup.find("section", "tomorrow-weather")
    today_section = section.find("h3", "left-style").contents
    tomorrow_weather["date_info"] = re.sub("\xa0", " ", f"{today_section[0]} {today_section[1].text}")
    # 明日の天気
    tomorrow_weather["weather"] = section.find("p", "weather-telop").string
    # 最高気温
    tomorrow_weather["high_temperature"] = section.find("dd", "high-temp temp").text
    # 最低気温
    tomorrow_weather["low_temperature"] = section.find("dd", "low-temp temp").text
    # 降水確率
    tomorrow_weather["prob_midnight"] = section.select('.rain-probability > td')[0].text
    tomorrow_weather["prob_morning"] = section.select('.rain-probability > td')[1].text
    tomorrow_weather["prob_afternoon"] = section.select('.rain-probability > td')[2].text
    tomorrow_weather["prob_night"] = section.select('.rain-probability > td')[3].text
    # 今日明日の天気リストの格納
    weather_list.append(tomorrow_weather)

    return weather_list

def create_msg(weather_title, weather_list):
    """ LINE BOTメッセージ作成 """

    # メッセージタイトル
    msg_title = "★" + weather_title + "★\n"

    # BOTメッセージフォーマット
    msg_format = """
        ====={0}=====
        天気              : {1}
        最高気温(C)       : {2}
        最低気温(C)       : {3}
        降水確率[00-06]   : {4}
        降水確率[06-12]   : {5}
        降水確率[12-18]   : {6}
        降水確率[18-24]   : {7}
    """
    msg = ""
    for weather in weather_list:
        msg += msg_format.format(
            weather["date_info"],
            weather["weather"],
            weather["high_temperature"],
            weather["low_temperature"],
            weather["prob_midnight"],
            weather["prob_morning"],
            weather["prob_afternoon"],
            weather["prob_night"]
        )
    bot_msg = msg_title + msg

    return bot_msg


def main():
    """ LINE BOTメイン処理 """

    # 天気予報ページ情報取得
    soup = get_page_info()

    # ページタイトル
    page_title = soup.title.text
    m = re.search(".*天気", page_title)
    weather_title = m.group(0) # 福山市の今日明日の天気

    # 今日明日の天気予報情報
    weather_list = get_wether_info(soup)

    # LINE BOTメッセージ
    msg = create_msg(weather_title, weather_list)
    messages = TextSendMessage(text=msg)
    line_bot_api = LineBotApi(CH_TOKEN)
    line_bot_api.push_message(USER_ID, messages=messages)


if __name__ == "__main__":
    main()

 

# LINE BOTメッセージ
msg = create_msg(weather_title, weather_list)
messages = TextSendMessage(text=msg)
line_bot_api = LineBotApi(CH_TOKEN)
line_bot_api.push_message(USER_ID, messages=messages)

作成したメッセージを最終的にLINEのAPIで送信する。

ターミナルを開いて、以下を実行してLINEに正しくメッセージが届くか確認すること。

ターミナル


python main.py

 

 メッセージの定期実行

Git Hub Actionsを使用して、定刻になるとmain.pyを実行する仕組みを作成する。

【Pythonで天気予報BOTを作成する方法(後編)】スケジュール実行概要
▲BOTの定期実行イメージ

 

前提

・Git Hub側でリモートリポジトリを作成していること(※Git Hub側でリポジトリを作成する際には、privateにして作成すること
・VSCodeでGit連携できる状態であること

 

Git連携

Git Hub Actionsを利用するため、作成したLINE BOTファイルをGit Hubに連携する。

【Pythonで天気予報BOTを作成する方法(後編)】作業フォルダを開く
▲LINE BOTファイルを作成したフォルダを開く

 

【Pythonで天気予報BOTを作成する方法(後編)】リポジトリの初期化
▲リポジトリを初期化するボタンを押下

 

【Pythonで天気予報BOTを作成する方法(後編)】リモートの追加
▲リモートの追加

 

【Pythonで天気予報BOTを作成する方法(後編)】リポジトリの追加
▲作成したリポジトリを選択

 

【Pythonで天気予報BOTを作成する方法(後編)】リモート名の追加
▲リモート名の入力

 

【Pythonで天気予報BOTを作成する方法(後編)】資材をコミットする
▲コミットする

 

【Pythonで天気予報BOTを作成する方法(後編)】資材をプッシュする
▲プッシュする

 

スケジュール実行

Git Hub Actionsにて、定期的にmain.pyを実行させるymlファイルを作成する。

【Pythonで天気予報BOTを作成する方法(後編)】ymlファイルの作成
▲上記のリンクを選択

 

ymlファイルの作成

main.yml


# ワークフロー名	
name: chatbot	
	
# 実行タイミング	
# スケジュールの設定時刻はUTCとなる。	
# 例えばUTC時刻を22時とすると、日本時間(JST: Japan Standard Time)の場合は翌7時になる。	
on:	
  push:	
  #schedule:	
  #  - cron: '0 22 * * *'	
	
jobs:	
  build:	
    # Ubuntuの最新版環境内で処理を実行することを指定	
    runs-on: ubuntu-latest	
	
    # 実行する処理&コマンド指定	
    steps:	
      # リポジトリからチェックアウトして以下の処理を実行していく	
      - uses: actions/checkout@v2	
      - name: Set up Python 3.8	
        uses: actions/setup-python@v1	
        with:	
          python-version: 3.8	
      - name: Install dependencies	
        run: |	
          # pip更新	
          python -m pip install --upgrade pip	
          # 必要なパッケージインストール	
          pip install line-bot-sdk	
          pip install beautifulsoup4	
          pip install lxml	
      - name: Run script	
        run: |	
          # main.pyの実行	
          python main.py	

 

push:
#schedule:
# – cron: ‘0 22 * * *’

main.pyを実行するためのスケジュール設定箇所。
pushとしており、何らかのファイルがプッシュされたタイミングでLINE BOTファイルを実行する。

コメントアウトしている箇所は後で書き換える部分となる
上記の意味は翌朝7:00にLINE BOTファイルを実行するという意味。※Git Hub Actionsの定期実行設定では必ずしも時刻通りにならないので注意
各数値の意味は以下となる。

・0分
・UTC22時(日本時刻:翌7:00)
・毎日(*)
・毎月(*)
・すべての曜日(*)

 

GitHub Docs

GitHub で特定のアクティビティが実行された時、スケジュールした時間、または GitHub 外でイベントが発生した時…

 

# 必要なパッケージインストール
pip install line-bot-sdk
pip install beautifulsoup4
pip install lxml

上記はGit Hub ActionsでLINE BOTファイルを実行する際に必要なパッケージとなる。

 

run: |
# main.pyの実行
python main.py

上記はGit Hub Actionsに実行させるファイル名になる。
今回はmain.pyを作成したので、そのファイル名を指定している。

 

ymlファイルのコミット(プッシュ)

ymlファイルをコミットする。
リモート側でのコミットはプッシュ扱いとなるため、これによりGit Hub Actionsがmain.pyを実行する。

【Pythonで天気予報BOTを作成する方法(後編)】ymlファイルのコミット
▲作成したymlファイルをコミット(プッシュ)

 

ymlファイルをコミットして、LINE BOTメッセージが届いたら動作確認完了
※buildに時間がかかるため、コミットして少しまてば届く

 

スケジュール設定

LINE BOTから問題なくメッセージが届いたなら、ymlファイルを以下のように修正して定期的にBOTメッセージを送信させるようにする。(翌7:00に自動でメッセージ配信を行う設定
※Git Hub Actionsでは時間通りにメッセージが届かず、割と遅れてメッセージが届くので注意

main.yml


# ワークフロー名
name: test_chatbot

# 実行タイミング
# スケジュールの設定時刻はUTCとなる。
# 以下の例ではUTC時刻が22時のため、日本時間(JST: Japan Standard Time)だと翌7時になる。
on:
  #push:
  schedule:
    - cron: '0 22 * * *'
(略)

 

動作確認

翌日に届いたメッセージが以下になる。
※7時ぴったりにはメッセージは届かない

【Pythonで天気予報BOTを作成する方法(後編)】BOTの動作確認
▲LINE BOTからの自動配信

 

補足

グループチャットにBOTを招待してメッセージ配信したいときは、グループチャットのIDを取得する必要がある。
以下はグループIDを取得して、グループチャットにてメッセージ配信する方法について紹介する。

 

BOT設定

複数人トークへの参加を許可する。

【Pythonで天気予報BOTを作成する方法(後編)】グループトークの有効化
▲グループトークへの参加を許可する

 

GASでグループID取得

Google Apps Scriptを使用してグループIDを取得する。

準備

BOTを招待するためのグループを作成する。

【Pythonで天気予報BOTを作成する方法(後編)】グループの作成
▲グループトークの用意

 

GASでグループIDの取得スクリプト作成

BOTをグループに招待した際にスプレッドシートにグループIDを書き込むスクリプトを作成する。

【Pythonで天気予報BOTを作成する方法(後編)】スプレッドシートの作成
▲スプレッドシート選択

 

【Pythonで天気予報BOTを作成する方法(後編)】Appsスクリプト選択
▲スプレッドシートに紐づけたAppsスクリプト選択

 

GASファイルに以下のコードを張り付ける。

GAS


function doPost(e){
 var json = JSON.parse(e.postData.contents);
 var gid = json.events[0].source.groupId;
  
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
 sheet.getRange(1,1).setValue(gid);

}

 

URL取得

GASをデプロイしてURLを取得する。

【Pythonで天気予報BOTを作成する方法(後編)】デプロイ選択
▲デプロイ選択

 

【Pythonで天気予報BOTを作成する方法(後編)】ウェブアプリ選択
▲ウェブアプリ選択

 

【Pythonで天気予報BOTを作成する方法(後編)】デプロイ設定
▲上記の設定でデプロイ選択

 

【Pythonで天気予報BOTを作成する方法(後編)】アクセス承認選択
▲アクセスを承認を押下

 

【Pythonで天気予報BOTを作成する方法(後編)】アクセス承認許可OK
▲上記のリンク押下

 

【Pythonで天気予報BOTを作成する方法(後編)】アクセス承認OK
▲アクセスを許可する

 

【Pythonで天気予報BOTを作成する方法(後編)】webhookの設定
▲デプロイ成功

 

【Pythonで天気予報BOTを作成する方法(後編)】webhookの設定
▲コピーしたデプロイURLを、招待したいBOTのWebhook URLに設定

 

【Pythonで天気予報BOTを作成する方法(後編)】BOTの招待
▲対象のBOTをグループに招待

 

【Pythonで天気予報BOTを作成する方法(後編)】スプレッドシートにグループID
▲スプレッドシートにLINEのグループIDが記載される

 

【Pythonで天気予報BOTを作成する方法(後編)】グループラインにBOT配信
▲ユーザーIDをグループIDに変更して送信することで、グループにBOTからメッセージ配信できる

 

スポンサーリンク