1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめてのアドベントカレンダーAdvent Calendar 2024

Day 23

Python で OpenWeather API の気象データを取得してみた

Last updated at Posted at 2024-12-22

OpenWeather は様々な気象データの API を提供しており、一部の機能は無料で使用できる。

アプリ開発チュートリアルでもよく見かける定番の API だ。

今回は、データを取得して表示する Python スクリプトと共に紹介してみたい。

以下の流れで進めていく。

  1. OpenWeather にサインアップして API キーを入手する
  2. API を呼び出してデータを取得する
    a. 事前準備
    b. Current weather data
    c. 5 day weather forecast

1. OpenWeather にサインアップして API キーを入手する

まずは、OpenWeather にサインアップする。

  1. サインアップページ にアクセスする
  2. フォームを入力し、Create Account をクリックする
  3. ホーム画面が開かれる(サインアップに使用したメールアドレスに確認メールが届く。メール を開き、Verify your email をクリックする)
    20241221_1_openweather_mypage.png
  4. ホーム画面の API keys をクリックする
  5. Default という名前の API キーを確認する
    20241221_2_oenweather_apikeys.png

今回使用するのは、このデフォルトで用意されている API キーだ。

2. API を呼び出してデータを取得する

事前準備

環境のセットアップ

環境について説明しておく。

Python バージョン 3.13.1 を使用しており、venv で作成した仮想環境内で作業する。

python -m venv .venv
source .venv/bin/activate

API リクエストに requests、結果を整形して表示するために pandas を利用する。

pip install requests pandas

また、先ほど確認した OpenWeather の API キーを環境変数に入れておく

export API_KEY=<your-api-key>


今回用いるスクリプトの流れは次の通りだ。

  1. ユーザー入力として「地名」を受け取る
  2. 地名を緯度経度に変換する
  3. 気象 API を呼び出す
  4. 結果を確認する

ヘルパーモジュールを作成する

気象データの取得に使用するヘルパーモジュールを作成しておく。

Geocoding API

まずは Geocoding API を呼び出す処理だ。これも OpenWeather API の一つだ。

これを使用して、ユーザーから受け取った地名を緯度経度に変換する。後で出てくる気象データ用の API で、どの地点の天気を取得するかを指定するために使用する。

Built-in geo-coding を使用する方が簡単だが廃止されているため、今回は正規の方法を採用した。


Geocoding API を用いて関数のコードスニペットを以下に示す。

def get_coordinates_by_city_name(city_name):
    """Converting a city name to geographical coordinates."""
    url = f"{BASE_URL}/{GEO_URL}?q={city_name}&appid={API_KEY}&limit=1"
    response = requests.get(url, timeout=1)
    data = response.json()

    if response.status_code != 200 or not data:
        raise Exception(f"City not found: {data if not data else data["message"]}")
    else:
        return data[0]["lat"], data[0]["lon"]

日付フォーマット

後で表示用に使うので。以下のような感じ。

def format_datetime(dt_value, format_string):
    """Convert a UNIX timestamp to a formatted date-time string."""
    return datetime.fromtimestamp(
        dt_value, tz=ZoneInfo("Asia/Tokyo")
    ).strftime(format_string)


上記をヘルパーにまとめたコード。

open_weather_helper.py
"""OpenWeather API helper"""

import os
from datetime import datetime
from zoneinfo import ZoneInfo
import requests

API_KEY = os.environ.get("API_KEY")
BASE_URL = "http://api.openweathermap.org"
GEO_URL = "/geo/1.0/direct"


def get_coordinates_by_city_name(city_name):
    """Converting a city name to geographical coordinates."""
    url = f"{BASE_URL}/{GEO_URL}?q={city_name}&appid={API_KEY}&limit=1"
    response = requests.get(url, timeout=1)
    data = response.json()

    if response.status_code != 200 or not data:
        raise Exception(f"City not found: {data if not data else data["message"]}")
    else:
        return data[0]["lat"], data[0]["lon"]


def format_datetime(dt_value, format_string):
    """Convert a UNIX timestamp to a formatted date-time string."""
    return datetime.fromtimestamp(
        dt_value, tz=ZoneInfo("Asia/Tokyo")
    ).strftime(format_string)


if __name__ == "__main__":
    city_name_input = input("Enter city name: ")

    lat, lon = get_coordinates_by_city_name(city_name_input)

    print(f"\n(Latitude, Longitude) = ({lat}, {lon})")

実行してみる。

python geo_coding_sample.py
Enter city name: tokyo

