Zum Hauptinhalt springen

Datensets zum Herunterladen

Überblick

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"
}
}
Struktur kann variieren

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?​

AnwendungsfallEmpfohlener Weg
Suchoberfläche, einzelne AbfragenSuche API
Einzelnes Objekt in voller TiefeObjekt API
Inkrementelles Harvesting, AggregatorenOAI-PMH
Vollständiger Datenbestand, Analyse, ArchivierungDatensets (diese Seite)
tipp

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.