Cloudflare "Just a Moment" на Python: Почему requests не работает
Страница Cloudflare 'Just a moment...' представляет собой JavaScript-задачу, и Python requests не может выполнять JavaScript. Вот как её обнаружить, почему она сильнее нагружает серверы, чем ноутбуки, почему трюки в стиле cloudscraper перестали быть достаточными, и что прошло в нашем тесте 29 сентября 2026 года.
'Just a moment...' — это страница с задачей от Cloudflare. Она просит клиента выполнить JavaScript и доказать, что это браузер, прежде чем сайт ответит. Python requests не может выполнять JavaScript, и с IP-адреса датацентра его IP и TLS рукопожатие уже выглядят автоматизированными. То, что проходит, — это реальный браузер на чистом IP или веб-разблокировщик, который его использует.
Это руководство показывает, как обнаружить задачу на Python, почему тот же скрипт проходит на вашем ноутбуке и не проходит на вашем сервере, почему трюки эпохи cloudscraper перестали быть достаточными, и что на самом деле прошло, когда мы тестировали это 29 сентября 2026 года. Это включает сайт, где ничего из того, что мы пробовали, не прошло 'Just a moment'.
- Это задача, а не ошибка. Cloudflare маркирует ответы с задачей заголовком
cf-mitigated: challenge. В нашем тесте они приходили как HTTP 403. - Заголовки не исправят это. 'Enable JavaScript and cookies to continue' означает, что странице нужен JavaScript-движок. Ни одна строка User-Agent его не предоставляет.
- Сервер против ноутбука — это в основном репутация IP плюс TLS отпечаток. Один только жилой IP не прошел Indeed или Glassdoor в нашем тесте.
- Что прошло: Web Unlocker прошел Glassdoor (после безголового браузера, 17,2 с) и Indeed (с первой попытки, 2,6 с).
- Закрепите сессию. Повторное использование clearance браузера сократило второй запрос к Glassdoor с 14,0 с до 1,4 с в нашем тесте.
Что на самом деле представляет собой страница "Just a moment..."
Cloudflare называет это промежуточной страницей с задачей: это полностраничный барьер между посетителем и сайтом, пока Cloudflare решает, является ли посетитель автоматизированным. В её документации по страницам с задачами описаны три вида. Неинтерактивная задача требует только, чтобы браузер выполнил внедренный JavaScript. Управляемая задача позволяет Cloudflare выбрать тип задачи из сигналов запроса. Интерактивная задача просит посетителя что-то сделать. Когда проверка проходит, оригинальный запрос продолжается к сайту, и браузер получает cookie cf_clearance, которое позволяет ему пропускать барьер на некоторое время.
Клиент HTTP на Python никогда не доходит так далеко. Он загружает страницу с задачей, не имеет движка для выполнения скрипта и передает вам HTML барьера вместо страницы, которую вы запросили.
Почему задача возвращается как 403 и как её обнаружить
В нашем тесте каждая страница с задачей приходила со статусом 403, поэтому raise_for_status() выдает 403 Client Error: Forbidden, и люди ищут 'cloudflare just a moment 403'. Один статус не может отличить задачу от любого другого отказа. Надежный сигнал — это заголовок: Cloudflare документирует, что ответ с задачей несет cf-mitigated: challenge, независимо от запрашиваемого ресурса. Сначала проверьте это, затем заголовок как запасной вариант:
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'
Не повторяйте запрос с задачей в плотном цикле с тем же клиентом. Каждая повторная попытка загружает тот же барьер, и некоторые сайты отвечают на повторные неудачи более строгими правилами. Так скрейперы застревают в цикле 'Just a moment'.
"Enable JavaScript and cookies to continue" и "your browser does not support JavaScript"
Эти строки — резервный текст страницы с задачей, показываемый клиентам, которые не выполняют её скрипт. Когда Python requests показывает вам одну из них, сайт не жалуется на ваши заголовки. Он буквально говорит вам, что ему нужен JavaScript-движок и контейнер для cookie, который сохраняет то, что устанавливает скрипт.
Это именно то, что наш простой жилой запуск получил от Indeed и Glassdoor: 403 с 'Enable JavaScript and cookies to continue', с чистого домашнего IP. Добавление Chrome User-Agent, заголовка Accept-Language или Referer ничего не меняет, потому что страница не читает их для принятия решения. Она ждет выполнения скрипта.
Почему ваш скрейпер работает локально, но блокируется Cloudflare на сервере
Это самая распространенная версия жалобы: скрипт работает на ноутбуке, затем получает 'Just a moment', как только запускается на облачном VM. Две вещи меняются между этими машинами.
- IP. На вашем ноутбуке скрипт выходит с адреса домашнего интернет-провайдера. На VM он выходит из диапазона хостинг-провайдера, который защиты от ботов оценивают как вероятно автоматизированный, прежде чем они читают что-либо еще. Наш сервер в датацентре во Франкфурте был отклонен Glassdoor, Indeed, Zillow и Leboncoin, среди прочих.
- TLS отпечаток. Рукопожатие Python выглядит как Python на обеих машинах, но на домашнем IP сайт может его терпеть, а на хостинговом IP редко будет. Наше объяснение на curl_cffi vs requests показывает, насколько рукопожатие контролируется библиотекой.
Жилая колонка нашего теста показывает предел исправления только IP. Zillow и Leboncoin обслужили реальную страницу на простой запрос через жилой прокси. Indeed и Glassdoor все еще ответили JavaScript-задачей. Ваш ноутбук может столкнуться с той же стеной на более строгом сайте. Он просто сталкивается с ней реже.