(Latitude, Longitude) = (35.6828387, 139.7594549)

準備が終わったところで、OpenWeather API を呼び出してみる。


Current weather data

Current weather data を使用すると、現在の天気や気温を取得できる。

ここでは、以下のコードで

  • 天気
  • 気温
  • 湿度

を表示してみた。

fetch_current_weather_by_city.py
"""Featch current weather by city."""

import requests
from pandas import DataFrame
from open_weather_helper import (
    API_KEY,
    BASE_URL,
    get_coordinates_by_city_name,
    format_datetime,
)

WEATHER_URL = "/data/2.5/weather"


if __name__ == "__main__":
    city_name = input("Enter city name: ")

    lat, lon = get_coordinates_by_city_name(city_name)

    url = f"{BASE_URL}/{WEATHER_URL}?lat={lat}&lon={lon}&appid={API_KEY}&units=metric"

    response = requests.get(url, timeout=1)
    data = response.json()

    if response.status_code == 200:
        print("\n==============================================")
        print(f"Current weather data in {city_name}")
        print("==============================================", end="\n\n")

        display_data = [
            ["Date/Time (JST)", format_datetime(data["dt"], "%Y-%m-%d %H:%M")],
            ["Weather", data['weather'][0]['description']],
            ["Temperature", f"{data['main']['temp']}°C"],
            ["Humidity", f"{data['main']['humidity']}%"],
        ]

        print(
            DataFrame(display_data).to_string(index=False, header=False)
        )
    else:
        print(f"City not found: {data['message']}")

実行結果

python fetch_current_weather_by_city.py
Enter city name: tokyo

==============================================
Current weather data in tokyo
==============================================

Date/Time (JST) 2024-12-21 23:17
        Weather        clear sky
    Temperature          10.46°C
       Humidity              65%


5 day weather forecast

5 day weather forecast を使うと、直近5日間の3時間ごとの天気を取得できる。

データをいくつ取得するかは cnt パラメータで指定できる。今回は24時間分取得する(cnt=9)。

fetch_forecast_by_city.py
"""Featch current weather by city."""

import requests
from pandas import DataFrame
from open_weather_helper import (
    API_KEY,
    BASE_URL,
    get_coordinates_by_city_name,
    format_datetime,
)

FORECAST_URL = "/data/2.5/forecast"


if __name__ == "__main__":
    city_name = input("Enter city name: ")

    lat, lon = get_coordinates_by_city_name(city_name)

    endpoint = f"{BASE_URL}/{FORECAST_URL}"
    url = f"{endpoint}?lat={lat}&lon={lon}&appid={API_KEY}&units=metric&cnt=9"

    response = requests.get(url, timeout=1)
    data = response.json()

    if response.status_code == 200:
        print("\n==============================================")
        print(f"24 hours forecast in {city_name}")
        print("==============================================", end="\n\n")

        display_data = []
        for e in data["list"]:
            display_data.append([
                format_datetime(e["dt"], "%Y-%m-%d %H:%M"),
                e['weather'][0]['description'],
                f"{e['main']['temp']}°C",
                f"{e['main']['humidity']}%",
                f"{e['pop'] * 100}%"
            ])

        print(
            DataFrame(
                display_data,
                columns=[
                    "Date/Time (JST)",
                    "Weather",
                    "Temperature",
                    "Humidity",
                    "Precipitation"
                ]
            ).to_string(index=False)
        )
    else:
        print(f"City not found: {data['message']}")

実行結果

python fetch_forecast_by_city.py
Enter city name: tokyo

==============================================
24 hours forecast in tokyo
==============================================

 Date/Time (JST)    Weather Temperature Humidity Precipitation
2024-12-22 00:00  clear sky     10.24°C      69%            0%
2024-12-22 03:00  clear sky     10.01°C      59%            0%
2024-12-22 06:00  clear sky       8.8°C      49%            0%
2024-12-22 09:00  clear sky      8.43°C      35%            0%
2024-12-22 12:00  clear sky      9.17°C      29%            0%
2024-12-22 15:00 few clouds      9.11°C      21%            0%
2024-12-22 18:00  clear sky      6.41°C      28%            0%
2024-12-22 21:00  clear sky      5.49°C      31%            0%
2024-12-23 00:00  clear sky      5.03°C      32%            0%

以上だ

今回使用したもの以外にも、次のようなデータが取れる。

  • 風向・風速
  • 視程
  • 日の出時刻
  • 日の入り時刻

一度じっくり見てみるのも良いかもしれない。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?