Datensets zum Herunterladen
Der Kulturpool stellt täglich aktualisierte Komplett-Exporte aller Objektdaten zum Download bereit. Diese Datensets ermöglichen die lokale Verarbeitung, Analyse und Wiederverwendung des gesamten Datenbestands für Forschung, eigene Anwendungen oder Archivierungszwecke.
Download-URL
Die tagesaktuellen Datensets sind als komprimiertes TAR-Archiv unter der folgenden, stabilen URL verfügbar:
https://s3.kpool.at/nightly/records_export_full.tar.gz
Das Archiv wird nächtlich neu erzeugt und ist derzeit rund 650 MB groß. Der Server unterstützt HTTP-Range-Requests (Accept-Ranges: bytes), abgebrochene Downloads lassen sich also fortsetzen — etwa mit curl -C - oder wget -c.
curl -C - -O "https://s3.kpool.at/nightly/records_export_full.tar.gz"
Über den Last-Modified-Header lässt sich prüfen, ob seit dem letzten Abruf ein neuer Export vorliegt:
curl -sI "https://s3.kpool.at/nightly/records_export_full.tar.gz" | grep -i last-modified
Datenformat
1. Archiv (.tar.gz)
Der Download ist eine einzelne, mit gzip komprimierte TAR-Archivdatei. Sie müssen diese Datei nach dem Herunterladen entpacken, um auf die eigentlichen Datensätze zugreifen zu können.
tar -xzf full_records.tar.gz
2. Datendateien (.jsonl)
Das entpackte Archiv enthält mehrere Dateien mit der Endung .jsonl — für jede datenliefernde Institution eine. Das JSONL-Format (JSON Lines) bedeutet, dass jede Datei aus mehreren Zeilen besteht, wobei jede Zeile ein vollständiges, eigenständiges JSON-Objekt darstellt.
3. Datensatz (JSON-LD / EDM)
Jedes JSON-Objekt (also jede Zeile in einer .jsonl-Datei) repräsentiert ein einzelnes Kulturgut. Der Datensatz ist im JSON-LD-Format strukturiert und folgt dem Europeana Data Model (EDM). Die Struktur entspricht dem metadata-Objekt, das auch von der Objekt API ausgeliefert wird.
Struktur eines Datensatzes
Jede Zeile in den .jsonl-Dateien ist ein JSON-Objekt, das wie folgt aussehen kann:
{
"@context": {
"ore": "http://www.openarchives.org/ore/terms/",
"edm": "http://www.europeana.eu/schemas/edm/",
"dc": "http://purl.org/dc/elements/1.1/",
"...": "..."
},
"id": "#belvedere_5420_AGG",
"type": "Aggregation",
"aggregatedCHO": {
"id": "#belvedere_5420",
"type": "ProvidedCHO",
"dc:title": [
{
"lang": "de",
"value": "Der Kuss"
}
],
"dc:creator": [
{
"value": "Gustav Klimt"
}
]
},
"provider": {
"id": "https://www.belvedere.at/",
"type": "Agent",
"dc:title": [
{
"lang": "de",
"value": "Belvedere"
}
]
},
"edm:dataProvider": {
"id": "https://www.belvedere.at/",
"type": "Agent",
"dc:title": [
{
"lang": "de",
"value": "Belvedere"
}
]
},
"edm:isShownAt": {
"id": "https://digital.belvedere.at/objects/5420/der-kuss-liebespaar",
"type": "WebResource"
},
"edm:isShownBy": {
"id": "https://digital.belvedere.at/resources/images/xl/5420.jpg",
"type": "WebResource"
},
"edm:rights": {
"id": "http://creativecommons.org/publicdomain/mark/1.0/",
"type": "RightStatement"
}
}
Nicht jeder Datensatz enthält alle Felder, und mehrsprachige Werte sind als Arrays von {lang, value}-Objekten modelliert. Greifen Sie daher defensiv auf verschachtelte Felder zu.
Beispiel zur Verarbeitung (Python)
Das folgende Skript lädt das Archiv streamend auf die Festplatte, entpackt es und verarbeitet die JSONL-Dateien Zeile für Zeile — ohne den gesamten Datenbestand im Arbeitsspeicher zu halten.
import json
import tarfile
from pathlib import Path
import requests
DATASET_URL = "https://s3.kpool.at/nightly/records_export_full.tar.gz"
ARCHIVE_PATH = Path("full_records.tar.gz")
def download(url: str, target: Path) -> Path:
"""Archiv streamend herunterladen (mehrere hundert MB)."""
if target.exists():
print(f"{target} existiert bereits — Download übersprungen.")
return target
print(f"Lade Datenset von {url} herunter ...")
with requests.get(url, stream=True, timeout=60) as response:
response.raise_for_status()
with target.open("wb") as fh:
for chunk in response.iter_content(chunk_size=1024 * 1024):
fh.write(chunk)
print(f"Fertig: {target} ({target.stat().st_size / 1024**2:.0f} MB)")
return target
def iter_records(archive: Path):
"""Alle Datensätze aus allen .jsonl-Dateien im Archiv liefern."""
with tarfile.open(archive, mode="r:gz") as tar:
for member in tar:
if not (member.isfile() and member.name.endswith(".jsonl")):
continue
print(f"\n--- Verarbeite Datei: {member.name} ---")
handle = tar.extractfile(member)
if handle is None:
continue
for line_number, raw_line in enumerate(handle, 1):
line = raw_line.decode("utf-8").strip()
if not line:
continue
try:
yield member.name, json.loads(line)
except json.JSONDecodeError:
print(f"Fehler beim Parsen von {member.name}:{line_number}")
def get_title(record: dict) -> str | None:
"""Titel extrahieren, bevorzugt auf Deutsch."""
titles = record.get("aggregatedCHO", {}).get("dc:title") or []
if not titles:
return None
german = next((t["value"] for t in titles if t.get("lang") == "de"), None)
return german or titles[0].get("value")
if __name__ == "__main__":
download(DATASET_URL, ARCHIVE_PATH)
count = 0
for source_file, record in iter_records(ARCHIVE_PATH):
title = get_title(record)
if title:
count += 1
if count <= 10:
print(f"Gefundener Titel: {title}")
print(f"\nVerarbeitung abgeschlossen. {count} Datensätze mit Titel gefunden.")
Wann welcher Zugang?
| Anwendungsfall | Empfohlener Weg |
|---|---|
| Suchoberfläche, einzelne Abfragen | Suche API |
| Einzelnes Objekt in voller Tiefe | Objekt API |
| Inkrementelles Harvesting, Aggregatoren | OAI-PMH |
| Vollständiger Datenbestand, Analyse, Archivierung | Datensets (diese Seite) |
Wenn Sie den kompletten Datenbestand benötigen, ist der Download eines Datensets deutlich schneller und schonender für die Infrastruktur als tausende paginierte API-Anfragen.