SIGMA-SE Math & Tech Library

SIGMA-SE Math & Tech Library


数学と情報技術をテーマに、書籍や教材だけではつかみにくい考え方を具体例とともに簡潔にわかりやすく伝える解説サイトです。
技術の歴史や背景、関連知識の整理、学習のための覚書や要約記事も掲載しています。

Python - タスク指向型対話:2/5 OpenWeatherMap・Telegramの環境準備

概要

状態遷移ベースの天気案内Botで使用するOpenWeatherMap、Telegram、python-telegram-botの準備手順を整理する。

天気案内Botでは、天気情報を外部APIから取得し、ユーザーとのやり取りをメッセンジャー上で行う必要がある。OpenWeatherMapは天気情報の取得、Telegramはユーザーとの対話画面、python-telegram-botはBot実装の接続部分を担当する。

ここでは、API利用登録、Bot作成、ライブラリのインストール、オウム返しBotによる疎通確認までを扱う。

この記事の構成

対象環境と利用上の注意

  • 本文記載時の環境
    2020年7月時点のOpenWeatherMap APIと、python-telegram-bot \(12.8\)の同期APIを使った手順。
  • 確認時期
    2026年8月にTelegram Bot API、python-telegram-bot、OpenWeatherMapの公式資料と照合し、記載内容を見直した。
  • 現在そのまま利用できない箇所
    掲載コード全体は現行サービス・ライブラリで再実行していない。
    料金、呼出し上限、登録画面、APIレスポンスは変更され得る。
    現行のpython-telegram-botは掲載コードとAPIが異なるため、旧コードをそのまま新規利用せず、利用する版を固定して公式サンプルへ合わせる。

作業時の注意点

  • APIキーとBotトークン
    コードに直書きすると漏えいリスクがあるため、環境変数や設定ファイルで管理。
  • 疎通確認の順番
    天気APIとTelegram Botを別々に確認してから結合すると原因を切り分けやすい。
  • ライブラリのバージョン
    python-telegram-botはバージョンで書き方が変わるため、記事のコードと環境を合わせる。

解説と実装サンプル

