Ein lokaler Metadaten-Katalog für Open-Data-Quellen.
Harvestet Metadaten von öffentlichen Datenportalen, speichert sie in einer DuckDB und macht sie über ein Streamlit-Dashboard durchsuchbar.
- 🔍 Metadaten-Suche über 400.000+ Datensätze aus 6+ Portalen
- 📊 Streamlit-Dashboard mit 4D-Explorer, Parallel-Ansicht, Karte und CSV-Export
- 🔄 Idempotenter Harvest — UPSERT auf Primärschlüssel, keine Duplikate
- 📦 Provenienz — Rohdaten unverändert als gzip-JSONL archiviert
- 🔌 Erweiterbar — neue Portal-Typen durch eine Python-Klasse
- 💻 Lokal & offline — DuckDB auf lokaler Platte, keine Cloud-Abhängigkeit
| Portal | Typ | Datasets | Lizenz |
|---|---|---|---|
| GovData | CKAN | ~151.000 | variiert |
| Hamburg Transparenzportal | CKAN | ~237.000 | variiert |
| Open.NRW | CKAN | ~10.000 | variiert |
| Open Data München | CKAN | ~336 | variiert |
| Our World in Data | OWID Search-API | ~12.000 Charts | CC-BY-4.0 |
| Destatis GENESIS-Online | REST (POST) | ~110.000+ | dl-de/by-2-0 |
# 1. Repository klonen
git clone https://github.com/YOUR_USER/open-data-katalog.git
cd open-data-katalog
# 2. Virtuelle Umgebung erstellen
python -m venv .venv
source .venv/bin/activate # Linux/Mac
.venv\Scripts\activate # Windows
# 3. Abhängigkeiten installieren
pip install -r requirements.txt
# 4. Portale konfigurieren
cp seeds.example.yaml seeds.yaml
# → seeds.yaml bearbeiten, ggf. Destatis-Token eintragen
# 5. Harvest starten
python harvester.py
# 6. Dashboard starten
streamlit run dashboard.py --server.port 8501open-data-katalog/
├── harvester.py # Haupt-Harvester (CKAN + OWID)
├── harvester_destatis.py # Separater Destatis-Harvester
├── dashboard.py # Streamlit-Dashboard
├── seeds.yaml # Portal-Konfiguration
├── seeds.example.yaml # Beispiel-Konfiguration (ohne Tokens)
├── requirements.txt # Python-Abhängigkeiten
├── catalog.db # DuckDB (wird vom Harvester erzeugt)
├── log.md # Append-only Ingest-Log
├── sources/ # Rohdaten (gzip-JSONL, Provenienz)
│ ├── ckan/<portal>/<date>/
│ ├── owid/<portal>/<date>/
│ └── destatis/<portal>/<date>/
└── .github/workflows/ci.yml # CI (Syntax-Check)
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ CKAN-API │ │ OWID-API │ │ Destatis-API│
│ (REST) │ │ (Search) │ │ (POST) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────┐
│ harvester.py / _destatis.py │
│ → Paginierter Abruf │
│ → Rohdaten als gzip-JSONL (Provenienz) │
│ → Normalisierung + UPSERT in DuckDB │
└─────────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ catalog.db (DuckDB) │
│ datasets: portal, dataset_id, titel, thema, │
│ publisher, formate, lizenz, url, … │
│ tags: portal, dataset_id, tag │
└─────────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ dashboard.py (Streamlit) │
│ → Sidebar-Filter (Portal, Thema, Lizenz, …) │
│ → KPI-Zeile (Datasets, Portale, Formate, …) │
│ → 4D-Explorer (Bubble-Matrix) │
│ → Parallel-Ansicht (Plotly parallel_categories) │
│ → Karte (Portal-Standorte) │
│ → Datentabelle + CSV-Export │
└─────────────────────────────────────────────────┘
- seeds.yaml definiert Portale mit Typ und Basis-URL
- harvester.py iteriert über alle Portale
- Pro Portal: paginierter API-Abruf → Rohdaten speichern → normalisieren → UPSERT
- log.md dokumentiert jeden Lauf (append-only)
- Dashboard liest read-only aus der DuckDB
- Die GENESIS-API unterstützt nur POST (GET wurde am 15.07.2025 abgeschaltet)
- Authentifizierung per
username/passwordals HTTP-Header - Kostenlose Registrierung unter genesis.destatis.de
- API ist langsam (~25s/Page) — Batch-Commit alle 50 Seiten
- In
harvester.pyeine neueharvest_*-Funktion schreiben - In
harvest_portal()den neuen Typ registrieren - In
seeds.yamleinen Eintrag mittype: dein_typhinzufügen
def harvest_mein_portal(con, session, name, base_url):
# 1. API abrufen
# 2. Rohdaten speichern (save_raw / save_raw_*)
# 3. Normalisieren → rows + tags
# 4. upsert_datasets() + upsert_tags()
# 5. append_log()MIT — siehe LICENSE.
Dieses Projekt erntet ausschließlich Metadaten (Titel, Beschreibung, Lizenz, URL),
niemals die eigentlichen Dateninhalte. Die Nutzung der Daten unterliegt den
Lizenzen der jeweiligen Quellportale.