Bulk WHOIS lookup: herramientas, scripts y metodos de API

Como consultar WHOIS o RDAP para decenas de dominios a la vez. Herramientas web, script bash con rate limiting y enfoque RDAP en Python.

Consultar WHOIS o RDAP para una lista de dominios no es trivial. El protocolo WHOIS impone límites estrictos de peticiones por IP, superarlos provoca que tu dirección quede bloqueada durante una hora o más. El servidor varía según el TLD, así que una lista de 100 dominios con diferentes extensiones puede requerir consultar 20 servidores distintos. Además, la salida en texto plano es difícil de parsear de forma fiable. RDAP resuelve los dos últimos problemas pero tiene sus propios límites. Este artículo cubre tres enfoques en orden creciente de complejidad: una herramienta web, un script bash con rate limiting, y un script Python para RDAP. La elección correcta depende de tu volumen y de si necesitas los resultados una vez o de forma continua.

El problema del rate limiting

Antes de elegir una solución, entiende por qué un simple bucle no funciona:

  • La mayoría de los servidores WHOIS limitan a 1-5 peticiones por segundo por IP. Superarlo activa un bloqueo temporal, normalmente 1 hora, a veces 24 horas.
  • No hay estándar sobre cómo debe comportarse un cliente bloqueado. Algunos servidores devuelven un mensaje de error; otros simplemente dejan de responder.
  • RDAP gestiona el rate limiting de forma más limpia: los servidores devuelven HTTP 429 con una cabecera Retry-After que especifica exactamente cuánto tiempo esperar. Pero el límite sigue siendo real.
  • Una lista que mezcla .com, .net, .io, .es y .mx requiere consultar cinco servidores WHOIS diferentes, cada uno con sus propios límites.

La regla práctica: mantente en 1 petición cada 2 segundos para WHOIS, y respeta cada respuesta HTTP 429 que recibas de servidores RDAP.

¿Rate limit alcanzado? Los servidores RDAP deben devolver HTTP 429 con una cabecera Retry-After. Respétala, o tu IP quedará bloqueada.

Método 1: Herramientas web para bulk lookup

Para quienes no son desarrolladores y quieren subir una lista y obtener resultados sin escribir código:

HerramientaLímite gratuitoFormato de salidaNotas
WhoisXMLAPI500 créditos/mesJSON, CSVBuena cobertura API
ViewDNS.info~100/díaHTML, CSVBásico, sin API
DomainToolsMínimoCSV, JSONEl más completo, caro
Who.isMuy limitadoSolo HTMLSolo manual

La limitación de todas estas herramientas: limitan las consultas bulk en el nivel gratuito a volúmenes razonables, y el precio escala rápidamente por encima de algunos cientos de dominios al mes. Son válidas para necesidades puntuales de volumen moderado. Para cualquier uso recurrente o por encima de 500 dominios, un enfoque basado en scripts es más rentable.

Método 2: Script bash con rate limiting

Para usuarios de Linux y macOS que quieren una solución simple sin dependencias. Guarda esto como bulk-whois.sh:

#!/bin/bash
# bulk-whois.sh: consultar WHOIS para una lista de dominios
# Uso: ./bulk-whois.sh domains.txt

DELAY=2  # segundos entre peticiones, mantenerse bajo los límites

INPUT="$1"
if [[ -z "$INPUT" ]]; then
  echo "Uso: $0 <archivo-dominios>"
  exit 1
fi

