initial commit
This commit is contained in:
364
jaar_weerdata.py
Normal file
364
jaar_weerdata.py
Normal file
@@ -0,0 +1,364 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user