猿でもわかるAIプログラミングシリーズ 🐵💻  Pythonでお天気Botを作ってみよう（API活用入門）

## 1. はじめに：なぜ天気予報Botを作るのか？

**こんな悩みありませんか？**
- 朝の支度中に急に雨が降ってきて慌てた
- 出張先の天気を調べるのが面倒
- API連携の実践的な使い方を学びたい

本記事では、OpenWeatherMap APIとLINE通知を組み合わせ、毎朝指定した時間に天気予報を教えてくれるBotを作成します。実際の業務でも応用できる「外部API連携」「定期実行」「通知システム」の3つの要素を一度に学べる実践的な内容です。

## 2. 使用技術の概要

### 2.1 OpenWeatherMap API
無料で利用できる気象データAPIで、現在の天気や5日先までの予報、過去データなど豊富な情報を取得できます。

**無料プランの主な仕様**
- 1時間あたり60回までのAPIコール
- 現在の天気、5日間/3時間ごとの予報
- 200,000以上の都市に対応

### 2.2 LINE Notify
LINEが提供する通知APIで、個人アカウントやグループにメッセージを送信できます。Botを作成するのに特別な審査は不要です。

## 3. 実装手順（コード付き解説）

### 3.1 環境準備
まずは必要なライブラリをインストールします。

```bash
pip install requests python-dotenv schedule
```

### 3.2 APIキーの取得

