Python で気象庁の天気APIを活用して Discord に通知、AWS Lambda + EventBridge で定期実行

## 本記事の目的

私自身の学習結果のアウトプットの一環として、PythonとAWSを用い、気象情報を自動通知するツールを作成しました。

## 前提知識（※生成AIを活用することでも代替可能です）

* Pythonの基本文法の理解
* AWSについてのアーキテクチャの基本概念
* Discord Webhook URLの利用方法の理解

## 利用技術の検討

> ※当初「スクレイピングによる取得」も検討しましたが、最終的には気象庁の公式API（JSON）を使用しており、スクレイピングは行っていません。

今回のツールを設計するにあたり、複数の技術を比較検討しました（私の主観も含まれます）。ここでは、どのような選択肢があったのか、その中からなぜ現在の構成を選んだのかという検討過程を説明します。

### ▶ 気象情報取得手段の検討

| 候補             | 特徴                             | 課題                          |
| -------------- | ------------------------------ | --------------------------- |
| 気象庁API（JSON）   | 無料・信頼性が高く、日本の気象情報に特化           | ドキュメントが簡素で、構造理解に少し工夫が必要     |
| OpenWeatherMap | グローバルに有名で使いやすく、英語のAPIリファレンスも充実 | 一部の詳細データ取得は有料、精度もやや簡易的な傾向   |
| スクレイピング        | 任意のWebページから直接データ取得可能           | 規約違反の恐れ、構造変更に脆弱、信頼性・再現性に乏しい |

→ 最終的に、**信頼性と無料利用、API形式の安定性を優先し、気象庁のJSON APIを採用**しました。

### ▶ 通知方法の検討

> ※LINE Notifyは2025年3月31日をもってサービス終了となりました。そのため現在は利用できません。代替としてLINE Messaging APIが案内されていますが、Webhook形式ではなく、Bot開発や公式アカウント運用に近い形になるため、今回は候補から除外しました。

| 候補          | 特徴                      | 課題                          |
| ----------- | ----------------------- | --------------------------- |
| Discord     | Webhook対応・スマホで即座に確認しやすい | 初回Webhook作成が少し手順多め          |
| Slack       | チーム通知向けに便利・同様にWebhook対応 | 無料版では通知の履歴保存に制限あり           |
| LINE Notify | 個人利用に向いている              | Webhook形式ではなく、アクセストークン登録が必要 |

→ **Webhook形式で簡単に通知できること**、**確認がスマホでも容易であること**から、Discordを選定しました。

---
🔰 Webhookとは？

Webhook（ウェブフック）とは、「特定のイベントが発生したときに、自動的に決められたURLに通知（リクエスト）を送る仕組み」です。

たとえば今回のように「Pythonのプログラムが天気を取得したあと、決まったURLに自動で送信する」という用途で使います。

Webhookを使うと、以下のようなことが実現できます：
* Webサービス同士の簡単な連携（通知・チャット送信など）
* DiscordやSlackなど、外部サービスに自動でメッセージ送信
* サーバー不要・リアルタイムな連携が可能

Webhookは「通知先の受信窓口（URL）」を発行し、そのURLに向けてHTTPリクエストを送るだけで機能するため、初心者でも取り組みやすい自動化手段です。

---


### ▶ 定期実行の仕組みの検討

| 候補                       | 特徴                 | 課題                    |
| ------------------------ | ------------------ | --------------------- |
| AWS Lambda + EventBridge | 無料枠あり・インフラレスでサーバ不要 | ZIPパッケージ作成など初期構築は少し複雑 |
| cron + Python on EC2     | 柔軟に処理可能            | 常時稼働インスタンスが必要でコスト増    |
| GitHub Actions + curl    | GitHub上で完結         | 連携先への通知などに制限あり        |

→ **無料・スケーラブルで定期的なトリガーを柔軟に設定できる** Lambda + EventBridge を採用しました。

※他のクラウドでも同様のサービスがあったり、タイムスケジューラー等でも代替可能です。

---

## 実装手順

Pythonコードの作成から、AWS Lambdaへの登録、EventBridgeによる定期実行の設定、Discord Webhookの取得まで、ひとつずつ解説します。

以下の手順に沿って進めることで、毎日自動で天気を取得し、Discordへ通知する仕組みを構築することができます。