天気情報を取得する「OpenWeatherMap」WebAPIの概要と利用登録

  • 天気APIの準備と疎通確認

    天気情報は、無償で天気情報を取得できるOpenWeatherMapのWebAPIを用いて取得する。
    下記トップページにアクセスするとGUIでも天気情報を確認することができる。

    【OpenWeatherMap】: https://openweathermap.org/

    本文記載時はFreeプランで毎分60回までの呼出しと、3時間ごとの5日予報を利用できた。料金、呼出し上限、利用できるAPIは変更されるため、実装時はOpenWeatherMap公式の料金・APIページで現行条件を確認する。
    そして、APIをコールするには、API Keyが必要でアカウント作成する必要がある。

    • OpenWeatherMapのアカウント作成
      下記のアカウント作成ページ【Create New Account】を開き、UsernameEnter emailPasswordRepeat passwordを入力し、「Create Account」ボタンクリックでアカウントを作成。

      【Create New Account】: https://home.openweathermap.org/users/sign_up

      アカウント作成後、ログインした状態で下記のAPIKey確認ページ【api_keys】開くとKey欄にAPIKeyが表示されるので、ここからAPIKeyを確認。
      ※ 登録完了のメール本文でもAPIKeyを確認できる。

      【api_keys】: https://home.openweathermap.org/api_keys

      また、PythonからURLへアクセスするため、サードパーティライブラリであるRequestsが必要。
      ※ 標準ライブラリurllibでもアクセスできるが、Requestsの方がシンプルであるため、これを使用。

    • Requestsのインストール

      $ pip3 install requests
      

      以上でOpenWeatherMapAPIを呼ぶ準備が完了。
      以下、準備されている2つのAPI現在の天気情報天気予報の呼出確認となる。

    • 呼出し確認(現在の天気情報)
      福岡県(県庁)の緯度、経度を指定して現在の天気情報(JSON)を取得。
      ※ API呼出しのunits=metricは、気温を摂氏で取得する指定とする。

      $ python
          >>> import requests
          >>>
          >>> # 福岡県(県庁)の緯度、経度
          >>> lat = 33.60
          >>> lon = 130.41
          >>>
          >>> # 自アカウントのAPIKey
          >>> appid = '**********'
          >>>
          >>> # 現在の天気情報
          >>> current_weather_url = 'https://api.openweathermap.org/data/2.5/weather'
          >>>
          >>> # API呼出し
          >>> response = requests.get("{}?lat={}&lon={}&lang=ja&units=metric&APPID={}".format(current_weather_url,lat,lon,appid))
          >>>
          >>> # 結果出力
          >>> response.json()
          {'coord': {'lon': 130.41, 'lat': 33.6}, 'weather': [{'id': 803, 'main': 'Clouds', 'description': '曇りがち', 'icon': '04n'}], 'base': 'stations', 'main': {'temp': 25.87, 'feels_like': 29.51, 'temp_min': 24.44, 'temp_max': 27.78, 'pressure': 1010, 'humidity': 83}, 'visibility': 10000, 'wind': {'speed': 2.1, 'deg': 290}, 'clouds': {'all': 75}, 'dt': 1595079741, 'sys': {'type': 1, 'id': 7998, 'country': 'JP', 'sunrise': 1595017250, 'sunset': 1595068076}, 'timezone': 32400, 'id': 1863967, 'name': '福岡市', 'cod': 200}
          >>>
      
    • 呼出し確認(天気予報) 上記と同じ、福岡県(県庁)の緯度、経度を指定して天気予報を取得。
      list配列に3時間毎の天気予報(JSON)が格納されいる。
      (*1)4つ目以降のlist配列は割愛

      $ python
          >>> import requests
          >>>
          >>> # 福岡県(県庁)の緯度、経度
          >>> lat = 33.60
          >>> lon = 130.41
          >>>
          >>> # 自アカウントのAPIKey
          >>> appid = '**********'
          >>>
          >>> # 明日以降の天気情報
          >>> forecast_url = 'https://api.openweathermap.org/data/2.5/forecast'
          >>>
          >>> # API呼出し
          response = requests.get("{}?lat={}&lon={}&lang=ja&units=metric&APPID={}".format(forecast_url,lat,lon,appid))
          >>>
          >>> # 結果出力
          >>> response.json()["list"][0]
          {'dt': 1595084400, 'main': {'temp': 24.97, 'feels_like': 28.68, 'temp_min': 24.37, 'temp_max': 24.97, 'pressure': 1010, 'sea_level': 1010, 'grnd_level': 1009, 'humidity': 79, 'temp_kf': 0.6}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': '厚い雲', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 0.72, 'deg': 54}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2020-07-18 15:00:00'}
          >>>
          >>> response.json()["list"][1]
          {'dt': 1595095200, 'main': {'temp': 24.65, 'feels_like': 27.75, 'temp_min': 24.41, 'temp_max': 24.65, 'pressure': 1010, 'sea_level': 1010, 'grnd_level': 1009, 'humidity': 75, 'temp_kf': 0.24}, 'weather': [{'id': 804, 'main': 'Clouds', 'description': '厚い雲', 'icon': '04n'}], 'clouds': {'all': 100}, 'wind': {'speed': 0.79, 'deg': 157}, 'visibility': 10000, 'pop': 0, 'sys': {'pod': 'n'}, 'dt_txt': '2020-07-18 18:00:00'}
          >>>
          >>> response.json()["list"][2]
          {'dt': 1595106000, 'main': {'temp': 24.47, 'feels_like': 26.82, 'temp_min': 24.4, 'temp_max': 24.47, 'pressure': 1010, 'sea_level': 1010, 'grnd_level': 1009, 'humidity': 75, 'temp_kf': 0.07}, 'weather': [{'id': 500, 'main': 'Rain', 'description': '小雨', 'icon': '10d'}], 'clouds': {'all': 100}, 'wind': {'speed': 1.75, 'deg': 161}, 'visibility': 10000, 'pop': 0.54, 'rain': {'3h': 0.25}, 'sys': {'pod': 'd'}, 'dt_txt': '2020-07-18 21:00:00'}
          >>>
      

