指定した緯度、経度での天候のデータを取得する Python のスクリプトについてまとめておきます。
以下の2つの環境のそれぞれで動作確認をしています。
環境1:Raspberry Pi 5 (bookworm)
環境2:Windows パソコン
背景
以前に、気象庁のサイトにアクセスし、天気予報等をダウンロードする Python のプログラムをまとめています。
しかしながら、一般的な天気予報では、予報エリアが関東など広すぎることが多く、局所的な大雨などでは当たらないことがよくあります。加えて、降雨量、温度、湿度などの数値の詳細は得られないといったことがけっこうあります。現在の天候データと予報のデータの双方が得られないこともよくあります。
ネットで調べると、open-meteo.com というサイトでは、緯度、経度をピンポイントで指定して、天候のデータを取得することができます。
ということで、緯度、経度を指定して、データを取得する Python のスクリプトを作成し、公開しておくことにします。具体的には、現在の降雨量、温度、湿度、日照量、風速などのデータ、また、1時間ごとの予報データを取得してみることにします。
加えて、サーバーとデータをやり取りするときは、JSON ファイルを扱うことが標準的となっています。そこで、JSON ファイルについて、サーバーからの取得方法や保存、読み出し、また、データへのアクセス方法などについてもまとめておくことにします。
考え方のまとめ
・ 緯度、経度をピンポイントで指定すると、現在時点での降雨量、温度、湿度、日照量、風速などが取得できるようにします。
・ 加えて、現在時刻以降の天候も取得できるようにします。
・ ちょうどよい事例となりますので、インターネット上のサーバーと情報のやり取りを行うプログラムを整理しておくことにします。
具体的には、サーバーにクエリーを送り、JSON ファイルを取得し、ローカルに保存します。加えて、保存した JSON ファイルを読み出して、任意の項目を取得して表示します。
・ ネットからファイルを取得して、温度、湿度などが取得できれば、あとは自由にカスタマイズができることになります。すでにこのサイトでは音声でお知らせするスクリプトなどを公開しています。任意に組み合わせて応用できることになります。
・ open-meteo.com では、とくにユーザー登録等を必要とせずにデータを取得することができるため、このサイトを使うことにします。
このサイトの URL に必要な気象データのクエリーを付けてアクセスすると、JSON ファイル形式のデータを返す仕様になっています。
・ なお、open-meteo.com という外部のサーバーを使っていますので、サーバーに負荷がかからないよう配慮をお願いいたします。
設定方法
パソコンでの設定
① 以下を参考に、パソコンにフォルダを作り、weather1.py という名前でファイルを作ります。
例:
c:\user\weather_checker1\get_weather1.py
c:\user\weather_checker1\read_weather1.py
② ①のフォルダ内にさらに、weather1 という名前でフォルダを作ります。
ネットから取得したファイルを保存するためのフォルダです。
③ プロンプト(または、Anaconda Prompt)を起動し、①の1つめのスクリプトを実行します。
例: python c:\user\weather_checker1\get_weather1.py
→ 実行すると、ネットにアクセスして天候のデータを取得し、②のフォルダにファイル YYMMDD_HH_weather1.json といったファイル名で JSON ファイルを保存します。
YYMMDD_HH は、アクセスした年月日と時間です。
④ ①の2つめのスクリプトを実行します。
例: python c:\user\weather_checker1\read_weather1.py
→ 実行すると、ローカルに保存した JSON ファイル(③)を読みだして、プロンプトに表示します。
→ 天気の情報が表示されたら成功です。
※ 各要素の読み取りはできていますので、任意にカスタマイズすることで自由に機能を追加することが可能です。
※ なお、サーバーへの重複したアクセスを避けるため、③で、ファイルが取得されていないときのみネットへアクセスするようにしています。具体的には、open-meteo.com の仕様上、天気の情報は1時間程度おきに1度程度更新されるようです。そこで、年月日と時間が同一となるファイルがすでに存在しているときは、サーバーへのアクセスはしないようにしています。
※ また、④のスクリプトは、実行した日に対応するファイルの中で最新のファイルを読みだして、天候の情報を取得するようにしています。
Raspberry Pi での設定
・ 上記のファイルを Raspberry Pi に移しても同様に動くことを確認しています。
Python のスクリプトと同じ場所にフォルダ weather1 を作成しておくようにしてください。
天候データの例
上記の2つのスクリプトを実行したときの表示例を以下に挙げておきます。
260730_07_weather1.json
2026-07-30
07:00 0.0mm 26.8degC 83% 1000.3hPa 6.4% 0.4m/s 326 NW 1
00:00 0.0mm 27.1degC 83% 998.7hPa 0.0% 0.3m/s 180 S 1
01:00 0.0mm 26.7degC 86% 998.6hPa 0.0% 0.6m/s 121 ESE 1
02:00 0.0mm 26.4degC 87% 998.7hPa 0.0% 0.8m/s 220 SW 1
03:00 0.0mm 26.2degC 86% 999.0hPa 0.0% 0.8m/s 284 WNW 1
04:00 0.0mm 26.1degC 86% 999.2hPa 0.0% 0.9m/s 311 NW 1
05:00 0.0mm 25.8degC 87% 999.6hPa 0.0% 0.9m/s 315 NW 1
06:00 0.0mm 25.9degC 86% 1000.0hPa 0.0% 0.4m/s 304 NW 1
07:00 0.0mm 26.8degC 83% 1000.3hPa 0.9% 0.4m/s 326 NW 1
08:00 0.0mm 28.3degC 78% 1000.6hPa 78.3% 0.4m/s 34 NE 1
09:00 0.0mm 30.0degC 72% 1000.7hPa 100.0% 0.7m/s 45 NE 1
10:00 0.0mm 31.5degC 67% 1000.6hPa 100.0% 0.8m/s 67 ENE 1
11:00 0.0mm 32.8degC 65% 1000.3hPa 100.0% 0.9m/s 96 E 0
12:00 0.0mm 33.3degC 64% 1000.1hPa 100.0% 1.3m/s 108 ESE 1
13:00 0.0mm 33.4degC 64% 1000.0hPa 100.0% 1.6m/s 125 SE 1
14:00 0.0mm 33.7degC 60% 999.9hPa 100.0% 1.6m/s 135 SE 1
15:00 0.0mm 32.9degC 65% 1000.2hPa 100.0% 2.0m/s 101 E 1
16:00 0.3mm 30.5degC 78% 1001.0hPa 85.6% 2.4m/s 78 ENE 51
17:00 0.0mm 29.1degC 77% 1001.6hPa 48.0% 2.2m/s 72 ENE 2
18:00 0.0mm 27.5degC 80% 1002.4hPa 0.0% 2.0m/s 70 ENE 2
19:00 0.1mm 25.8degC 86% 1003.5hPa 0.0% 1.9m/s 62 ENE 51
20:00 0.5mm 24.7degC 91% 1004.5hPa 0.0% 1.6m/s 55 NE 53
21:00 0.4mm 24.3degC 93% 1005.2hPa 0.0% 1.4m/s 34 NE 51
22:00 0.9mm 24.0degC 94% 1005.7hPa 0.0% 1.3m/s 27 NNE 53
23:00 0.2mm 23.8degC 95% 1005.9hPa 0.0% 1.2m/s 14 NNE 51
・ 1行目は 、JSON ファイルのファイル名です。weather1 フォルダ内から読み出したファイルのファイル名です。
・ 2行目は、天候データの取得日です。サーバーから返ってくるデータに日時が入っているため、日付部分を読みだしています。
・ 3行目は、サーバーにアクセスした現時点(current)での天候データです。
上記の例では、朝の7 時台にサーバーにアクセスしたので、冒頭の時刻が 7:00 になっています。
・ 4行目以降は、サーバーから得られた予報データ(hourly)です。当日の 00:00 から 23:00 までを表示させています。これ以降のデータも表示可能です。
・ 天候データは、以下の順としています。
時刻、降雨量 mm、温度 degC、相対湿度 %、気圧 hPa、日照量 %、風速 m/s、風向き1(0-360deg)、風向き2(方位)、天気コード
この表示は、Python のスクリプト内で決めています。スクリプトを修正することで任意のカスタマイズが可能です。
・ 上記のサンプルの例では、天候データを朝7:00時台に取得しています。16:00 以降に(降雨量)> 0 mm となっていることから、夕方ににわか雨・雷雨となる予報となっていることがわかります。
昼間で(日照量)≒ 100% となっているものの、(温度) > 30度、(相対湿度) > 60% と高めであり、(風速) < 2.5 m/s と低めであることから、高湿度の空気が長時間溜まり上昇気流が生じ、にわか雨や雷雨となりやすい条件となっています。この日は実際に 16:00 以降に雨が降ってくることを確認しています。
天気予報では、一般に予報エリアが広く、広範に長時間続く雨や台風のマクロ的な予報は当たりやすいです。しかし一方、局所的な入道雲の発生、雷雨、にわか雨、線状降水帯の予報は難しく、外すことも多いとのことです。必要により、温湿度などの条件から急な雨が降る可能性を各地点ごとに判断していったほうがよさそうです。
うまく動いたら
うまく動いたら、スクリプトをカスタマイズして活用してみてください。
get_weather1.py のスクリプト内で、サンプルとして東京での緯度、経度を記載しています。
天候を取得したいエリアの緯度、経度に修正して実行してみてください。
なお、サーバーへの過剰なアクセスを避けるため、天候のデータ(同一時刻でのファイル)が取得されていないときのみサーバーにアクセスするようにしています。テストで複数回アクセスするときは、weatehr1 フォルダ内のファイルを削除してからスクリプトを実行してください。
関連リンクに音声を鳴らす Python のスクリプトの例を挙げておきます。
たとえば、データの取得時に(降雨量) > 0 であれば、「現在、雨が降っています」といった音声を鳴らすことも可能です。
予報データの部分をカスタマイズすることで雨が降る予報であれば何時頃降る予報となっているのか、雨が止むのであれば何時頃やむ予報となっているか、音声通知することも可能です。
以前に、温度、相対湿度、風速、日照量が与えられたとき、洗濯物が乾燥する時間を予測する機械学習を試みました。係数はわかっていますので、今回のスクリプトと組み合わせることで、洗濯物が乾燥する時間などを予測することなども可能です。
スクリプトの説明
get_weather1.py
・ サーバーにアクセスするため、requests をインポートしています。また、JSON ファイルを扱うため、json をインポートしています。datetime は、取得した年月日(+時間)をファイル名として使用したいため、読み込んでいます。
・ read1_json() と write1_json() は、JSON ファイルをハードディスクに読み書きするための関数です。
・ str1_url() は、緯度、経度を指定して、サーバーの URL とクエリーを生成するための関数です。
lat1 = …、lon1 = … とした行で、緯度、経度を指定しています。
東京の緯度、経度の例としていますので、東京以外での天候データを取得したい場合は、この部分を書き換えてください。緯度、経度の数値データは、たとえば、Google Map などのサイト上で任意の地点を右クリックすると取得することが可能です。
文字列 url1 が、URL + クエリーとなっています。上記の緯度、経度の数値を差し込み、文字列を作っています。
クエリーの部分では、URL と緯度、経度を指定します。つぎに、現在(current)の天候データとして、降雨量、温度、相対湿度、気圧、風速、風の向き、日照量、天気コードを指定しています。
つぎに、1時間ごとの予報データ(hourly)も取得できるようになっているので、予報データとしての上記の降雨量等のデータも取得します。タイムゾーンは東京としています。
どういった項目が指定できるかは、サーバーの仕様によります。下記の外部リンクを適宜参照してください。
ちなみに、ブラウザを起動して、この文字列 url1 でアクセスすると、open-meteo のサイトから JSON ファイルが返ってきて、ブラウザに表示されるようになっています。
この url1 の文字列を return で返します。
・ requests_get1() は、サーバーから天候のデータを取得する関数です。
まず、上記の URI (=URL + クエリー)を作り、get コマンドでサーバーに送ります。サーバーから返ってきた応答を JSON 形式として受け取ります。JSON ファイルは、Python の辞書型として扱うことができます。
・ show_dict1() は、サーバーから受け取った JSON ファイル(辞書型)を表示する関数です。サーバーから受け取ったままのデータを加工などはせずに表示します。このデータを参照することで、どの項目名を指定すればどういったデータが取得できるかが、わかるようにしています。
・ show_current1() は、現在の天候データを表示する関数です。
具体的には、サーバーから受け取った JSON ファイルの内部を参照して、current(現在のデータ)となっている部分を抜き出して、天候データの取得日時、温度、相対湿度、… などのデータを表示します。
・ show1() は、上記の show_dict1() と show_current1() を実行する関数です。
・ filename1() は、保存するファイル名を生成する関数です。
・ スクリプトを実行すると、保存するファイル名 file1 を生成します。
つぎに file1 でファイルの読み込みをまず試み、ファイルが存在しない場合(サーバーにアクセスしていない場合)は、requests_get1() を実行することでサーバーにアクセスし、JSON ファイルの取得を試みます。JSON ファイルが取得できた場合は、ファイルを保存します。
その後、取得した JSON ファイルを表示します。
保存するファイルは、まずはサーバーから返ってきたデータ形式について改変をせず、そのまま保存するようにしています。テキストエディタなどで開くことでデータ形式を確認できるようにしています。
サーバーから得られるデータは JSON ファイルの形式となっているため、Python のスクリプト側も JSON ファイルの形式として取得することとし、以後、ファイルの保存、読み出しも JSON ファイル形式で統一するようにしています。
JSON ファイルのデータにアクセスする場合は、取得されたファイルの形式に基づいて、Key を指定して Value を取得していく、といった考え方でデータを取得できます。
また、JSON ファイルの仕様として、Value の中にはさらに辞書形式やリスト形式のデータを入れていくことができる仕様になっています。すなわち、Value の中に Key と Value のセットを入れていったり、Key のないリスト(通常の配列)を入れることができる仕様になっています。
上記の YYMMDD_HH_weather.json のファイルの内部をテキストエディタなどで確認しながら、階層をたぐっていき、欲しい情報を取得していきます。
read_weather1.py
・ read_weather1.py は、上記で保存したファイル YYMMDD_HH_weather1.json を読みだして、天候のデータを表示します。
・ 天候データは、サーバーへのアクセス時の値(current)として、以下としています。
時刻、降雨量 mm、温度 degC、相対湿度 %、気圧 hPa、日照量 %、風速 m/s、風向き1(0-360deg)、風向き2(方位)、天気コード
また、1時間おきの予報データ(hourly)も取得できるため、それらについても表示します。
・ 日照量は、サーバーから、3600s あたりの日照量 s で得られるため、% の単位に換算しています。
・ 風速は、サーバーから得られる数値の単位系が km/h となっています。天気予報では、風速は m/s の単位系が使われることが多いため、換算しています。
・ 風向き1は、風が吹いてくる方角で、北を 0 度として、時計回りの角度です。東が 90度、南が 180度、西が 270度に対応します。
・ 風向き2は、上記の角度を16方位に分割し、東西南北(E, W, S, N)で表したものです。
・ 天気コードは、世界気象機関の天気コードです。代表的なものを抜粋すると、以下となっています。
0: 快晴 clear sky、1: ほぼ晴れ mainly clear、2: 所により曇り partly cloudy、3: 曇り overcast
45-48: 霧、51-57: 霧雨等、61-67: 雨、71-77: 雪、80-82: にわか雨、95-99: 雷雨
何か簡単に役に立つ機能を自作するのであれば、この天気コードの数値を参照して対応する音声ファイルを再生するようにすれば、最もシンプルに現在の天候などを音声通知するシステムを構築できます。
まとめ
open-meteo というサイトを使って、指定した緯度、経度での天候データを取得するスクリプトをまとめました。
また、JSONファイルをサーバーから取得して保存したり、ファイルを読みだして任意の項目を読み出すことも可能になりました。
データが取得できたら、Raspberry Pi を使って音声でお知らせをしたり、洗濯物の乾燥時間の予測、機械学習や実測データと組み合わせるなど、任意の応用が可能です。興味のある方は、下記の関連リンクなども参照してみてください。
関連リンク
・ 天気予報を取得してテキストで出力する 【Python】
・ Raspberry Pi で時報を鳴らす 【Python】
・ 温度、湿度、気圧を測定する 【Raspberry Pi & BME280】
・ 乾燥時間の機械学習を行ってみる 【Python & Tensorflow】
外部リンク
・ https://open-meteo.com/
サンプルスクリプト
get_weather1.py ~ 指定した緯度、経度での天候データを取得して保存するスクリプト
import os
import requests as rq1
import json as js1
import datetime as dt1
def read1_json(file1):
try:
with open(file1, "r", encoding="utf-8") as f1:
dict1 = js1.load(f1)
except:
dict1 = {}
return dict1
def write1_json(file1, str1):
with open(file1, "w", encoding="utf-8") as f1:
js1.dump(str1, f1, ensure_ascii=False, indent=4)
return ""
def str1_url():
lat1 = 35.65 # latitude Tokyo
lon1 = 139.3392 # longitude Tokyo
url1 = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={lat1}&longitude={lon1}&"
f"current=precipitation,temperature_2m,relative_humidity_2m,surface_pressure,wind_speed_10m,wind_direction_10m,sunshine_duration,weather_code&"
f"hourly=precipitation,temperature_2m,relative_humidity_2m,surface_pressure,wind_speed_10m,wind_direction_10m,sunshine_duration,weather_code&"
f"timezone=Asia/Tokyo"
)
print(url1)
return url1
def requests_get1():
url1 = str1_url()
try:
resp1 = rq1.get(url1)
if resp1.status_code == 200:
dict1 = resp1.json()
else:
print("failed!")
dict1 = {}
except:
dict1 = {}
finally:
return dict1
def show_dict1(dict1):
for key1, val1 in dict1.items():
print(f"{key1}: {val1}")
return
def show_current1(dict1):
dict2 = dict1.get("current", {})
dict3 = dict1.get("current_units", {})
a1 = ["time", "temperature_2m", "relative_humidity_2m", "surface_pressure", "wind_speed_10m", "wind_direction_10m", "sunshine_duration", "precipitation", "weathter_code"]
str1 = ""
for i1 in range(len(a1)):
str2 = a1[i1]
str3 = str(dict2.get(str2, 0))
str4 = dict3.get(str2, "")
str5 = str3 + " " + str4 + " " + str2
str1 = str1 + str5 + "\n"
print(str1)
return str1
def show1(dict1):
show_dict1(dict1)
show_current1(dict1)
def filename1():
str1 = dt1.datetime.now().strftime("%y%m%d_%H") # %y%m%d_%H%M%S yyyymmdd_HHMMSS format
str1 = str1 + "_weather1.json"
return str1
path1 = os.path.dirname(__file__) + "/"
file1 = path1 + "weather1/" + filename1()
dict1 = read1_json(file1)
if dict1 == {}:
dict1 = requests_get1()
if dict1 != {}:
file1 = path1 + "weather1/" + filename1()
write1_json(file1, dict1)
show1(dict1)
read_weather1.py ~ JSON ファイル(天候データ)を読み出して表示するスクリプト
import os
import json as js1
import datetime as dt1
import glob as gl1
def read1_json(file1):
try:
with open(file1, "r", encoding="utf-8") as f1:
dict1 = js1.load(f1)
except:
dict1 = {}
return dict1
def write1_json(file1, str1):
with open(file1, "w", encoding="utf-8") as f1:
js1.dump(str1, f1, ensure_ascii=False, indent=4)
return ""
def show_dict1(dict1):
for key1, val1 in dict1.items():
print(f"{key1}: {val1}")
return
def show_current1(dict1):
dict2 = dict1.get("current", {})
dict3 = dict1.get("current_units", {})
a1 = ["time", "temperature_2m", "relative_humidity_2m", "surface_pressure", "wind_speed_10m", "wind_direction_10m", "sunshine_duration", "precipitation", "weathter_code"]
str1 = ""
for i1 in range(len(a1)):
str2 = a1[i1]
str3 = str(dict2.get(str2, 0))
str4 = dict3.get(str2, "")
str5 = str3 + " " + str4 + " " + str2
str1 = str1 + str5 + "\n"
print(str1)
return str1
def show_current2(dict1):
dict2 = dict1.get("current", {})
time1 = dict2.get("time", "").split("T")
str1 = ""
if len(time1) == 2:
prec1 = dict2.get("precipitation", 0.0) # precipitation, mm
temp1 = dict2.get("temperature_2m", 0.0) # temperature, degC
humi1 = dict2.get("relative_humidity_2m", 0) # relative humidity, % (decimal)
sped1 = dict2.get("wind_speed_10m", 0.0)*1000.0/3600.0 # wind speed, m/s (km/h -> m/s)
sped1 = f"{sped1:>3.1f}"
dire1 = dict2.get("wind_direction_10m", 0.0) # wind direction 0 - 360 deg
dire1 = direction1(dire1)
suns1 = dict2.get("sunshine_duration", 0.0)/3600.0 * 100.0 # sunshine duration, % (s -> %)
suns1 = f"{suns1:>5.1f}"
pres1 = dict2.get("surface_pressure", 0.0) # pressure, hPa
pres1 = f"{pres1:>6.1f}"
code1 = dict2.get("weather_code", -1) # weather code
str1 = str(time1[0]) + " \n"
str1 = str1 + str(time1[1]) + " " + str(prec1) + "mm " + str(temp1) + "degC " + str(humi1) + "% " + str(pres1) + "hPa " + str(suns1) + "% "
str1 = str1 + str(sped1) + "m/s " + str(dire1) + " " + str(code1) + " "
print(str1)
return str1
def direction1(angle1):
NESW1 = [
" N", "NNE", " NE", "ENE",
" E", "ESE", " SE", "SSE",
" S", "SSW", " SW", "WSW",
" W", "WNW", " NW", "NNW"
]
angle2 = angle1 % 360.0 # angle2 >=0, and <360 n1 = int((angle2 + 11.25) // 22.5) % 16 # 0, 1, ..., 15 str1 = f"{int(angle2):>3}" + " " + NESW1[n1]
return str1
def show_hourly1(dict1):
dict2 = dict1.get("hourly", {})
a1 = dict2.get("time", [])
a2 = dict2.get("precipitation", []) # precipitation, mm
a3 = dict2.get("temperature_2m", []) # temperature, degC
a4 = dict2.get("relative_humidity_2m", []) # relative humidity, %
a5 = dict2.get("wind_speed_10m", []) # wind speed, km/h
a6 = dict2.get("wind_direction_10m", []) # wind direction, 0 - 360
a7 = dict2.get("surface_pressure", []) # pressure, hPa
a8 = dict2.get("sunshine_duration", []) # sunshine duration, s (/3600s)
a9 = dict2.get("weather_code", []) # weather code
str1 = dt1.datetime.now().strftime("%Y-%m-%dT%H")
str2 = ""
n1 = 0
for i1 in range(len(a1)):
str3 = a1[i1] # date
if str1 in str3:
n1 = n1 + 1
if n1 > -1:
time1 = str3.split("T")[1] # time
prec1 = str(a2[i1])
temp1 = str(a3[i1])
humi1 = str(a4[i1])
sped1 = a5[i1]*1000.0/3600.0 # km/h -> m/s
sped1 = f"{sped1:>3.1f}"
dire1 = direction1(a6[i1])
pres1 = f"{a7[i1]:>6.1f}"
suns1 = a8[i1]/3600.0*100.0
suns1 = f"{suns1:>5.1f}"
code1 = str(a9[i1])
str4 = time1 + " " + prec1 + "mm " + temp1 + "degC " + humi1 + "% " + pres1 + "hPa " + suns1 + "% " + sped1 + "m/s " + dire1 + " " + code1
str2 = str2 + str4 + "\n"
n1 = n1 + 1
# if n1 > 12:
# if n1 > 16:
if n1 > 24:
break
print(str2)
return str2
def get_filename1(path1):
pattern1 = dt1.datetime.now().strftime("%y%m%d") + "_*_weather1.json"
# pattern1 = dt1.datetime.now().strftime("%y%m") + "*_*_weather1.json"
path2 = path1 + pattern1
a1 = sorted(gl1.glob(path2))
file1 = ""
if len(a1) > 0:
file1 = os.path.basename(a1[-1]) # latest file
else:
print("cannot find!")
return file1
def show1(dict1):
# show_dict1(dict1)
# show_current1(dict1)
show_current2(dict1)
show_hourly1(dict1)
path1 = os.path.dirname(__file__) + "/weather1/"
file1 = get_filename1(path1)
print(file1)
file2 = path1 + file1
dict1 = read1_json(file2)
show1(dict1)