### ▶ Discord Webhook の作成手順

この手順では、通知を送信するための Discord Webhook を設定します。以下のように操作してください：

#### ❶ Discordアプリで任意のサーバーを開く

* 通知を送りたいサーバーを選択する
新規作成する場合は、画面左にある⊕ボタン（サーバーを追加）をクリックして新規作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/47c12930-4ee6-4f4f-9e14-8ede351d463e.png)

#### ❷ 通知を送りたいテキストチャンネルを選択

* 左側のチャンネル一覧から、通知を表示させたいチャンネル名を右クリック
* 「チャンネルを編集（⚙ アイコン）」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/49976098-9dcf-40ca-bb03-f5dc57019176.png)

#### ❸ 「連携サービス」または「Integrations」を選択

* 左メニューにある「連携サービス」または英語UIでは「Integrations」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/a5f6b162-ba39-4a76-90ee-8133a99ea85d.png)

#### ❹ 「Webhook」設定画面で「新しいWebhookを作成」

* 「Webhook」セクションに移動し、「Webhookを作成」または「新しいWebhook」をクリック
* Webhookの名前をわかりやすく設定（例：天気通知用）
* チャンネルが通知先チャンネルになっていることを確認（必要に応じて変更）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/7ebacea1-f41b-4ece-a000-68a7658d500d.png)


#### ❺ Webhook URLをコピー

* 「Webhook URL」の右にある「コピー」ボタンをクリック
* URLをメモ帳などに一時保存しておく（Lambda関数に設定するため）

> ⚠ Webhook URLは外部に漏れると第三者に勝手に投稿される恐れがあるため、厳重に取り扱ってください。

### ▶ Step 1: Python コードの作成

以下は、気象庁の天気APIから当日の天気・降水確率・概況を取得し、DiscordのWebhookへ投稿するコードになります。今回は、コメントで内容がわかるようにしました。

**なお、今回は神奈川県を例にしていますが、確認したい対象により変更が必要になります。
overview_url = 'https://www.jma.go.jp/bosai/forecast/data/overview_forecast/140000.json'
detail_url = 'https://www.jma.go.jp/bosai/forecast/data/forecast/140000.json'**

**webhook_url = "あなたのDiscord Webhook URLをここに貼ってください"
に自身のDiscord Webhook URLを転記してください。**

```python
# 必要なモジュールをインポート
# requests: HTTPリクエストを送るためのライブラリ
# datetime: 現在の日付を取得する標準ライブラリ
import requests
from datetime import datetime

# 気象庁のAPIから天気情報を取得してDiscord向けに整形する関数
def fetch_weather():
    try:
        # 概況情報と詳細天気情報のAPIエンドポイント（神奈川県を例に）
        overview_url = 'https://www.jma.go.jp/bosai/forecast/data/overview_forecast/140000.json'
        detail_url = 'https://www.jma.go.jp/bosai/forecast/data/forecast/140000.json'

        # JSONデータを取得
        overview = requests.get(overview_url).json()
        detail = requests.get(detail_url).json()

        # 地域名（例: 東部）を取得
        area_name = detail[0]['timeSeries'][0]['areas'][0]['area']['name']
        # 今日の日付を YYYY-MM-DD の形式で取得
        date_str = datetime.now().strftime('%Y-%m-%d')
        # 今日の天気（例: 晴れ時々曇り）を取得
        weather_today = detail[0]['timeSeries'][0]['areas'][0]['weathers'][0]

        # 降水確率を取得し、時間帯ごとに表示用の文字列に整形
        pops_series = detail[0]['timeSeries'][1]
        pop_times = pops_series['timeDefines']
        pops = pops_series['areas'][0]['pops']
        pop_text = "☔ 降水確率：\n"
        for time, pop in zip(pop_times, pops):
            hour_str = time[11:16]  # 例: '06:00'
            pop_value = pop if pop else "---"
            pop_text += f"・{hour_str} 時 ～ : {pop_value}%\n"

        # 概況テキスト（文章による天気の説明）を取得
        overview_text = overview["text"]

        # 通知メッセージ全体を組み立てる
        message = (
            f"📅 {date_str} の天気情報（{area_name}）\n"
            f"🌤 今日の天気: {weather_today}\n"
            f"{pop_text.strip()}\n"
            f"📝 概況:\n{overview_text}"
        )
        return message

    except Exception as e:
        # 例外が発生した場合はエラーメッセージを返す
        return f"[エラー] 天気情報の取得に失敗しました: {str(e)}"

# DiscordのWebhookにPOSTしてメッセージを通知する関数
def send_to_discord(message, webhook_url):
    try:
        data = {"content": message}
        response = requests.post(webhook_url, json=data)
        if response.status_code != 204:
            raise Exception(f"Discord通知失敗: {response.status_code}")
    except Exception as e:
        print(f"[エラー] Discord送信に失敗: {str(e)}")

# AWS Lambdaのエントリーポイント関数
def lambda_handler(event, context):
    webhook_url = "あなたのDiscord Webhook URLをここに貼ってください"
    weather_message = fetch_weather()
    send_to_discord(weather_message, webhook_url)
    return {
        'statusCode': 200,
        'body': '天気通知完了'
    }
```