メッセンジャーアプリ「Telegram」の利用登録と「python-telegram-bot」のインストール

  • Telegram Botの準備

    最後に対話で使用するメッセンジャーアプリTelegramの利用登録(アカウント作成)とPythonからTelegramを認識できるようにするためのライブラリであるpython-telegram-botをインストールする。

    • Telegramインストーラのダウンロードとアカウント作成
      下記のTelegramトップページ【Telegram Top】を開き、インストール端末に応じたインストーラを選択し、ダウンロード。
      ※ Windowsなら「Telegram for Pc/Mac/Linux」リンク →「Get Telegram for Windows」ボタンでダウンロード。
      ※ Linuxなら「Telegram for Pc/Mac/Linux」リンク →「Show all platforms」リンク→「Get Telegram for Linux 64 bit」ボタンでダウンロード。

      【Telegram Top】: https://telegram.org

      続いて、ダウンロードしたインストーラを実行後、Telegramを起動し、アカウント作成を行う。
      ※ 国番号を付加した電話番号を入力後、SMS確認コードの本人確認が必要。

    • スクリーンネームの登録とアクセストークンの取得
      新しいBotの作成とスクリーンネームの登録を行い、アクセストークンを取得。

      アカウント作成後、左サイドメニュー上部のユーザー検索欄から「@BotFather」で検索し、「Start」ボタンクリックで「@BotFather」と対話できる状態にする。

      以降は、下記のようにBot名の入力とスクリーンネームを登録し、アクセストークンを取得。

      • Bot名の入力(Botの新規作成)
        「Alright, a new bot. How are we going to call it? Please choose a name for your bot.」と表示されるので、任意のBot名を入力。
        ※ 下記サンプルでは「SHamaBot 」と入力している。

      • スクリーンネームの登録
        「Good. Now let's choose a username for your bot. It must end in bot. Like this, for example: TetrisBot or tetris_bot.」
        と表示されるので、末尾がbotで終わるスクリーンネームを入力。(既に使用されているスクリーンネームは使用不可。)

        ※ 下記サンプルでは、Bot名と同じ「SHamaBot 」で入力したところ、既に使用されているスクリーンネームであったため「sorry this username is already taken. please try something different」とエラーが出ている。
        そのため「GSHamaBot」の再入力で登録している。

      • アクセストークンの取得
        スクリーンネームの登録後、「Use this token to access the HTTP API:」の直後にアクセストークンが表示される。

        ※ このアクセストークンがTelegramクライアント(Telegramをインストールした端末)とPythonの対話システムTelegramのサーバーを介して互いに連携するためのKeyとなる。

        pid40_1

    • 「python-telegram-bot」のインストール
      掲載コードは旧版 \(12.8\) のAPIを使うため、再現する場合は隔離した仮想環境で版を固定する。新規実装では現行版の公式サンプルを使用する。

      $ pip3 install 'python-telegram-bot==12.8'
      

