Bulk-WHOIS-Abfrage: Tools, Skripte und API-Methoden

So fragen Sie WHOIS oder RDAP für Dutzende Domains gleichzeitig ab: Web-Tools, ein Bash-Skript mit Rate-Limiting und ein Python-RDAP-Ansatz.

WHOIS oder RDAP für eine Domain-Liste abzufragen ist nicht trivial. Das WHOIS-Protokoll erzwingt strikte Rate-Limits pro IP, überschreiten Sie diese, wird Ihre Adresse für eine Stunde oder länger gesperrt. Der Server variiert je nach TLD, sodass eine Liste mit 100 Domains über verschiedene Endungen bis zu 20 verschiedene Server erfordern kann. Und die Klartext-Ausgabe ist schwierig zuverlässig zu parsen. RDAP löst die letzten beiden Probleme, hat aber seine eigenen Rate-Limits. Dieser Artikel deckt drei Ansätze in aufsteigender Komplexität ab: ein Web-Tool, ein Bash-Skript mit Rate-Limiting und ein Python-RDAP-Skript. Die richtige Wahl hängt von Ihrem Volumen ab und davon, ob Sie die Ergebnisse einmalig oder fortlaufend benötigen.

Das Rate-Limiting-Problem

Bevor Sie nach einer Lösung greifen, verstehen Sie, warum eine naive Schleife nicht funktioniert:

  • Die meisten WHOIS-Server limitieren auf 1-5 Anfragen pro Sekunde pro IP. Übersteigen Sie das, folgt eine temporäre Sperre, typischerweise 1 Stunde, manchmal 24 Stunden.
  • Es gibt keinen Standard dafür, wie sich ein gesperrter Client verhalten soll. Manche Server geben eine Fehlermeldung zurück; andere hören einfach auf zu antworten.
  • RDAP handhabt Rate-Limiting sauberer: Server geben HTTP 429 mit einem Retry-After-Header zurück, der genau angibt, wie lange zu warten ist. Aber das Limit ist trotzdem real.
  • Eine Liste mit gemischten .com-, .net-, .io-, .de- und .at-Domains erfordert das Abfragen von fünf verschiedenen WHOIS-Servern, jeder mit eigenen Limits.

Die praktische Regel: Bei WHOIS 1 Anfrage pro 2 Sekunden einhalten, und jeden HTTP-429-Response von RDAP-Servern respektieren.

Rate-Limit erreicht? RDAP-Server müssen HTTP 429 mit einem Retry-After-Header zurückgeben. Respektieren Sie ihn, oder Ihre IP wird gesperrt.

Methode 1: Web-Tools für Bulk-Lookups

Für Nicht-Entwickler, die eine Liste hochladen und Ergebnisse erhalten möchten, ohne Code zu schreiben:

ToolKostenloses LimitAusgabeformatHinweise
WhoisXMLAPI500 Credits/MonatJSON, CSVGute API-Abdeckung
ViewDNS.info~100/TagHTML, CSVGrundlegend, keine API
DomainToolsMinimalCSV, JSONUmfassendste, teuer
Who.isSehr begrenztNur HTMLNur manuell

Die Einschränkung aller dieser Tools: Sie begrenzen Bulk-Abfragen bei kostenlosen Tarifen auf überschaubare Mengen, und die Preise steigen schnell über einige Hundert Domains pro Monat hinaus. Sie funktionieren für gelegentliche, moderate Volumen. Für alles Wiederkehrende oder über 500 Domains ist ein skriptbasierter Ansatz kostengünstiger.

Methode 2: Bash-Skript mit Rate-Limiting

Für Linux- und macOS-Nutzer, die eine einfache, abhängigkeitsfreie Lösung möchten. Speichern als bulk-whois.sh:

#!/bin/bash
# bulk-whois.sh: WHOIS für eine Domain-Liste abfragen
# Verwendung: ./bulk-whois.sh domains.txt

DELAY=2  # Sekunden zwischen Anfragen, unter Rate-Limits bleiben

INPUT="$1"
if [[ -z "$INPUT" ]]; then
  echo "Verwendung: $0 <domains-datei>"
  exit 1
fi