### ▶ Step 2: requests ライブラリを同じフォルダに加える

AWS Lambdaには外部ライブラリ（requests）が含まれていないため、自分で同梱する必要があります。
まずは、どこでも構いませんのでフォルダを定義します。（例：weather_lambda）
以下のコマンドを、lambda\_function.py を保存した上記フォルダで実行します。

```powershell
pip install requests -t .
```

これにより、requestsフォルダなどが現フォルダに展開されます。

### ▶ Step 3: すべてを ZIP 化

ここでは、requestsライブラリとPythonスクリプトを1つのZIPファイルにまとめます。OSによってZIP化の方法が異なるため、以下に分けて説明します。

#### ✅ Windows PowerShell の場合

1. `weather_lambda` フォルダを右クリックし「ターミナルで開く」または「PowerShellをここで開く」を選択
2. 次のコマンドを実行：

```powershell
Compress-Archive -Path * -DestinationPath ../weather_lambda.zip
```

> 上記で、現在のフォルダの中身（lambda\_function.pyとライブラリ）がすべて1つのZIPファイルにまとまり、1つ上の階層に `weather_lambda.zip` として出力されます。

#### ✅ Mac/Linux の場合（ターミナル）

1. `cd` コマンドで `weather_lambda` フォルダに移動
2. 次のコマンドを実行：

```bash
zip -r ../weather_lambda.zip .
```

> 注意：`weather_lambda.zip` には `lambda_function.py` や `requests/` がルートに入っている必要があります。中に `weather_lambda/` フォルダごと含まれてしまうと Lambda では動きません。

展開されたrequestsフォルダとlambda\_function.py を一緒に ZIP 形式に圧縮します。

```powershell
Compress-Archive -Path * -DestinationPath ../weather_lambda.zip
```

※ LambdaにアップロードするZIPには、フォルダごとではなく中身（.pyとライブラリ）だけが含まれる必要があります。

### ▶ Step 4: AWS Lambda にアップロード

ここからは AWS 管理コンソールを使用して Lambda 関数を作成し、先ほど作成した ZIP ファイルをアップロードします。

#### ❶ AWS Lambda サービスを開く

* AWS 管理コンソール（[https://console.aws.amazon.com/lambda/）にログイン](https://console.aws.amazon.com/lambda/）にログイン)
* 左側の「関数」メニューをクリック
* 「関数の作成」ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/5692141c-8db4-4e6b-8755-f80d7e61ffba.png)

#### ❷ 関数の基本情報を入力

* 関数名：`WeatherDiscordNotifier`
* ランタイム：`Python 3.12`
* 実行ロール：`新しいロールを作成` を選択 → 「基本的な Lambda 権限」を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/65593fc7-48a2-42fd-885c-aab55dff7ea2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/b33268af-489a-4095-b16c-5249abeffbe8.png)

#### ❸ 関数を作成し ZIP ファイルをアップロード

* 関数が作成されたら、関数ページ内の「コードソース」セクションへ移動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/72e0a987-4a70-4e39-b5fa-ea02c65b0466.png)

* 「アップロード元」→「.zip ファイルをアップロード」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/1431332d-d2c8-42b2-b9fd-694dc7a6b406.png)
* 「ファイルをアップロード」ボタンから `weather_lambda.zip` を選択
* 「保存」ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/f949a08b-39ef-4b1b-9ed6-b87dae416ee1.png)