TelegramBotを使用した対話サンプル(オウム返し)

  • オウム返しBotの実装と確認

    下記の(*1)、(*2)が上記で登録した@GSHamaBotのレスポンスをPythonでオウム返しする実装サンプルで、(*1)のTelegramBotクラスは、GSHamaBot(Telegramサーバー側)との通信処理で、(*2)のEchoSystemクラスは、Botが応答する内容の制御処理となる。

    • (*1)TelegramBotクラス(telegram_bot.py)
      ※ 実行前にアクセストークンを環境変数TELEGRAM_BOT_TOKENへ設定する。ソースコードへ直書きしない。

      import os
      from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
      
      # アクセストークンは環境変数から取得
      TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
      
      class TelegramBot:
          def __init__(self, system):
              self.system = system
      
          def start(self, bot, update):
              # 辞書型 inputにユーザIDを設定
              input = {'utt': None, 'sessionId': str(update.message.from_user.id)}
      
              # システムからの最初の発話をinitial_messageから取得し,送信
              update.message.reply_text(self.system.initial_message(input)["utt"])
      
          def message(self, bot, update):
              # 辞書型 inputにユーザからの発話とユーザIDを設定
              input = {'utt': update.message.text, 'sessionId': str(update.message.from_user.id)}
      
              # replyメソッドによりinputから発話を生成
              system_output = self.system.reply(input)
      
              # 発話を送信
              update.message.reply_text(system_output["utt"])
      
          def run(self):
              updater = Updater(TOKEN)
              dp = updater.dispatcher
              dp.add_handler(CommandHandler("start", self.start))
              dp.add_handler(MessageHandler(Filters.text, self.message))
              updater.start_polling()
              updater.idle()
      
    • (*2)EchoSystemクラス(echo_system.py)

      from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
      from telegram_bot import TelegramBot
      
      # ユーザの入力をそのまま返す対話システム.
      class EchoSystem:
          def __init__(self):
              pass
      
          def initial_message(self, input):
              return {'utt': 'こんにちは。対話を始めましょう。', 'end':False}
      
          def reply(self, input):
              return {"utt": input['utt'], "end": False}
      
      if __name__ == '__main__':
          system = EchoSystem()
          bot = TelegramBot(system)
          bot.run()
      
      • 以下、実行順に処理の流れを解説
        • まず、(*2)EchoSystemクラス(echo_system.py)を実行
        • (*2)EchoSystemクラスのメイン処理で自身のインスタンスをTelegramBotクラスのコンストラクタに渡し、(*1)TelegramBotクラスの runメソッド をコール
        • (*1)TelegramBotクラスの runメソッドでは、telegramサーバー側のUpdater関数にてアクセストークンを設定後、自身のstartメソッドをコマンドハンドラとして、messageメソッドをメッセージハンドラとして設定し、コマンドハンドラとメッセージハンドラの受付を開始(待機状態)
        • Telegramクライアントで「start」ボタンをクリックするとTelegramサーバーがstartコマンドを発行し、上記で設定(待機)していたコマンドハンドラを受付け、startメソッドが実行される
        • startメソッドでは、まずユーザーの発話情報を保持する input(dict型) オブジェクトを定義し、uttは発話内容、 sessionIdはセッションIDを格納
          ※ Telegramの対話はすべて、システム側(Bot側)の発話から始まるため、utt(発話内容)は None を設定し、sessionIdには、ユーザーのセッションIDを設定している。
        • 次に initial_message でBotの初回発話内容を取得後、Telegramサーバー側の reply_text メソッドをコールし、Botの発話内容( 'utt': 'こんにちは。対話を始めましょう。' )を送信 ※ initial_messageの戻り値dict型のendは、対話の完了フラグ(True:完了、False:継続)
        • その後、ユーザーがTelegramクライアントから発話すると、上記で設定(待機)していたメッセージハンドラを受付け、messageメソッドが実行される
        • messageメソッドでは、まずユーザーの発話内容(Telegramサーバー側の text から取得したutt(発話内容))とユーザーのセッションIDでユーザー発話情報inputを定義 続けて reply メソッドで発話内容を取得後(*1)、Telegramサーバー側の reply_text メソッドに発信内容を渡して送信。
          (*1)発話内容は、オウム返し するため、引数の発話内容 input['utt'] をそのまま返している。
    • 上記「対話サンプル (オウム返し)」の実行確認
      以下、(1)、(2)の実行確認結果。
      ※「telegram_bot.py」のアクセストークン(TOKEN)を、自身のものに置き換えることを忘れずに。

      「echo_system.py」の実行にて対話を開始。

      $ python ~/gitlocalrep/dsbook/echo_system.py
      /root/gitlocalrep/dsbook/telegram_bot.py:29: TelegramDeprecationWarning: Old Handler API is deprecated - see https://git.io/fxJuV for details
      updater = Updater(TOKEN)
      

      上記コンソールが実行中の状態。

      ↓ ユーザーの入力をすべてオウム返しする。
      ※ 対話(オウム返し)を終了する場合は「Ctrl + C」で終了。
      pid40_2

まとめ

  • OpenWeatherMapは天気情報取得、Telegramは対話インターフェースとして使う。
  • python-telegram-botを使うと、PythonからTelegram Botを実装できる。
  • 本格実装の前に、APIとBotの疎通確認を分けて行うと安全。

参考文献

この記事を共有
Xで共有 Facebookで共有 LINEで共有



Copyright SIGMA-SE All Rights Reserved.
s-hama@sigma-se.jp