Cloudflare "Un momento" en Python: Por qué requests falla

La página 'Un momento...' de Cloudflare es un desafío de JavaScript, y Python requests no puede ejecutar JavaScript. Aquí te mostramos cómo detectarlo, por qué afecta más a los servidores que a las laptops, por qué los trucos al estilo cloudscraper dejaron de ser suficientes y qué logró pasar en nuestra prueba del 29 de septiembre de 2026.

'Un momento...' es la página de desafío de Cloudflare. Solicita al cliente ejecutar JavaScript y demostrar que es un navegador antes de que el sitio responda. Python requests no puede ejecutar JavaScript, y desde un servidor de centro de datos su IP y el apretón de manos TLS ya parecen automatizados. Lo que pasa es un navegador real en una IP limpia, o un desbloqueador web que ejecute uno.

Esta guía muestra cómo detectar el desafío en Python, por qué el mismo script pasa en tu laptop y falla en tu servidor, por qué los trucos de la era cloudscraper dejaron de ser suficientes y qué realmente logró pasar cuando lo probamos el 29 de septiembre de 2026. Eso incluye el sitio donde nada de lo que intentamos pasó de 'Un momento'.

Qué es realmente la página "Un momento..."

Cloudflare la llama una Página de Desafío intersticial: una puerta de página completa entre el visitante y el sitio mientras Cloudflare decide si el visitante es automatizado. Su documentación sobre páginas de desafío describe tres tipos. Un desafío no interactivo solo necesita que el navegador ejecute el JavaScript inyectado. Un desafío gestionado permite a Cloudflare elegir el tipo de desafío a partir de las señales de la solicitud. Un desafío interactivo pide al visitante que haga algo. Cuando la verificación pasa, la solicitud original continúa al sitio y el navegador obtiene una cookie cf_clearance que le permite saltarse la puerta por un tiempo.

Un cliente HTTP de Python nunca llega tan lejos. Descarga la página de desafío, no tiene motor para ejecutar el script y te entrega el HTML de la puerta en lugar de la página que solicitaste.

Por qué el desafío regresa como un 403, y cómo detectarlo

En nuestra prueba, cada página de desafío llegó con el estado 403, por lo que raise_for_status() lanza 403 Client Error: Forbidden y la gente busca 'cloudflare un momento 403'. El estado por sí solo no puede distinguir un desafío de cualquier otra negativa. La señal confiable es un encabezado: Cloudflare documenta que una respuesta desafiada lleva cf-mitigated: challenge, sea cual sea el recurso que solicitaste. Verifica eso primero, luego el título como respaldo:

import re
import requests

URL = "https://www.glassdoor.com/Reviews/Google-Reviews-E9079.htm"
HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
        "(KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36"
    ),
    "Accept-Language": "en-US,en;q=0.9",
}


def title_of(html: str) -> str:
    m = re.search(r"<title[^>]*>(.*?)</title>", html, re.I | re.S)
    return m.group(1).strip() if m else ""


def is_cloudflare_challenge(r: requests.Response) -> bool:
    if r.headers.get("cf-mitigated") == "challenge":      # documented by Cloudflare
        return True
    if "just a moment" in title_of(r.text).lower():
        return True
    return "enable javascript and cookies to continue" in r.text[:20000].lower()


r = requests.get(URL, headers=HEADERS, timeout=30)
print(r.status_code, is_cloudflare_challenge(r), title_of(r.text))
# 29 Sep 2026, plain request through a residential proxy (US exit):
# 403, body asking to 'Enable JavaScript and cookies to continue'

No reintentes una solicitud desafiada en un bucle cerrado con el mismo cliente. Cada reintento obtiene la misma puerta, y algunos sitios responden a fallas repetidas con reglas más estrictas. Así es como los scrapers terminan atrapados en un bucle de 'Un momento'.

"Enable JavaScript and cookies to continue" y "tu navegador no soporta JavaScript"

Estas cadenas son el texto de respaldo de una página de desafío, mostrado a clientes que no ejecutan su script. Cuando Python requests te muestra uno de ellos, el sitio no se está quejando de tus encabezados. Te está diciendo, literalmente, que necesita un motor de JavaScript y un contenedor de cookies que mantenga lo que el script establece.