Почему трюки эпохи cloudscraper перестают работать
cloudscraper был создан для старой страницы Cloudflare 'I'm Under Attack'. Эта страница в основном проверяла, может ли клиент выполнить JavaScript-вычисление, поэтому библиотека загружала задачу, решала скрипт в встроенном интерпретаторе, отправляла ответ обратно и сохраняла cookie, все это поверх requests. Долгое время этого было достаточно, и это причина, по которой 'cloudscraper alternative' теперь является популярным поисковым запросом.
С тех пор многое изменилось, и это не зависит от какой-либо одной версии библиотеки:
- Рукопожатие все еще говорит Python. Библиотека, построенная на requests, подключается через TLS стек Python, поэтому ClientHello не соответствует браузеру, которым заявляет быть его User-Agent. Это несоответствие видно до того, как запускается любой JavaScript.
- Задача больше не только арифметическая. Управляемые задачи выбирают проверку из сигналов запроса, и JavaScript-детекции Cloudflare читают окружение браузера. Интерпретатор, который оценивает скрипт, не является браузером, который рендерит страницу.
- Clearance привязан к клиенту. Документация Cloudflare по clearance говорит, что cookie cf_clearance привязано к посетителю и устройству, которому оно было выдано, чтобы предотвратить повторное использование на других машинах. Копирование одного из вашего браузера в скрипт на другой машине предназначено для неудачи.
- IP все еще ваш. Решение страницы не меняет IP из диапазона хостинга, и некоторые сайты отказываются от них до того, как будет выдана какая-либо задача.
На 29 сентября 2026 года последний push в репозитории cloudscraper был в июне 2025 года. Это не приговор для какого-либо конкретного сайта, и мы не проводили его бенчмаркинг для этой статьи. Это означает, что вы должны тестировать его на своих собственных целях, а не предполагать, что он работает. Альтернативы исправляют каждую часть проблемы. curl_cffi воспроизводит рукопожатие браузера TLS, но не выполняет JavaScript. Playwright или другой реальный браузер выполняет задачу, но все же нуждается в чистом IP, и его тяжело использовать в больших объемах. Разблокировщик комбинирует оба и сообщает вам, когда ни один из них не сработал.
Что проходит: путь веб-разблокировщика
Web Unlocker от QuantumProxies.io обрабатывает GET поэтапно. Сначала до трех попыток TLS, каждая на свежем жилом выходе под разным отпечатком браузера. Если каждая попытка возвращается с задачей, он переходит к безголовому браузеру, который выполняет задачу. Если страница все еще заблокирована после этого, вы получаете статус ошибки с x-qp-unlocker-blocked и классом блокировки, никогда не страницу задачи, замаскированную под 200. С Python это настройка прокси:
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"))
Заголовки x-qp-* читаются разблокировщиком и никогда не пересылаются на сайт. Если вы предпочитаете вообще не иметь дело с сертификатом, REST endpoint POST https://app.quantumproxies.io/api/v1/scraper/unlock принимает URL в теле JSON с вашим API ключом и возвращает blocked, blockClass и vendor в ответе. Наш учебник по API веб-разблокировщика проходит через оба.
Измерено: два типа защиты в стиле Cloudflare, которые были пройдены
Измерено 29 сентября 2026 года. Простые запросы были curl с Chrome User-Agent, с сервера в датацентре во Франкфурте и через жилой прокси с выходом в США. Разблокировщик использовал жилой уровень с выходом в США. Время указано по часам для одного запроса.
| Сайт | Простой, сервер датацентра | Простой, жилой прокси | Web Unlocker |
|---|---|---|---|
| Glassdoor (обзоры компаний) | 403, страница 'Безопасность' | 403, 'Enable JavaScript and cookies to continue' | 200, 2 попытки + безголовый браузер, 17,2 с |
| Indeed (поиск работы) | 403, страница 'Проверка безопасности' | 403, 'Enable JavaScript and cookies to continue' | 200, 1 попытка, без браузера, 2,6 с |
Glassdoor — это полный путь. Две попытки TLS были с задачей, затем безголовый браузер выполнил задачу и вернул страницу с обзорами. Indeed — это интересный случай: задача, которую простой жилой запрос получил, никогда не появилась для первой попытки разблокировщика. Отпечаток браузера TLS на свежем жилом выходе был достаточным, без браузера.
Обходите JavaScript-задачи с помощью Web Unlocker
Повторное использование clearance: почему второй запрос быстрый
Эскалация браузера — это медленная часть, и вы не хотите платить за неё на каждой странице. Когда безголовый браузер проходит задачу, он зарабатывает clearance. Отправьте то же значение x-qp-session, или сохраните тот же -session-<id> в имени пользователя прокси, на следующих запросах, и они будут выходить из того же выхода, повторно используя этот clearance вместо повторного запуска браузера. Заголовок x-qp-clearance сообщает вам, что произошло на каждом вызове: minted, когда был заработан новый clearance, hit, когда использовался сохраненный, miss, когда не было ничего для повторного использования.
В тесте Glassdoor 29 сентября 2026 года, с закрепленной сессией в имени пользователя прокси и двумя отдельными соединениями, первый запрос прошел через браузер за 14,0 секунды (minted), а второй вернулся за 1,4 секунды (hit). Закрепление имеет значение из-за того, как Cloudflare связывает clearance: он привязан к посетителю и устройству, которое его заработало, и остается действительным на время, которое сайт настраивает, если только Cloudflare не решит, что сессия выглядит подозрительно. Измените выход или отпечаток, и вы снова новый посетитель.