#### OpenWeatherMap
1. [OpenWeatherMap](https://openweathermap.org/)にアクセス
2. アカウント登録後、[API Keys](https://home.openweathermap.org/api_keys)からキーを取得

#### LINE Notify
1. [LINE Notify](https://notify-bot.line.me/ja/)にログイン
2. [マイページ→トークンを発行する]からトークンを取得

`.env`ファイルにキーを保存：

```plaintext
OPENWEATHER_API_KEY=your_api_key_here
LINE_NOTIFY_TOKEN=your_line_token_here
CITY=Tokyo,JP
```

### 3.3 天気情報取得関数の実装

```python
import os
import requests
from dotenv import load_dotenv

load_dotenv()

def get_weather_forecast():
    api_key = os.getenv("OPENWEATHER_API_KEY")
    city = os.getenv("CITY")
    
    base_url = "http://api.openweathermap.org/data/2.5/weather"
    params = {
        'q': city,
        'appid': api_key,
        'units': 'metric',
        'lang': 'ja'
    }
    
    response = requests.get(base_url, params=params)
    data = response.json()
    
    if response.status_code == 200:
        weather = data['weather'][0]['description']
        temp = data['main']['temp']
        humidity = data['main']['humidity']
        
        return f"【{city}の天気】\n状態: {weather}\n気温: {temp}℃\n湿度: {humidity}%"
    else:
        return f"天気情報の取得に失敗しました: {data['message']}"
```

### 3.4 LINE通知関数の実装

```python
def send_line_notification(message):
    line_token = os.getenv("LINE_NOTIFY_TOKEN")
    headers = {
        'Authorization': f'Bearer {line_token}'
    }
    payload = {
        'message': message
    }
    
    response = requests.post(
        'https://notify-api.line.me/api/notify',
        headers=headers,
        data=payload
    )
    
    return response.status_code == 200
```

### 3.5 定期実行の設定

```python
import schedule
import time

def job():
    weather_info = get_weather_forecast()
    success = send_line_notification(weather_info)
    
    if success:
        print("通知を送信しました")
    else:
        print("通知送信に失敗しました")

# 毎朝7時に実行
schedule.every().day.at("07:00").do(job)

while True:
    schedule.run_pending()
    time.sleep(60)
```

## 4. 実践的なTipsとよくある落とし穴

### 4.1 エラーハンドリングの強化
実際の運用では、以下のようなエラーハンドリングが重要です。

```python
def get_weather_forecast():
    try:
        # ...（前略）...
        response = requests.get(base_url, params=params, timeout=5)
        response.raise_for_status()  # HTTPエラーを例外として発生させる
        
        data = response.json()
        
        # 必要なフィールドの存在確認
        if not all(key in data for key in ['weather', 'main']):
            raise ValueError("APIレスポンスの形式が不正です")
            
    except requests.exceptions.RequestException as e:
        return f"APIリクエストエラー: {str(e)}"
    except ValueError as e:
        return f"データ解析エラー: {str(e)}"
```

### 4.2 ログ記録の実装
長期運用する場合は、ログをファイルに記録しましょう。

```python
import logging

logging.basicConfig(
    filename='weather_bot.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

def job():
    try:
        weather_info = get_weather_forecast()
        success = send_line_notification(weather_info)
        
        if success:
            logging.info("通知を送信しました")
        else:
            logging.error("通知送信に失敗しました")
    except Exception as e:
        logging.error(f"予期せぬエラー: {str(e)}")
```

### 4.3 よくある問題と解決策
- **API制限に達した**：無料プランでは1時間60回まで。`time.sleep()`で間隔を空ける
- **都市名が認識されない**：`city`パラメータを「都市名,国コード」（例: "Osaka,JP"）形式で指定
- **LINE通知が届かない**：トークンの有効期限（発行から10年）を確認

## 5. 応用編：さらに便利に拡張するアイデア

### 5.1 降水確率を含む予報
5日間予報APIを使用して、より詳細な情報を取得できます。

```python
def get_detailed_forecast():
    api_key = os.getenv("OPENWEATHER_API_KEY")
    city = os.getenv("CITY")
    
    url = "http://api.openweathermap.org/data/2.5/forecast"
    params = {
        'q': city,
        'appid': api_key,
        'units': 'metric',
        'lang': 'ja',
        'cnt': 4  # 次の12時間分（3時間ごと×4回）
    }
    
    response = requests.get(url, params=params)
    data = response.json()
    
    forecast = []
    for item in data['list']:
        time = item['dt_txt']
        weather = item['weather'][0]['description']
        temp = item['main']['temp']
        pop = item.get('pop', 0) * 100  # 降水確率（0~1 → %）
        
        forecast.append(f"{time}: {weather}, {temp}℃, 降水確率{pop:.0f}%")
    
    return "\n".join(forecast)
```

### 5.2 複数都市のモニタリング
環境変数を配列で管理し、複数都市の天気をチェック。

```python
# .env
CITIES=Tokyo,JP;Osaka,JP;Sapporo,JP
```

```python
cities = os.getenv("CITIES").split(';')

for city in cities:
    weather_info = get_weather_forecast(city)
    send_line_notification(weather_info)
```

### 5.3 クラウドでの定期実行（AWS Lambda例）
ローカルPCで常時実行する代わりに、AWS Lambdaでサーバーレスに実行。

```python
import json

def lambda_handler(event, context):
    weather_info = get_weather_forecast()
    success = send_line_notification(weather_info)
    
    return {
        'statusCode': 200 if success else 500,
        'body': json.dumps('Notification sent' if success else 'Failed to send')
    }
```

## 6. まとめ：天気Botのメリット・デメリットと今後

### ✅ メリット
- **実用的**：日常生活で実際に使える
- **学習効果が高い**：API連携、定期実行、通知の基本を網羅
- **拡張性が高い**：他のサービスと連携可能

### ❌ デメリット
- 無料APIには制限がある
- 天気情報の精度は提供元に依存

### 今後の発展可能性
- 機械学習で降水確率を予測
- 過去データの分析で傾向を可視化
- 他のサービス（Googleカレンダーなど）と連携

## おわりに

今回はPythonを使った天気予報Botの作成方法を解説しました。API連携は現代のプログラミングにおいて必須スキルの1つです。このプロジェクトを通じて、外部サービスと連携するアプリケーション開発の基礎をマスターしてください。

「動くもの」を作る楽しさを感じながら、ぜひ自分なりのカスタマイズを加えてみてください。例えば、アイコンを変えたり、メッセージの文体をアレンジするだけでも、オリジナリティが出ますよ！

質問や改善提案があれば、コメント欄でお気軽にどうぞ。Happy Coding! 🚀

---