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?

【Python】定時飛行場実況気象通報式をAPIから取得してみた

Last updated at Posted at 2025-08-18

定時飛行場実況気象通報式(METAR)とは

空港の気象状況について、航空機の離着陸のため自動で行った観測の成果(航空気象観測機器で観測された成果)を自動で通報している電文である。

空港の気象状況を取得するため、AVWX REST APIを用いて、METARを取得した。

プログラム

与論空港(RORY)の例
他の空港の場合はURLの最後を書き換えること

get_metar.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
与論空港(RORY)のMETARデータを取得するプログラム
"""

import json
import sys
from datetime import datetime

def get_cloud_type_japanese(cloud_type):
    """雲の種類を日本語に変換"""
    cloud_types = {
        'FEW': '少量 (1-2/8)',
        'SCT': '散在 (3-4/8)', 
        'BKN': '曇り (5-7/8)',
        'OVC': '曇天 (8/8)',
        'CLR': '快晴',
        'SKC': '快晴',
        'VV': '垂直視程'
    }
    return cloud_types.get(cloud_type, cloud_type)

def format_datetime(dt_string):
    """日時を日本語形式にフォーマット"""
    try:
        dt = datetime.fromisoformat(dt_string.replace('Z', '+00:00'))
        return dt.strftime('%Y年%m月%d日 %H:%M:%S UTC')
    except:
        return dt_string

def get_metar_data():
    """METARデータを取得 (requests が無ければ urllib 利用)"""
    url_base = "https://avwx.rest/api/metar/RORY"
    params = {
        'options': '',
        'airport': 'true',
        'reporting': 'true',
        'format': 'json'
    }
    headers = {
        'Authorization': 'Token [your token]'
    }
    
    try:
        r = requests.get(url_base, params=params, headers=headers, timeout=10)
        r.raise_for_status()
        return r.json()
    except Exception as e:
        print(f"APIリクエストエラー(requests): {e}")
        sys.exit(1)

def display_metar_info(metar_data):
    """METAR情報を表示"""
    print("=== 与論空港(RORY)METAR情報 ===")
    print(f"生METAR: {metar_data.get('raw', 'N/A')}")
    print(f"空港名: {metar_data.get('station', 'N/A')}")
    
    # 観測時刻
    time_info = metar_data.get('time', {})
    if time_info.get('dt'):
        print(f"観測時刻: {format_datetime(time_info['dt'])}")
    
    # 風向・風速
    wind_info = metar_data.get('wind')
    if wind_info:
        wind_dir = wind_info.get('direction', {}).get('value', 'N/A')
        wind_speed = wind_info.get('speed', {}).get('value', 'N/A')
        wind_unit = wind_info.get('speed', {}).get('unit', '')
        print(f"風向: {wind_dir}")
        print(f"風速: {wind_speed} {wind_unit}")
        
        # 突風
        wind_gust = metar_data.get('wind_gust')
        if wind_gust:
            gust_value = wind_gust.get('value', 'N/A')
            gust_unit = wind_gust.get('unit', '')
            print(f"突風: {gust_value} {gust_unit}")
    
    # 視程
    visibility = metar_data.get('visibility')
    if visibility:
        vis_value = visibility.get('value', 'N/A')
        vis_unit = visibility.get('unit', '')
        print(f"視程: {vis_value} {vis_unit}")
    
    # 気温
    temperature = metar_data.get('temperature')
    if temperature:
        temp_value = temperature.get('value', 'N/A')
        print(f"気温: {temp_value}°C")
    
    # 露点
    dewpoint = metar_data.get('dewpoint')
    if dewpoint:
        dew_value = dewpoint.get('value', 'N/A')
        print(f"露点: {dew_value}°C")
    
    # 湿度
    humidity = metar_data.get('relative_humidity')
    if humidity is not None:
        print(f"相対湿度: {humidity:.1%}")
    
    # 気圧
    altimeter = metar_data.get('altimeter')
    if altimeter:
        alt_value = altimeter.get('value', 'N/A')
        alt_unit = altimeter.get('unit', '')
        print(f"気圧: {alt_value} {alt_unit}")
    
    # 雲量情報
    clouds = metar_data.get('clouds', [])
    print("雲量:")
    if not clouds:
        print("  快晴 (雲なし)")
    else:
        for i, cloud in enumerate(clouds, 1):
            cloud_type = cloud.get('type', 'N/A')
            altitude = cloud.get('altitude', 'N/A')
            repr_str = cloud.get('repr', 'N/A')
            
            type_jp = get_cloud_type_japanese(cloud_type)
            print(f"{i}: {type_jp} - 高度 {altitude}00ft ({repr_str})")
    
    # フライトルール
    flight_rules = metar_data.get('flight_rules')
    if flight_rules:
        rules_jp = {
            'VFR': '有視界飛行方式',
            'MVFR': '制限有視界飛行方式', 
            'IFR': '計器飛行方式',
            'LIFR': '低計器飛行方式'
        }.get(flight_rules, flight_rules)
        print(f"フライトルール: {rules_jp} ({flight_rules})")

def main():
    """メイン関数"""
    try:
        print("与論空港のMETARデータを取得中...")
        metar_data = get_metar_data()
        
        display_metar_info(metar_data)
        
        print("\n=== 完全なJSONデータ ===")
        print(json.dumps(metar_data, indent=2, ensure_ascii=False))
        
    except KeyboardInterrupt:
        print("\n処理が中断されました。")
        sys.exit(1)
    except Exception as e:
        print(f"予期しないエラーが発生しました: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()


レスポンス

与論空港の例

response.json
{
  "altimeter": {
    "repr": "Q1014",
    "spoken": "one zero one four",
    "value": 1014
  },
  "clouds": [
    {
      "altitude": 90,
      "modifier": null,
      "repr": "FEW090",
      "type": "FEW"
    },
    {
      "altitude": 130,
      "modifier": null,
      "repr": "SCT130",
      "type": "SCT"
    },
    {
      "altitude": 150,
      "modifier": null,
      "repr": "BKN150",
      "type": "BKN"
    }
  ],
  "density_altitude": 1601,
  "dewpoint": {
    "repr": "25",
    "spoken": "two five",
    "value": 25
  },
  "flight_rules": "VFR",
  "meta": {
    "cache-timestamp": "2025-08-18T06:47:01.843000Z",
    "stations_updated": "2024-12-02",
    "timestamp": "2025-08-18T06:47:12.669593Z"
  },
  "other": [
    "TCU"
  ],
  "pressure_altitude": 29,
  "raw": "RORY 180600Z AUTO 14007KT 9999 FEW090 SCT130 BKN150 //////TCU 28/25 Q1014",
  "relative_humidity": 0.8377219417290783,
  "remarks": "",
  "remarks_info": null,
  "runway_visibility": [],
  "sanitized": "RORY 180600Z 14007KT 9999 FEW090 SCT130 BKN150 TCU 28/25 Q1014",
  "station": "RORY",
  "temperature": {
    "repr": "28",
    "spoken": "two eight",
    "value": 28
  },
  "time": {
    "dt": "2025-08-18T06:00:00Z",
    "repr": "180600Z"
  },
  "units": {
    "accumulation": "in",
    "altimeter": "hPa",
    "altitude": "ft",
    "temperature": "C",
    "visibility": "m",
    "wind_speed": "kt"
  },
  "visibility": {
    "repr": "9999",
    "spoken": "nine nine nine nine",
    "value": 9999
  },
  "wind_direction": {
    "repr": "140",
    "spoken": "one four zero",
    "value": 140
  },
  "wind_gust": null,
  "wind_speed": {
    "repr": "07",
    "spoken": "seven",
    "value": 7
  },
  "wind_variable_direction": [],
  "wx_codes": []
}

参考文献

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?