Когда простые запросы все еще подходят на сайте Cloudflare
Множество сайтов работают за Cloudflare только как CDN или с правилами ботов, которые пропускают обычный трафик, и простые запросы работают на них. Быть 'на Cloudflare' не является причиной обращаться к браузеру. Сигнал — это ответ. Если нет заголовка cf-mitigated: challenge, нет заголовка 'Just a moment' и нет 403, сохраняйте простой запрос и эскалируйте только те URL, которые действительно получают задачу. Помощник plain-first в нашем учебнике делает именно это.
Две соседние проблемы имеют свои собственные руководства. Страница, которая говорит 'Error 1020 Access denied', — это правило брандмауэра, отказывающее вам, а не задача, и никакое количество JavaScript это не исправит; см. что вызывает ошибку Cloudflare 1020 и что её исправляет. Для более широкой картины защит Cloudflare за пределами Python, читайте как обойти задачи Cloudflare в 2026 году. Если страница за стеной — это Glassdoor, наше руководство по скрейпингу зарплат и отзывов Glassdoor охватывает сторону данных.
Часто задаваемые вопросы
Почему мой скрейпер работает локально, но блокируется Cloudflare в облаке?
Потому что IP меняется. Дома ваш скрипт выходит с адреса жилого интернет-провайдера; на облачном VM он выходит из диапазона хостинга, которому защиты от ботов не доверяют с первого взгляда. TLS рукопожатие Python одинаково на обоих, и на более строгом сайте оно получает задачу даже из дома. В нашем тесте один жилой IP не прошел Indeed или Glassdoor.
Почему страница Cloudflare "Just a moment" возвращает 403?
Страница с задачей выдается вместо страницы, которую вы запросили, и в нашем тесте она приходила со статусом 403, поэтому requests выдает '403 Client Error: Forbidden'. Статус не специфичен для задач. Проверьте заголовок ответа cf-mitigated, который Cloudflare документирует как установленный на challenge на каждом ответе страницы с задачей, или заголовок 'Just a moment'.
Работает ли cloudscraper, и какая есть хорошая альтернатива?
Он может все еще работать на сайтах с мягкими настройками, поэтому тестируйте его на своих целях. Он работает на TLS стеке Python и решает скрипты в интерпретаторе, в то время как текущие задачи также смотрят на рукопожатие и окружение браузера. Альтернативы: curl_cffi для рукопожатия браузера, реальный браузер для JavaScript или веб-разблокировщик, который делает и то, и другое.
Может ли Python requests самостоятельно пройти задачу Cloudflare?
Нет. requests не выполняет JavaScript, поэтому не может завершить задачу, которая зависит от выполнения скрипта страницы. Он может загружать страницы с сайтов Cloudflare, которые не бросают вам вызов. Как только появляется cf-mitigated: challenge, вам нужен реальный браузер, напрямую или через сервис, который его использует, и, желательно, чистый жилой IP.
Как долго длится clearance Cloudflare?
Настолько долго, насколько сайт его настраивает. Cloudflare называет эту настройку Challenge Passage, и clearance может закончиться раньше, если Cloudflare решит, что сессия выглядит подозрительно. Cookie cf_clearance привязано к посетителю и устройству, которое его заработало, поэтому оно помогает только если последующие запросы сохраняют тот же выход и отпечаток, что и закрепление x-qp-session.
Краткая версия: 'Just a moment...' просит браузер, поэтому никакой трюк с заголовками в requests не удовлетворит её. Обнаружьте её с помощью cf-mitigated, сохраняйте простые запросы для всего, что не бросает вызов, отправляйте URL с задачами через что-то, что запускает реальный браузер с чистого IP, и закрепите сессию, чтобы платить за этот браузер один раз, а не на каждой странице.