365 lines
12 KiB
Python
365 lines
12 KiB
Python
"""
|
|
Script voor het ophalen van een HEEL JAAR aan historische weerdata voor Amersfoort
|
|
"""
|
|
import requests
|
|
import sqlite3
|
|
import pandas as pd
|
|
from datetime import datetime
|
|
import time
|
|
|
|
# ===== CONFIGURATIE =====
|
|
LOCATIE = "Amersfoort"
|
|
LATITUDE = 52.15
|
|
LONGITUDE = 5.39
|
|
|
|
# Kies je jaar(en) hier!
|
|
START_JAAR = 2025
|
|
START_MAAND = 1
|
|
START_DAG = 1
|
|
|
|
EIND_JAAR = 2025
|
|
EIND_MAAND = 11
|
|
EIND_DAG = 11
|
|
|
|
DATABASE_NAAM = f"weer_amersfoort_{START_JAAR}.db"
|
|
|
|
# Open-Meteo kan maximaal 1 jaar per request, dus we splitsen het op indien nodig
|
|
# ========================
|
|
|
|
def setup_database(db_naam):
|
|
"""Maak database en tabellen aan"""
|
|
conn = sqlite3.connect(db_naam)
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS weer_dagelijks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
datum DATE UNIQUE NOT NULL,
|
|
locatie TEXT NOT NULL,
|
|
latitude REAL,
|
|
longitude REAL,
|
|
temp_max REAL,
|
|
temp_min REAL,
|
|
temp_gem REAL,
|
|
neerslag REAL,
|
|
wind_max REAL,
|
|
wind_gem REAL,
|
|
wind_richting REAL,
|
|
luchtvochtigheid_gem REAL,
|
|
bewolking_gem REAL,
|
|
zonuren REAL,
|
|
toegevoegd_op TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS weer_uurlijks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
datum_tijd DATETIME UNIQUE NOT NULL,
|
|
locatie TEXT NOT NULL,
|
|
temperatuur REAL,
|
|
gevoelstemperatuur REAL,
|
|
neerslag REAL,
|
|
wind_snelheid REAL,
|
|
wind_richting REAL,
|
|
luchtvochtigheid INTEGER,
|
|
bewolking INTEGER,
|
|
luchtdruk REAL,
|
|
toegevoegd_op TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
|
|
conn.commit()
|
|
return conn
|
|
|
|
def haal_weerdata_op(start_date, end_date, ophaal_uurlijks=True):
|
|
"""
|
|
Haal weerdata op via Open-Meteo API
|
|
|
|
Args:
|
|
start_date: datetime object voor startdatum
|
|
end_date: datetime object voor einddatum
|
|
ophaal_uurlijks: Ook uurlijkse data ophalen (kan veel data zijn!)
|
|
"""
|
|
url = "https://archive-api.open-meteo.com/v1/archive"
|
|
|
|
# Uitgebreide parameters voor een volledig beeld
|
|
params = {
|
|
"latitude": LATITUDE,
|
|
"longitude": LONGITUDE,
|
|
"start_date": start_date.strftime("%Y-%m-%d"),
|
|
"end_date": end_date.strftime("%Y-%m-%d"),
|
|
"daily": [
|
|
"temperature_2m_max",
|
|
"temperature_2m_min",
|
|
"temperature_2m_mean",
|
|
"apparent_temperature_max",
|
|
"apparent_temperature_min",
|
|
"precipitation_sum",
|
|
"rain_sum",
|
|
"snowfall_sum",
|
|
"precipitation_hours",
|
|
"wind_speed_10m_max",
|
|
"wind_speed_10m_mean",
|
|
"wind_direction_10m_dominant",
|
|
"sunshine_duration"
|
|
],
|
|
"timezone": "Europe/Amsterdam"
|
|
}
|
|
|
|
if ophaal_uurlijks:
|
|
params["hourly"] = [
|
|
"temperature_2m",
|
|
"apparent_temperature",
|
|
"precipitation",
|
|
"rain",
|
|
"snowfall",
|
|
"wind_speed_10m",
|
|
"wind_direction_10m",
|
|
"relative_humidity_2m",
|
|
"cloud_cover",
|
|
"surface_pressure"
|
|
]
|
|
|
|
print(f"\n📡 Data ophalen voor periode: {start_date.date()} tot {end_date.date()}")
|
|
print(f" Aantal dagen: {(end_date - start_date).days + 1}")
|
|
|
|
try:
|
|
response = requests.get(url, params=params, timeout=60)
|
|
response.raise_for_status()
|
|
print(f"✅ Data succesvol opgehaald!")
|
|
return response.json()
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"❌ Fout bij ophalen data: {e}")
|
|
return None
|
|
|
|
def sla_dagelijkse_data_op(conn, data):
|
|
"""Sla dagelijkse data op in database"""
|
|
if not data or 'daily' not in data:
|
|
return 0
|
|
|
|
daily = data['daily']
|
|
cursor = conn.cursor()
|
|
records_toegevoegd = 0
|
|
|
|
for i in range(len(daily['time'])):
|
|
try:
|
|
cursor.execute('''
|
|
INSERT OR REPLACE INTO weer_dagelijks
|
|
(datum, locatie, latitude, longitude, temp_max, temp_min,
|
|
temp_gem, neerslag, wind_max, wind_gem, wind_richting,
|
|
zonuren)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
''', (
|
|
daily['time'][i],
|
|
LOCATIE,
|
|
LATITUDE,
|
|
LONGITUDE,
|
|
daily['temperature_2m_max'][i],
|
|
daily['temperature_2m_min'][i],
|
|
daily['temperature_2m_mean'][i],
|
|
daily['precipitation_sum'][i],
|
|
daily['wind_speed_10m_max'][i],
|
|
daily['wind_speed_10m_mean'][i],
|
|
daily['wind_direction_10m_dominant'][i],
|
|
daily['sunshine_duration'][i] / 3600 if daily['sunshine_duration'][i] else None # Convert seconds to hours
|
|
))
|
|
records_toegevoegd += 1
|
|
except sqlite3.IntegrityError:
|
|
pass
|
|
|
|
conn.commit()
|
|
return records_toegevoegd
|
|
|
|
def sla_uurlijkse_data_op(conn, data):
|
|
"""Sla uurlijkse data op in database"""
|
|
if not data or 'hourly' not in data:
|
|
return 0
|
|
|
|
hourly = data['hourly']
|
|
cursor = conn.cursor()
|
|
records_toegevoegd = 0
|
|
|
|
print(f" Uurlijkse records verwerken: {len(hourly['time'])} uur...")
|
|
|
|
# Batch insert voor betere performance
|
|
batch = []
|
|
for i in range(len(hourly['time'])):
|
|
batch.append((
|
|
hourly['time'][i],
|
|
LOCATIE,
|
|
hourly['temperature_2m'][i],
|
|
hourly['apparent_temperature'][i],
|
|
hourly['precipitation'][i],
|
|
hourly['wind_speed_10m'][i],
|
|
hourly['wind_direction_10m'][i],
|
|
hourly['relative_humidity_2m'][i],
|
|
hourly['cloud_cover'][i],
|
|
hourly['surface_pressure'][i]
|
|
))
|
|
|
|
cursor.executemany('''
|
|
INSERT OR REPLACE INTO weer_uurlijks
|
|
(datum_tijd, locatie, temperatuur, gevoelstemperatuur, neerslag,
|
|
wind_snelheid, wind_richting, luchtvochtigheid, bewolking, luchtdruk)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
''', batch)
|
|
|
|
conn.commit()
|
|
return len(batch)
|
|
|
|
def toon_statistieken(conn):
|
|
"""Toon statistieken van de database"""
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT COUNT(*) FROM weer_dagelijks")
|
|
aantal_dagen = cursor.fetchone()[0]
|
|
|
|
cursor.execute("SELECT COUNT(*) FROM weer_uurlijks")
|
|
aantal_uren = cursor.fetchone()[0]
|
|
|
|
print("\n" + "="*70)
|
|
print("DATABASE STATISTIEKEN")
|
|
print("="*70)
|
|
print(f"📊 Dagelijkse records: {aantal_dagen} dagen")
|
|
print(f"📊 Uurlijkse records: {aantal_uren} uur")
|
|
|
|
if aantal_dagen > 0:
|
|
cursor.execute("""
|
|
SELECT
|
|
MIN(datum) as eerste_datum,
|
|
MAX(datum) as laatste_datum,
|
|
ROUND(AVG(temp_max), 1) as gem_max_temp,
|
|
ROUND(MAX(temp_max), 1) as hoogste_temp,
|
|
ROUND(MIN(temp_min), 1) as laagste_temp,
|
|
ROUND(SUM(neerslag), 1) as totale_neerslag,
|
|
ROUND(AVG(wind_max), 1) as gem_wind,
|
|
ROUND(SUM(zonuren), 1) as totale_zonuren
|
|
FROM weer_dagelijks
|
|
""")
|
|
|
|
stats = cursor.fetchone()
|
|
print(f"\n📅 Periode: {stats[0]} tot {stats[1]}")
|
|
print(f"\n🌡️ TEMPERATUUR:")
|
|
print(f" Gemiddeld max: {stats[2]}°C")
|
|
print(f" Hoogste: {stats[3]}°C")
|
|
print(f" Laagste: {stats[4]}°C")
|
|
print(f"\n💧 NEERSLAG:")
|
|
print(f" Totaal: {stats[5]} mm")
|
|
print(f"\n💨 WIND:")
|
|
print(f" Gemiddeld max: {stats[6]} km/h")
|
|
print(f"\n☀️ ZON:")
|
|
print(f" Totale zonuren: {stats[7]} uur ({stats[7]/24:.1f} dagen)")
|
|
|
|
# Maandstatistieken
|
|
print(f"\n📊 PER MAAND:")
|
|
cursor.execute("""
|
|
SELECT
|
|
strftime('%Y-%m', datum) as maand,
|
|
ROUND(AVG(temp_max), 1) as gem_max,
|
|
ROUND(AVG(temp_min), 1) as gem_min,
|
|
ROUND(SUM(neerslag), 1) as neerslag,
|
|
COUNT(CASE WHEN neerslag > 0.1 THEN 1 END) as regendagen
|
|
FROM weer_dagelijks
|
|
GROUP BY maand
|
|
ORDER BY maand
|
|
""")
|
|
|
|
print(f"\n {'Maand':<10} {'Max°C':<8} {'Min°C':<8} {'Neerslag':<12} {'Regendagen':<12}")
|
|
print(f" {'-'*60}")
|
|
for row in cursor.fetchall():
|
|
print(f" {row[0]:<10} {row[1]:<8} {row[2]:<8} {row[3]:<12} {row[4]:<12}")
|
|
|
|
print("="*70)
|
|
|
|
def exporteer_naar_csv(conn, output_prefix="weer_export"):
|
|
"""Exporteer data naar CSV bestanden"""
|
|
# Dagelijkse data
|
|
df_dagelijks = pd.read_sql_query(
|
|
"SELECT * FROM weer_dagelijks ORDER BY datum",
|
|
conn
|
|
)
|
|
csv_dag = f"{output_prefix}_dagelijks.csv"
|
|
df_dagelijks.to_csv(csv_dag, index=False)
|
|
print(f"✅ Dagelijkse data: {csv_dag} ({len(df_dagelijks)} records)")
|
|
|
|
# Uurlijkse data (alleen als niet te groot)
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT COUNT(*) FROM weer_uurlijks")
|
|
aantal_uur = cursor.fetchone()[0]
|
|
|
|
if aantal_uur > 0 and aantal_uur < 10000: # Max ~1 jaar uurlijks
|
|
df_uurlijks = pd.read_sql_query(
|
|
"SELECT * FROM weer_uurlijks ORDER BY datum_tijd",
|
|
conn
|
|
)
|
|
csv_uur = f"{output_prefix}_uurlijks.csv"
|
|
df_uurlijks.to_csv(csv_uur, index=False)
|
|
print(f"✅ Uurlijkse data: {csv_uur} ({len(df_uurlijks)} records)")
|
|
elif aantal_uur > 10000:
|
|
print(f"⚠️ Uurlijkse data ({aantal_uur} records) niet geëxporteerd (te groot)")
|
|
|
|
|
|
def main():
|
|
"""Hoofdfunctie"""
|
|
print("="*70)
|
|
print(f"HISTORISCHE WEERDATA VOOR {LOCATIE}")
|
|
print("="*70)
|
|
|
|
# Datum objecten maken
|
|
start_date = datetime(START_JAAR, START_MAAND, START_DAG)
|
|
end_date = datetime(EIND_JAAR, EIND_MAAND, EIND_DAG)
|
|
|
|
# Check of periode niet te groot is
|
|
dagen = (end_date - start_date).days + 1
|
|
if dagen > 400:
|
|
antwoord = input(f"\n⚠️ Je wilt {dagen} dagen ophalen. Dit kan even duren. Doorgaan? (j/n): ")
|
|
if antwoord.lower() != 'j':
|
|
print("Geannuleerd.")
|
|
return
|
|
|
|
# Uurlijkse data vraag
|
|
if dagen > 180:
|
|
print(f"\n💡 TIP: Voor {dagen} dagen is dat {dagen*24} uur aan data.")
|
|
ophaal_uurlijks = input(" Wil je ook uurlijkse data? Dit maakt de database groter. (j/n): ")
|
|
ophaal_uurlijks = ophaal_uurlijks.lower() == 'j'
|
|
else:
|
|
ophaal_uurlijks = True
|
|
|
|
# Setup database
|
|
print(f"\n📁 Database: {DATABASE_NAAM}")
|
|
conn = setup_database(DATABASE_NAAM)
|
|
|
|
# Haal data op
|
|
data = haal_weerdata_op(start_date, end_date, ophaal_uurlijks)
|
|
|
|
if data:
|
|
print("\n💾 Data opslaan in database...")
|
|
|
|
# Dagelijkse data
|
|
dag_records = sla_dagelijkse_data_op(conn, data)
|
|
print(f"✅ {dag_records} dagelijkse records opgeslagen")
|
|
|
|
# Uurlijkse data
|
|
if ophaal_uurlijks:
|
|
uur_records = sla_uurlijkse_data_op(conn, data)
|
|
print(f"✅ {uur_records} uurlijkse records opgeslagen")
|
|
|
|
# Statistieken
|
|
toon_statistieken(conn)
|
|
|
|
# Exporteer
|
|
print(f"\n📤 Data exporteren...")
|
|
exporteer_naar_csv(conn, f"amersfoort_{START_JAAR}")
|
|
|
|
conn.close()
|
|
print(f"\n✅ Klaar! Database opgeslagen als: {DATABASE_NAAM}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("\n💡 Open-Meteo API - Gratis historische weerdata")
|
|
print(" Data beschikbaar vanaf 1940")
|
|
print(" Geen API key nodig!\n")
|
|
|
|
main()
|