while IFS= read -r domain; do
  # Leerzeilen und Kommentare überspringen
  [[ -z "$domain" || "$domain" == \#* ]] && continue
  echo "=== $domain ==="
  whois "$domain" 2>/dev/null \
    | grep -E "Registrar:|Expir|Name Server|Domain Status"
  sleep "$DELAY"
done < "$INPUT"

Der grep -E-Filter extrahiert nur die nützlichen Zeilen, ohne ihn umfasst die rohe WHOIS-Ausgabe 50-100 Zeilen pro Domain. Eine domains.txt-Datei mit einer Domain pro Zeile erstellen:

github.com
stripe.com
# diese Zeile wird ignoriert
vercel.com
netlify.com

Ausgabe als CSV

Für die Integration mit Tabellenkalkulationen oder anderen Tools, hier eine Version, die eine CSV schreibt:

#!/bin/bash
OUTPUT="output.csv"
echo "domain,registrar,expiry,status" > "$OUTPUT"

while IFS= read -r domain; do
  [[ -z "$domain" || "$domain" == \#* ]] && continue
  
  raw=$(whois "$domain" 2>/dev/null)
  registrar=$(echo "$raw" | grep -i "^Registrar:" \
    | head -1 | cut -d: -f2- | xargs)
  expiry=$(echo "$raw" | grep -iE "Expiry|Expiration Date" \
    | head -1 | cut -d: -f2- | xargs)
  status=$(echo "$raw" | grep -i "^Domain Status:" \
    | head -1 | cut -d: -f2- | xargs)
  
  echo "$domain,$registrar,$expiry,$status" | tee -a "$OUTPUT"
  sleep 2
done < domains.txt

Ein wichtiger Vorbehalt: grep-Feldnamen variieren zwischen Registries. Expiry Date funktioniert für Verisign; Expiration Date kommt von manchen Registraren. Das Muster grep -iE "Expiry|Expiration Date" deckt beide ab, kann aber andere verpassen. Das ist die grundlegende Fragilität des WHOIS-Text-Parsings, deshalb wurde RDAP geschaffen.

Methode 3: RDAP-Abfragen via Skript

Der empfohlene Ansatz für Entwickler. RDAP liefert strukturiertes JSON, das Parsing ist zuverlässig und die Feldnamen sind unabhängig davon konsistent, welche Registry antwortet.

Den richtigen RDAP-Server pro TLD finden

Die IANA-Bootstrap-Datei ordnet TLDs zu RDAP-Server-URLs zu. Einmalig beim Start laden:

import json
import urllib.request
import time

# IANA-Bootstrap einmalig laden
with urllib.request.urlopen("https://data.iana.org/rdap/dns.json") as r:
    bootstrap = json.load(r)

def get_rdap_server(tld: str) -> str | None:
    for entry in bootstrap["services"]:
        if tld.lower() in [t.lower() for t in entry[0]]:
            return entry[1][0]
    return None

def rdap_lookup(domain: str) -> dict:
    tld = domain.split(".")[-1]
    server = get_rdap_server(tld)
    if not server:
        return {"error": f"Kein RDAP-Server für .{tld}"}
    
    url = f"{server.rstrip('/')}/domain/{domain}"
    try:
        with urllib.request.urlopen(url, timeout=10) as r:
            return json.load(r)
    except urllib.error.HTTPError as e:
        return {"error": f"HTTP {e.code}", "retry_after": e.headers.get("Retry-After")}
    except Exception as e:
        return {"error": str(e)}

domains = ["github.com", "stripe.com", "vercel.com", "netlify.com"]

for domain in domains:
    data = rdap_lookup(domain)
    
    if "error" in data:
        print(f"{domain}: FEHLER, {data['error']}")
        if data.get("retry_after"):
            wait = int(data["retry_after"])
            print(f"  Rate-limitiert. Warte {wait}s...")
            time.sleep(wait)
        continue
    
    # Ablaufdatum aus events-Array extrahieren
    expiry = next(
        (e["eventDate"] for e in data.get("events", [])
         if e["eventAction"] == "expiration"),
        "N/A"
    )
    status = ", ".join(data.get("status", []))
    
    print(f"{domain}: läuft ab am {expiry} | Status: {status}")
    time.sleep(1)  # 1 Req/s, konservativ für RDAP

Dieses Skript ist minimal. Für den Produktionseinsatz sollten Sie einen lokalen Cache der Bootstrap-Datei hinzufügen (sie ändert sich selten), exponentielles Backoff bei Wiederholungsversuchen und Logging. Das Skript oben schreibt auf stdout; bei Bedarf in eine Datei umleiten oder durch jq pipen.

Die Domain Sentinel API nutzen

Für Produktions-Workloads, bei denen Sie RDAP-Bootstrapping, Rate-Limiting-Logik und WHOIS-Fallback nicht selbst verwalten möchten, stellt Domain Sentinel eine API bereit, die all das übernimmt. Eine einzelne authentifizierte Anfrage liefert strukturierte Daten, unabhängig davon, ob der TLD über RDAP oder WHOIS bedient wird. Details zu Endpunkten und Authentifizierung finden Sie in der Domain Sentinel API-Dokumentation.

Ein Domain-Portfolio kontinuierlich überwachen

Es gibt einen wichtigen Unterschied zwischen Bulk-Lookup und kontinuierlicher Überwachung:

Bulk-Lookup liefert eine Momentaufnahme der aktuellen Daten zum Zeitpunkt der Abfrage. Einmal ausführen, Ergebnisse erhalten, weitermachen.

Kontinuierliche Überwachung bedeutet, jede Domain regelmäßig zu prüfen und Sie zu benachrichtigen, wenn sich etwas ändert. Ablaufdatum naht, Nameserver geändert, EPP-Status verschoben.

Bulk-Lookup gibt Ihnen eine Momentaufnahme. Domain Sentinel gibt Ihnen einen kontinuierlichen Feed mit Benachrichtigungen.

Für ein Portfolio von 50 Domains über mehrere Unternehmen oder Kunden hinweg ist der operative Arbeitsablauf: die Liste in Domain Sentinel importieren, Alarmschwellen konfigurieren (60 Tage, 30 Tage, 7 Tage vor Ablauf) und Benachrichtigungen pro Domain erhalten, anstatt Skripte manuell auszuführen. Jede erkannte Änderung wird mit Zeitstempel protokolliert, was auch einen Prüfpfad ergibt.

Die Entscheidung hängt von Volumen und Häufigkeit ab: Für 10-50 Domains, die gelegentlich geprüft werden, reichen ein Web-Tool oder ein Bash-Skript aus. Für 50-500 Domains, die regelmäßig geprüft werden, ist das Python-RDAP-Skript praktisch. Für 500 oder mehr Domains oder jedes Portfolio, das kontinuierliche Überwachung statt einmaliger Prüfungen braucht, ist ein dedizierter Dienst die richtige Antwort.

Fangen Sie mit einer Domain an, die Ihnen wichtig ist

Kostenlos nachschlagen. Für Benachrichtigungen bei Statusänderungen oder Ablauf einfach ein Konto erstellen. Dauert 30 Sekunden.