River_Network / scripts /download_hubeau.py
ageraustine's picture
Upload folder using huggingface_hub
a74054f verified
Raw
History Blame Contribute Delete
4.86 kB
"""
Download hydrometric data from Hub'Eau API v2.
Downloads QmJ (daily discharge), HIJ (daily water level) for all 27 stations.
"""
import requests
import pandas as pd
from pathlib import Path
from tqdm import tqdm
import time
# Configuration
OUTPUT_DIR = Path("datasets/hydrometric")
OUTPUT_DIR.mkdir(exist_ok=True)
BASE_URL = "https://hubeau.eaufrance.fr/api/v2/hydrometrie"
# Load stations
stations_df = pd.read_csv("datasets/station_list.csv")
station_codes = stations_df["station_code"].tolist()
print(f"Downloading hydrometric data for {len(station_codes)} stations...")
print(f"Output: {OUTPUT_DIR}")
print()
def download_observations(station_code, grandeur_hydro="Q", max_results=100000):
"""
Download observations for a station.
Args:
station_code: Station code (e.g., H602021010)
grandeur_hydro: H (water level) or Q (discharge)
max_results: Maximum results to fetch
Returns:
DataFrame with observations
"""
url = f"{BASE_URL}/obs_elab"
all_data = []
cursor = ""
page = 1
while len(all_data) < max_results:
params = {
"code_entite": station_code,
"grandeur_hydro": grandeur_hydro,
"size": 20000, # Max per request
"format": "json",
"cursor": cursor
}
try:
response = requests.get(url, params=params, timeout=30)
if response.status_code == 200:
data = response.json()
results = data.get("data", [])
if not results:
break
all_data.extend(results)
# Check for next page
next_url = data.get("next")
if not next_url or len(results) < 20000:
break
# Extract cursor from next URL
if "cursor=" in next_url:
cursor = next_url.split("cursor=")[1].split("&")[0]
else:
break
page += 1
time.sleep(0.1) # Rate limiting
else:
print(f" Error {response.status_code}")
break
except Exception as e:
print(f" Exception: {e}")
break
if all_data:
return pd.DataFrame(all_data)
else:
return pd.DataFrame()
# Download discharge (Q) for all stations
print("="*80)
print("DOWNLOADING DISCHARGE (Q)")
print("="*80)
discharge_data = []
for station_code in tqdm(station_codes, desc="Discharge"):
df = download_observations(station_code, grandeur_hydro="Q")
if not df.empty:
df["station_code"] = station_code
discharge_data.append(df)
tqdm.write(f"✓ {station_code}: {len(df)} observations")
else:
tqdm.write(f"✗ {station_code}: No data")
time.sleep(0.2)
if discharge_data:
discharge_df = pd.concat(discharge_data, ignore_index=True)
# Save
discharge_df.to_csv(OUTPUT_DIR / "discharge_observations.csv", index=False)
discharge_df.to_json(OUTPUT_DIR / "discharge_observations.json", orient="records", indent=2)
print(f"\n✓ Discharge: {len(discharge_df)} total observations")
print(f" Stations: {discharge_df['station_code'].nunique()}")
print(f" Date range: {discharge_df['date_obs_elab'].min()} to {discharge_df['date_obs_elab'].max()}")
# Download water level (H) for all stations
print("\n" + "="*80)
print("DOWNLOADING WATER LEVEL (H)")
print("="*80)
waterlevel_data = []
for station_code in tqdm(station_codes, desc="Water Level"):
df = download_observations(station_code, grandeur_hydro="H")
if not df.empty:
df["station_code"] = station_code
waterlevel_data.append(df)
tqdm.write(f"✓ {station_code}: {len(df)} observations")
else:
tqdm.write(f"✗ {station_code}: No data")
time.sleep(0.2)
if waterlevel_data:
waterlevel_df = pd.concat(waterlevel_data, ignore_index=True)
# Save
waterlevel_df.to_csv(OUTPUT_DIR / "waterlevel_observations.csv", index=False)
waterlevel_df.to_json(OUTPUT_DIR / "waterlevel_observations.json", orient="records", indent=2)
print(f"\n✓ Water level: {len(waterlevel_df)} total observations")
print(f" Stations: {waterlevel_df['station_code'].nunique()}")
print(f" Date range: {waterlevel_df['date_obs_elab'].min()} to {waterlevel_df['date_obs_elab'].max()}")
# Summary
print("\n" + "="*80)
print("DOWNLOAD COMPLETE")
print("="*80)
print(f"Files saved to: {OUTPUT_DIR}")
print(f"\nFiles created:")
for f in OUTPUT_DIR.glob("*"):
size_mb = f.stat().st_size / 1024 / 1024
print(f" - {f.name} ({size_mb:.1f} MB)")