以上で ZIP ファイルが反映され、Lambda 関数としてコードが登録されます。

### ▶ Step 5: AWS Lambda を手動実行して通知確認

Lambda関数が正常に動作するかを確認するため、手動でテスト実行を行います。通知がDiscordに届けば成功です。

#### ❶ AWS Lambda管理画面の上部「テスト」ボタンをクリック

* 関数ページ右上にある「テスト」ボタンを押す

#### ❷ 「新しいテストイベントを作成」を選択

* テストイベント名：例）`test-weather`
* イベントテンプレート：空白のまま `{}（中括弧のみ）`
* 「作成」ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/b26ad9b2-a9c1-4d43-b07c-f74df8e8e35d.png)

#### ❸ 作成したテストイベントを実行

* もう一度「テスト」ボタンをクリック
* 成功すると「実行結果: 成功」と表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/0be31f86-2e75-4277-b067-73429f3668d7.png)

#### ❹ Discordを確認

* 通知先チャンネルに、天気情報が投稿されていればOKです

> 通知が来ない場合は、Webhook URLが正しいか、AWS Lambdaログ（AWS CloudWatch Logs）にエラーが出ていないかを確認してください。

Lambda管理画面から「テスト」タブで新規イベントを作成し、次のように設定します：

* イベント名: `test-weather`
* イベントJSON: `{}`
* 実行 → Discord通知が届けば成功

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/579991f5-a2b4-4da3-b60e-0bce955b66c3.png)

### ▶ Step 6: Amazon EventBridge を使って定期実行を設定

毎日自動で天気を通知するには、Amazon EventBridgeを使ってAWS Lambdaを定期的に呼び出すよう設定します。

#### ❶ AWSコンソールで Amazon EventBridge を開く

* サービス検索で「Amazon EventBridge」と入力し、サービスを選択

#### ❷ 左メニュー「ルール」→「ルールの作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/b2a5c432-3373-481e-89f8-9edd31491d59.png)

#### ❸ 以下の情報を入力し、EventBridge Builderで実行をクリック

* 名前：例）`weather-every-morning`
* 説明：毎日7時に天気通知
* ルールタイプ：スケジュール

#### ❹ スケジュールパターンを設定

* 頻度：定期的なスケジュール
* タイムゾーン：(UTC+09:00)Asia/Tokyo
* スケジュールの種類：`cronベースのスケジュール`
* cron式：`cron(0 7 * * ? *)`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/45bb29d8-6bf9-44d5-a5ea-5d17f2b9e814.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/c9950bbe-4253-413e-92f5-c60195987fdc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/7f6a41dc-d613-4ca0-8f8a-5999f3b34d76.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/798020a6-360e-4156-a5c4-c25706e2bcc8.png)

#### ❺ ターゲットを設定

* ターゲットタイプ：AWSサービス
* サービス：Lambda関数
* 関数名：`WeatherDiscordNotifier`
* 関数バージョン：`$LATEST`（デフォルトでOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/65902056-f19d-4a84-901e-395fe36d8808.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/e76cdf47-cdd2-4ada-b2b5-9a2e8c93896f.png)

#### ❻ 「次へ」→「ルールの作成」ボタンをクリックして完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081366/66840f0a-fc03-4970-a7f6-283c80c1d975.png)



# まとめ

今回の記事では、Python を使って気象庁の天気APIから情報を取得し、Discord へ自動通知する仕組みを、AWS Lambda + EventBridge を使って構築する一連の手順を解説しました。

　✅**Webhook を用いた通知連携の考え方と実装**
　✅**外部API（気象庁API）からのJSON取得と整形**
　✅**AWS Lambda によるサーバーレス実行環境の構築**
　✅**EventBridge によるスケジュール実行（cron式設定）**

# 感想

今回初めて記事を投稿しましたが、学習したこと用いてアウトプットしてみることで自身があいまいなに理解していた箇所を再確認できました。また、もっとこうしたい、ああしたいなどの気づきも得られたので継続して学習していきたいですし、自身の役に立つような便利ツールや時短ツールを作成できるようになりたいと感じました。