Eso es exactamente lo que nuestra ejecución residencial simple recibió de Indeed y Glassdoor: un 403 con 'Enable JavaScript and cookies to continue', desde una IP doméstica limpia. Agregar un User-Agent de Chrome, un encabezado Accept-Language o un Referer no cambia nada, porque la página no los está leyendo para decidir. Está esperando que el script se ejecute.

Por qué tu scraper funciona localmente pero es bloqueado por Cloudflare en un servidor

Esta es la versión más común de la queja: el script funciona en una laptop, luego recibe 'Un momento' tan pronto como se ejecuta en una VM en la nube. Dos cosas cambian entre esas máquinas.

La columna residencial de nuestra prueba muestra el límite de corregir solo la IP. Zillow y Leboncoin sirvieron la página real a una solicitud simple a través de un proxy residencial. Indeed y Glassdoor aún respondieron con el desafío de JavaScript. Tu laptop puede chocar con la misma pared en un sitio más estricto. Simplemente lo hace con menos frecuencia.

Por qué un scraper en Python pasa Cloudflare desde una laptop y recibe el desafío Un momento desde un servidor en la nube: IP doméstica versus IP de alojamiento, misma huella digital TLS de Python, sin motor de JavaScript en ambos casos
Mismo script, dos máquinas. La IP cambia; el apretón de manos TLS de Python y el motor de JavaScript ausente no.

Por qué los trucos de la era cloudscraper dejan de funcionar

cloudscraper fue construido para la antigua página 'I'm Under Attack' de Cloudflare. Esa página principalmente verificaba si el cliente podía ejecutar un cálculo de JavaScript, por lo que la biblioteca obtenía el desafío, resolvía el script en un intérprete incrustado, enviaba la respuesta de vuelta y mantenía la cookie, todo sobre requests. Durante mucho tiempo eso fue suficiente, y es la razón por la que 'alternativa a cloudscraper' es ahora una búsqueda que la gente hace.

Varias cosas han cambiado desde entonces, y no dependen de ninguna versión de biblioteca en particular:

A partir del 29 de septiembre de 2026, el último push del repositorio de cloudscraper fue en junio de 2025. Eso no es un veredicto sobre ningún sitio en particular, y no lo evaluamos para este artículo. Significa que deberías probarlo contra tus propios objetivos en lugar de asumir que funciona. Las alternativas solucionan cada una parte del problema. curl_cffi reproduce un apretón de manos TLS de navegador pero no ejecuta JavaScript. Playwright u otro navegador real ejecuta el desafío pero aún necesita una IP limpia, y es pesado para operar a gran escala. El desbloqueador combina los dos y te dice cuándo ninguno funcionó.

Qué pasa: la ruta del desbloqueador web

El Web Unlocker de QuantumProxies.io maneja un GET en etapas. Primero, hasta tres intentos TLS, cada uno en una salida residencial fresca bajo una huella digital de navegador diferente. Si cada intento regresa desafiado, escala a un navegador sin cabeza que ejecuta el desafío. Si la página sigue bloqueada después de eso, obtienes un estado de error con x-qp-unlocker-blocked y una clase de bloqueo, nunca una página de desafío disfrazada de 200. Desde Python es una configuración de proxy:

import os
import time
import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

user = os.environ["QP_UNLOCK_USER"] + "-country-us"          # unlock-XXXXXXXX-country-us
PROXY = f"http://{user}:{os.environ['QP_UNLOCK_PASSWORD']}@unlock.quantumproxies.io:9000"

s = requests.Session()
s.proxies = {"http": PROXY, "https": PROXY}
s.verify = False                     # or the unlocker CA file from /api/v1/scraper/unlock/ca
s.headers["x-qp-session"] = "glassdoor-01"   # same value on every call: same exit, reusable clearance

for attempt in (1, 2):               # same page twice here; in practice, the next page
    t0 = time.monotonic()
    r = s.get(URL, timeout=120)
    print(attempt, r.status_code, f"{time.monotonic() - t0:.1f}s",
          "rendered:", r.headers.get("x-qp-unlocker-rendered"),
          "clearance:", r.headers.get("x-qp-clearance"),
          "block:", r.headers.get("x-qp-block-class"))