while IFS= read -r domain; do
  # ignorar líneas vacías y comentarios
  [[ -z "$domain" || "$domain" == \#* ]] && continue
  echo "=== $domain ==="
  whois "$domain" 2>/dev/null \
    | grep -E "Registrar:|Expir|Name Server|Domain Status"
  sleep "$DELAY"
done < "$INPUT"

El filtro grep -E extrae solo las líneas útiles, sin él, la salida WHOIS en bruto tiene 50-100 líneas por dominio. Crea un archivo domains.txt con un dominio por línea:

github.com
stripe.com
# esta línea se ignora
vercel.com
netlify.com

Exportar a CSV

Para integración con hojas de cálculo u otras herramientas, aquí una versión que escribe un CSV:

#!/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

Una advertencia importante: los nombres de campo de grep varían entre registros. Expiry Date funciona para Verisign; Expiration Date es lo que devuelven algunos registradores. El patrón grep -iE "Expiry|Expiration Date" cubre ambos pero puede perderse otros. Esta es la fragilidad fundamental del parsing de texto WHOIS, por eso se creó RDAP.

Método 3: Consultas RDAP mediante script

El enfoque recomendado para desarrolladores. RDAP devuelve JSON estructurado, por lo que el parsing es fiable y los nombres de campo son consistentes independientemente del registro que responda.

Encontrar el servidor RDAP correcto por TLD

El archivo bootstrap de IANA mapea TLDs a URLs de servidores RDAP. Cárgalo una vez al inicio:

import json
import urllib.request
import time

# Cargar el bootstrap de IANA una vez al inicio
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"No hay servidor RDAP para .{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}: ERROR, {data['error']}")
        if data.get("retry_after"):
            wait = int(data["retry_after"])
            print(f"  Rate limitado. Esperando {wait}s...")
            time.sleep(wait)
        continue
    
    # Extraer fecha de vencimiento del array events
    expiry = next(
        (e["eventDate"] for e in data.get("events", [])
         if e["eventAction"] == "expiration"),
        "N/A"
    )
    status = ", ".join(data.get("status", []))
    
    print(f"{domain}: vence el {expiry} | estado: {status}")
    time.sleep(1)  # 1 req/s, conservador para RDAP

Este script es mínimo. Para uso en producción, añade una caché local del archivo bootstrap (cambia con poca frecuencia), backoff exponencial en los reintentos y logging. El script anterior escribe en stdout; redirige a un archivo o pasa por jq según sea necesario.

Usar la API de Domain Sentinel

Para cargas de trabajo en producción donde no quieres mantener tú mismo el bootstrapping RDAP, la lógica de rate limiting y el fallback a WHOIS, Domain Sentinel expone una API que gestiona todo esto. Una única petición autenticada devuelve datos estructurados independientemente de si el TLD es servido por RDAP o WHOIS. Consulta la documentación de la API de Domain Sentinel para los detalles de los endpoints y la autenticación.

Monitorizar un portfolio de dominios de forma continua

Hay una distinción importante entre el bulk lookup y la monitorización continua:

El bulk lookup te da una instantánea de los datos actuales en el momento de la consulta. Lo ejecutas una vez, obtienes los resultados, y sigues adelante.

La monitorización continua significa revisar cada dominio regularmente y alertarte cuando algo cambia, fecha de vencimiento próxima, nameservers cambiados, estado EPP modificado.

El bulk lookup te da una instantánea. Domain Sentinel te da un feed continuo con alertas.

Para un portfolio de 50 dominios distribuidos entre varios negocios o clientes, el flujo de trabajo operativo es: importar la lista en Domain Sentinel, configurar los umbrales de alerta (60 días, 30 días, 7 días antes del vencimiento) y recibir notificaciones por dominio en lugar de ejecutar scripts manualmente. Cada cambio detectado queda registrado con marca de tiempo, lo que también proporciona una pista de auditoría.

La decisión depende del volumen y la frecuencia: para 10-50 dominios comprobados ocasionalmente, una herramienta web o un script bash es suficiente. Para 50-500 dominios comprobados regularmente, el script Python RDAP es práctico. Para 500 o más dominios, o cualquier portfolio que necesite monitorización continua en lugar de comprobaciones puntuales, un servicio dedicado es la respuesta correcta.

Empieza con un dominio que te importe

Búscalo gratis. Para recibir alertas cuando el estado cambie o la expiración se acerque, crea una cuenta. Son 30 segundos.