Respuesta rápida
¿Cómo debe un scraper manejar las respuestas 403, 429 y CAPTCHA?
Trátalos como señales, no como obstáculos. Con un 429, espera Retry-After y reduce tu tasa en ese host. Con un 403, reintenta una vez tras una pausa, luego para y revisa las reglas del sitio. Con un CAPTCHA, detén ese host: no lo resuelvas automáticamente. CrawlRelay proxies residenciales, de 0,50 US$/GB, distribuyen la carga y establecen ubicación; no son una forma de evadir la decisión del sitio. Sin KYC. Paga con criptomonedas.
Las tres señales de un vistazo
| 429 Demasiadas Solicitudes | Vas demasiado rápido. Respeta Retry-After, baja la marcha, reduce la concurrencia por host |
|---|---|
| 403 Forbidden | Se rechaza esta solicitud. Un reintento tras una pausa, luego para y revisa |
| CAPTCHA o página de desafío | El sitio quiere saber si eres humano. Detén el host y reduce la velocidad |
| Estándar para reglas de crawling | robots.txt, RFC 9309; Crawl-delay es una extensión común |
| Lo que no soportamos | Resolución de CAPTCHA, plugins stealth, falsificación de fingerprint |
¿Qué le dice cada señal a mi crawler?
- 429 es la señal más amable: el contenido está disponible, pero no a tu ritmo. El RFC 6585 lo define, a menudo con un encabezado
Retry-Afterque dice cuándo volver. - 403 es un rechazo de esta solicitud. Puede ser solucionable (país incorrecto, encabezados faltantes, muy rápido) o final (el sitio no permite acceso automatizado a ese contenido).
- Un CAPTCHA o página de desafío, a menudo con estado 403 o 503, significa que la gestión de bots del sitio duda de tu tráfico. Es una escalada: el siguiente paso tras ignorar 429.
Las tres son señales crecientes. Los sitios que ven ignorados sus 429 escalan a 403 y desafíos, luego a bloqueos largos en rangos completos de IP, lo que perjudica a todos los usuarios de esos rangos.
¿Qué debe hacer mi crawler ante cada señal?
| Señal | Primera respuesta | Si persiste | Detener cuando |
|---|---|---|---|
| 429 | Esperar Retry-After o retroceder exponencialmente con jitter | Reducir a la mitad la concurrencia en ese host | Retry-After crece o los 429 persisten a una solicitud por vez |
| 403 | Un reintento tras una pausa, mismo país | Comparar con un navegador desde el mismo país; revisar robots.txt y términos | Un segundo 403 en el mismo patrón URL |
| CAPTCHA / desafío | Pausar el host varios minutos | Reanudar a una tasa mucho menor | El desafío vuelve en baja tasa: el sitio no quiere acceso automatizado |
| 503 con Retry-After | Esperar lo indicado | Pausar el host | La mayoría de peticiones falla más de unos minutos |
¿Cómo construir un crawler que responda correctamente?
Pon las reglas en el fetcher, no en cada spider. Este envía una solicitud a la vez por host, respeta robots.txt y su Crawl-delay, espera Retry-After, y deja de pedir a un host tras tres rechazos consecutivos. Trata un 4xx en robots.txt como permiso y un 5xx como negación total, según RFC 9309.
import time
import urllib.robotparser
from urllib.parse import urlsplit
import requests
PROXY = "http://USERNAME-country-us:[email protected]:7777"
USER_AGENT = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"
class PoliteFetcher:
"""One request at a time per host; robots.txt, Crawl-delay and Retry-After honoured."""
def __init__(self, min_interval=1.0, max_refusals=3):
self.min_interval, self.max_refusals = min_interval, max_refusals
self.http = requests.Session()
self.http.proxies = {"http": PROXY, "https": PROXY}
self.http.headers["User-Agent"] = USER_AGENT
self.robots, self.next_time, self.refusals = {}, {}, {}
def _robots(self, root):
if root not in self.robots:
rp = urllib.robotparser.RobotFileParser(root + "/robots.txt")
try:
r = self.http.get(root + "/robots.txt", timeout=(10, 30))
if r.status_code >= 500:
rp.parse(["User-agent: *", "Disallow: /"]) # unreachable: assume disallow
else:
rp.parse(r.text.splitlines() if r.status_code == 200 else []) # 4xx: allowed
except requests.RequestException:
rp.parse(["User-agent: *", "Disallow: /"])
self.robots[root] = rp
return self.robots[root]
def get(self, url):
scheme, host = urlsplit(url)[:2]
if self.refusals.get(host, 0) >= self.max_refusals:
return None # this host said no: stop asking
rp = self._robots("%s://%s" % (scheme, host))
if not rp.can_fetch(USER_AGENT, url):
return None
delay = max(self.min_interval, rp.crawl_delay(USER_AGENT) or 0)
wait = self.next_time.get(host, 0) - time.monotonic()
if wait > 0:
time.sleep(wait)
r = self.http.get(url, timeout=(10, 30))
pause = delay
if r.status_code in (429, 503):
retry_after = r.headers.get("Retry-After", "")
pause = max(delay, int(retry_after) if retry_after.isdigit() else 60)
refused = r.status_code in (403, 429) or "captcha" in r.text[:5000].lower()
self.refusals[host] = self.refusals.get(host, 0) + 1 if refused else 0
self.next_time[host] = time.monotonic() + pause
return r
fetcher = PoliteFetcher()
resp = fetcher.get("https://example.com/")
print(resp.status_code if resp is not None else "skipped")¿Qué arregla legítimamente un 403?
Varias causas de 403 son culpa tuya y arreglarlas es correcto:
- País incorrecto. Muchos sitios sirven solo una región. Apunta al país con
-country-<code>. - Encabezados incompletos. Envía
Accept,Accept-Languagey un user agent honesto con URL de contacto. Un user agent tipo navegador en un cliente HTTP simple es inconsistente y suele rechazarse. - Tu propio ritmo. Un 403 que empieza tras N peticiones es problema de tasa; reduce la velocidad.
Lo que no es solución: rotar user agents para parecer muchos usuarios, falsificar fingerprints o cambiar IPs para evadir un bloqueo intencional. Si un sitio filtra rangos de hosting para evitar tráfico automático, una IP residencial no autoriza ese acceso.
¿Por qué no simplemente resolver los CAPTCHA?
Porque un CAPTCHA es el sitio haciéndote una pregunta a la que responderías falsamente. Resolverlos automáticamente convierte a un rastreador educado en una herramienta diseñada para vencer un control de acceso, lo que aumenta tu riesgo legal: los casos de EE. UU. en 2026 sobre scraping de búsquedas, Google v. SerpApi y Reddit v. SerpApi entre otros, se basan en afirmaciones de que los demandados evadieron un sistema anti-bots bajo la regla antielusión del DMCA. Los tribunales no han resuelto la cuestión, pero el riesgo es real.
CrawlRelay no soporta la resolución de CAPTCHA ni la evasión de detección de bots, y su Política de Uso Aceptable los prohíbe a través del gateway. Si necesitas datos detrás de un desafío, pide acceso al sitio, usa su API o licencia los datos.
¿Cuándo debo contactar al sitio en su lugar?
Cuando necesites más de lo que permiten sus valores por defecto. Muchos sitios ofrecen una API, un flujo de datos, un programa de socios o simplemente un límite más alto para un rastreador que se identifique y explique su propósito. Pon una URL de contacto en tu user agent, mantén una página que describa tu crawler y cómo optar por no participar, y responde rápido a reportes de abuso. Un rastreador accesible recibe advertencias antes de bloqueos.
403, 429 y CAPTCHA: preguntas
¿Los proxies residenciales evitan los CAPTCHA?
No cuentes con ello. Un proxy residencial cambia la IP que ve el sitio, no lo que hace tu crawler: los CAPTCHA causados por tu ritmo o comportamiento siguen ahí, y están diseñados para eso. Si los desafíos continúan con una tasa baja de solicitudes, el sitio no quiere acceso automatizado a ese contenido.
¿Cuánto debo esperar tras un 429 sin Retry-After?
Empieza unos segundos y duplica la espera tras cada nuevo 429, añadiendo un extra aleatorio y con un máximo de alrededor de un minuto. Cuando las solicitudes tengan éxito otra vez, reanuda a un ritmo menor que el que causó el 429, y súbelo lentamente mientras la tasa de error se mantenga estable.
¿Está permitido rotar IPs para evitar límites de tasa?
La rotación distribuye la carga entre salidas y permite elegir ubicaciones, lo cual es normal. Usar la rotación para mantenerse por debajo del límite por IP mientras se mantiene una tasa que el sitio rechazó es evasión. La mayoría de las políticas de uso la prohíben, al igual que nuestra Política de Uso Aceptable.
¿Qué user agent debe enviar mi scraper?
El tuyo propio: un nombre, una versión y una URL que explique el crawler y cómo contactarte, como ExampleCrawler/1.0 (+https://example.com/crawler-info). No uses nombres de otros crawlers como Googlebot o GPTBot.
Fuentes (4)
- RFC 9309: Protocolo de Exclusión de Robots — IETF (2022-09)
- RFC 6585: Códigos de Estado HTTP adicionales (429) — IETF (2012-04)
- Reddit v. SerpApi LLC — Loeb & Loeb (2026-08)
- Google v. SerpApi: el tribunal aceptó nuestra moción para desestimar — SerpApi (2026-07-21)
Proxies residenciales para crawlers educados
1,50 US$ por 1 GB, 0,50 US$/GB desde 50 GB.