Los encabezados x-qp-* son leídos por el desbloqueador y nunca se reenvían al sitio. Si prefieres no lidiar con el certificado en absoluto, el endpoint REST POST https://app.quantumproxies.io/api/v1/scraper/unlock toma la URL en un cuerpo JSON con tu clave API y devuelve blocked, blockClass y vendor en la respuesta. Nuestro tutorial de la API del desbloqueador web recorre ambos.

Medido: dos muros al estilo Cloudflare que pasaron, uno que no

Medido el 29 de septiembre de 2026. Las solicitudes simples fueron curl con un User-Agent de Chrome, desde un servidor de centro de datos en Frankfurt y a través de un proxy residencial con una salida en EE.UU. El desbloqueador utilizó el nivel residencial con una salida en EE.UU. Los tiempos son de reloj de pared para una solicitud.

SitioSimple, servidor de centro de datosSimple, proxy residencialWeb Unlocker
Glassdoor (reseñas de empresas)403, página de 'Seguridad'403, 'Enable JavaScript and cookies to continue'200, 2 intentos + navegador sin cabeza, 17.2 s
Indeed (búsqueda de empleo)403, página de 'Verificación de Seguridad'403, 'Enable JavaScript and cookies to continue'200, 1 intento, sin navegador, 2.6 s
StockX (página de producto)403403403 'Un momento...', x-qp-block-class js_challenge, vendor cloudflare, 47.8 s
DoorDash (página de ciudad)403403403, x-qp-block-class ip_reputation, vendor cloudflare

Glassdoor es el camino completo. Dos intentos TLS fueron desafiados, luego el navegador sin cabeza ejecutó el desafío y devolvió la página de reseñas. Indeed es el interesante: el desafío que la solicitud residencial simple recibió nunca apareció para el primer intento del desbloqueador. Una huella digital TLS de navegador en una salida residencial fresca fue suficiente, sin un navegador.

StockX es el fracaso honesto. El desbloqueador escaló, gastó 47.8 segundos, y la página seguía siendo 'Un momento...'. Regresó como un 403 con x-qp-block-class: js_challenge y x-qp-vendor: cloudflare, no como un 200 que tu analizador habría intentado leer. DoorDash, también detrás de Cloudflare, fue rechazado en la IP (ip_reputation) en lugar de desafiado. Algunas configuraciones de Cloudflare no se abren para ninguna de las herramientas en este artículo, y es mejor saberlo por un encabezado que por un conjunto de datos vacío.

Supera los desafíos de JavaScript con el Web Unlocker

Reutilizando la autorización: por qué la segunda solicitud es rápida

La escalada del navegador es la parte lenta, y no quieres pagar por ella en cada página. Cuando el navegador sin cabeza pasa un desafío, gana una autorización. Envía el mismo valor x-qp-session, o mantén el mismo -session-&lt;id&gt; en el nombre de usuario del proxy, en las siguientes solicitudes y salen desde la misma salida, reutilizando esa autorización en lugar de ejecutar el navegador nuevamente. El encabezado x-qp-clearance te dice qué pasó en cada llamada: minted cuando se ganó una nueva autorización, hit cuando se reutilizó una almacenada, miss cuando no había nada para reutilizar.

En una prueba de Glassdoor el 29 de septiembre de 2026, con la sesión fijada en el nombre de usuario del proxy y dos conexiones separadas, la primera solicitud pasó por el navegador en 14.0 segundos (minted) y la segunda regresó en 1.4 segundos (hit). La fijación importa debido a cómo Cloudflare vincula la autorización: está ligada al visitante y dispositivo que la ganó, y permanece válida durante el tiempo que el sitio configura a menos que Cloudflare decida que la sesión parece sospechosa. Cambia la salida o la huella digital y eres un nuevo visitante nuevamente.

Cronología de dos solicitudes en una sesión de desbloqueador fijada: la primera escala a un navegador sin cabeza y acuña una autorización de Cloudflare en 14.0 segundos, la segunda la reutiliza y regresa en 1.4 segundos
La primera solicitud paga por el navegador; las solicitudes posteriores en la misma sesión fijada reutilizan la autorización.

Cuando las solicitudes simples aún funcionan en un sitio de Cloudflare

Muchos sitios funcionan detrás de Cloudflare solo como un CDN, o con reglas de bots que permiten el tráfico ordinario, y las solicitudes simples funcionan en ellos. Estar 'en Cloudflare' no es una razón para recurrir a un navegador. La señal es la respuesta. Si no hay un encabezado cf-mitigated: challenge, ningún título 'Un momento' y ningún 403, mantén la solicitud simple, y escala solo las URL que realmente son desafiadas. El ayudante de primero simple en nuestro tutorial hace exactamente eso.

Dos problemas vecinos tienen sus propias guías. Una página que dice 'Error 1020 Acceso denegado' es una regla de firewall que te rechaza, no un desafío, y ninguna cantidad de JavaScript lo soluciona; consulta qué desencadena el error 1020 de Cloudflare y qué lo soluciona. Para la imagen más amplia de las defensas de Cloudflare más allá de Python, lee cómo superar los desafíos de Cloudflare en 2026. Si la página detrás del muro es Glassdoor, nuestra guía para extraer salarios y reseñas de Glassdoor cubre el lado de los datos.

Preguntas frecuentes

¿Por qué mi scraper funciona localmente pero es bloqueado por Cloudflare en la nube?

Porque la IP cambia. En casa tu script sale desde una dirección de ISP residencial; en una VM en la nube sale desde un rango de alojamiento que las defensas contra bots desconfían a primera vista. El apretón de manos TLS de Python es el mismo en ambos, y en un sitio más estricto se desafía incluso desde casa. En nuestra prueba, una IP residencial por sí sola no pasó Indeed o Glassdoor.

¿Por qué la página "Un momento" de Cloudflare devuelve un 403?

La página de desafío se sirve en lugar de la página que solicitaste, y en nuestra prueba vino con el estado 403, por lo que requests lanza '403 Client Error: Forbidden'. El estado no es específico de los desafíos. Verifica el encabezado de respuesta cf-mitigated, que Cloudflare documenta como configurado en challenge en cada respuesta de Página de Desafío, o el título 'Un momento'.

¿cloudscraper sigue funcionando, y cuál es una buena alternativa?

Puede que aún funcione en sitios con configuraciones indulgentes, así que pruébalo contra tus objetivos. Funciona sobre la pila TLS de Python y resuelve scripts en un intérprete, mientras que los desafíos actuales también miran el apretón de manos y el entorno del navegador. Alternativas: curl_cffi para un apretón de manos de navegador, un navegador real para el JavaScript, o un desbloqueador web que hace ambos.

¿Puede Python requests pasar un desafío de Cloudflare por sí solo?

No. requests no ejecuta JavaScript, por lo que no puede completar un desafío que depende de ejecutar el script de la página. Puede obtener páginas de sitios de Cloudflare que no te estén desafiando. Una vez que aparece cf-mitigated: challenge, necesitas un navegador real, directamente o a través de un servicio que ejecute uno, y preferiblemente una IP residencial limpia.

¿Puede el desbloqueador web resolver Cloudflare Turnstile u otros captchas?

Los desafíos de JavaScript no interactivos son respondidos por la escalada del navegador sin cabeza. Los desafíos interactivos que necesitan una acción humana, como una casilla de verificación, deslizador, presionar y mantener o cuadrícula de imágenes, no se resuelven. La solicitud falla en lugar de devolver el desafío como un 200, y el endpoint REST lo etiqueta con la clase de bloqueo captcha y el proveedor, para que tu código pueda decidir si omitir la URL, ralentizar o intentar más tarde.

¿Cuánto dura una autorización de Cloudflare?

Tanto como el sitio lo configure. Cloudflare llama a la configuración Challenge Passage, y la autorización puede terminar temprano si Cloudflare decide que la sesión parece sospechosa. La cookie cf_clearance está vinculada al visitante y dispositivo que la ganó, por lo que solo ayuda si las solicitudes posteriores mantienen la misma salida y huella digital, que es lo que hace fijar x-qp-session.

La versión corta: 'Un momento...' pide un navegador, por lo que ningún truco de encabezado en requests lo satisfará. Detéctalo con cf-mitigated, mantén las solicitudes simples para todo lo que no sea desafiado, envía las URL desafiadas a través de algo que ejecute un navegador real desde una IP limpia, y fija una sesión para que pagues por ese navegador una vez en lugar de en cada página.

Prueba el Web Unlocker en salidas residenciales