# Cloudflare "Just a Moment" w Pythonie: Dlaczego requests zawodzi

Strona 'Just a moment...' Cloudflare'a to wyzwanie JavaScript, a Python requests nie może uruchomić JavaScript. Oto jak je wykryć, dlaczego serwery są bardziej obciążone niż laptopy, dlaczego sztuczki w stylu cloudscraper przestały wystarczać i co przeszło w naszym teście z 29 września 2026.

'Just a moment...' to strona wyzwania Cloudflare'a. Prosi klienta o uruchomienie JavaScript i udowodnienie, że jest przeglądarką, zanim strona odpowie. Python requests nie może uruchomić JavaScript, a z serwera w centrum danych jego IP i handshake TLS już wyglądają na zautomatyzowane. Co przechodzi, to prawdziwa przeglądarka na czystym IP lub web unlocker, który ją uruchamia.

Ten przewodnik pokazuje, jak wykryć wyzwanie w Pythonie, dlaczego ten sam skrypt przechodzi na laptopie, a zawodzi na serwerze, dlaczego sztuczki z ery cloudscraper przestały wystarczać i co faktycznie przeszło, gdy testowaliśmy to 29 września 2026.

- **To wyzwanie, nie błąd.** Cloudflare oznacza odpowiedzi z wyzwaniem nagłówkiem `cf-mitigated: challenge`. W naszym teście przychodziły jako HTTP 403.
- **Nagłówki tego nie naprawią.** 'Enable JavaScript and cookies to continue' oznacza, że strona chce silnika JavaScript. Żaden ciąg User-Agent go nie dostarcza.
- **Serwer kontra laptop** to głównie reputacja IP plus odcisk palca TLS. Samo IP rezydencyjne nie przeszło Indeed ani Glassdoor w naszym teście.
- **Co przeszło:** Web Unlocker uzyskał dostęp do Glassdoor (po przeglądarce bezgłowej, 17,2 s) i Indeed (przy pierwszej próbie, 2,6 s).
- **Przypnij sesję.** Ponowne użycie clearance przeglądarki skróciło drugie żądanie do Glassdoor z 14,0 s do 1,4 s w naszym teście.

## Czym właściwie jest strona "Just a moment..."

Cloudflare nazywa to stroną wyzwania przejściowego: pełnostronicową bramą między odwiedzającym a stroną, podczas gdy Cloudflare decyduje, czy odwiedzający jest zautomatyzowany. Jej [dokumentacja dotycząca stron wyzwań](https://developers.cloudflare.com/cloudflare-challenges/challenge-types/challenge-pages/) opisuje trzy rodzaje. Wyzwanie nieinteraktywne wymaga jedynie, aby przeglądarka uruchomiła wstrzyknięty JavaScript. Zarządzane wyzwanie pozwala Cloudflare wybrać typ wyzwania na podstawie sygnałów z żądania. Wyzwanie interaktywne prosi odwiedzającego o wykonanie czegoś. Gdy kontrola przejdzie, oryginalne żądanie kontynuuje do strony, a przeglądarka otrzymuje ciasteczko `cf_clearance`, które pozwala ominąć bramę na jakiś czas.

Klient HTTP w Pythonie nigdy nie dochodzi tak daleko. Pobiera stronę wyzwania, nie ma silnika do uruchomienia skryptu i zamiast strony, o którą prosiłeś, zwraca ci HTML bramy.

## Dlaczego wyzwanie wraca jako 403 i jak je wykryć

W naszym teście każda strona wyzwania przychodziła ze statusem 403, co jest powodem, dla którego `raise_for_status()` wyrzuca `403 Client Error: Forbidden` i ludzie szukają 'cloudflare just a moment 403'. Sam status nie może odróżnić wyzwania od jakiejkolwiek innej odmowy. Wiarygodnym sygnałem jest nagłówek: Cloudflare [dokumentuje, że odpowiedź z wyzwaniem zawiera cf-mitigated: challenge](https://developers.cloudflare.com/cloudflare-challenges/challenge-types/challenge-pages/detect-response/), niezależnie od zasobu, o który prosiłeś. Sprawdź to najpierw, a potem tytuł jako rezerwę:

```python
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'
```

Nie próbuj ponownie żądania z wyzwaniem w ciasnej pętli z tym samym klientem. Każda próba pobiera tę samą bramę, a niektóre strony odpowiadają na powtarzające się niepowodzenia surowszymi zasadami. Tak właśnie scraper kończy w pętli 'Just a moment'.

## "Enable JavaScript and cookies to continue" i "your browser does not support JavaScript"

Te ciągi to tekst rezerwowy strony wyzwania, pokazywany klientom, którzy nie wykonują jej skryptu. Gdy Python requests pokazuje ci jeden z nich, strona nie narzeka na twoje nagłówki. Mówi ci dosłownie, że potrzebuje silnika JavaScript i słoika na ciasteczka, który zachowa to, co ustawia skrypt.

To dokładnie to, co nasz zwykły rezydencyjny bieg otrzymał od Indeed i Glassdoor: 403 z 'Enable JavaScript and cookies to continue', z czystego domowego IP. Dodanie User-Agent Chrome, nagłówka Accept-Language lub Referer nic nie zmienia, ponieważ strona ich nie czyta, aby zdecydować. Czeka, aż skrypt się uruchomi.

## Dlaczego twój scraper działa lokalnie, ale jest blokowany przez Cloudflare na serwerze

To najczęstsza wersja skargi: skrypt działa na laptopie, a potem otrzymuje 'Just a moment', gdy tylko uruchomi się na chmurze VM. Dwie rzeczy zmieniają się między tymi maszynami.

- **IP.** Na twoim laptopie skrypt wychodzi z adresu ISP domowego. Na VM wychodzi z zakresu dostawcy hostingu, który obrony przed botami oceniają jako prawdopodobnie zautomatyzowany, zanim cokolwiek innego przeczytają. Nasz serwer w centrum danych we Frankfurcie został odrzucony przez Glassdoor, Indeed, Zillow i Leboncoin, między innymi.
- **Odcisk palca TLS.** Handshake Pythona wygląda jak Python na obu maszynach, ale na domowym IP strona może go tolerować, a na IP hostingu rzadko to zrobi. Nasze wyjaśnienie na temat [curl_cffi vs requests](https://quantumproxies.io/blog/curl-cffi-vs-requests) pokazuje, jak wiele z handshake kontroluje biblioteka.

Kolumna rezydencyjna naszego testu pokazuje limit naprawy tylko IP. Zillow i Leboncoin obsłużyły prawdziwą stronę na zwykłe żądanie przez rezydencyjny proxy. Indeed i Glassdoor nadal odpowiadały wyzwaniem JavaScript. Twój laptop może trafić na tę samą ścianę na bardziej rygorystycznej stronie. Po prostu trafia na nią rzadziej.

![Ten sam skrypt Python requests na dwóch maszynach: z laptopa na domowym IP od dostawcy internetu strona często się ładuje, z serwera w chmurze na IP hostingu Cloudflare odpowiada wyzwaniem „Just a moment”. Karta pokazuje, co się zmienia, czyli wyjściowe IP, i co się nie zmienia: handshake TLS Pythona i brak silnika JavaScript.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1790701776/blog/generated/qp-unl-g3-diag1.png)
*Ten sam skrypt, dwie maszyny. IP się zmienia; handshake TLS Pythona i brak silnika JavaScript nie.*

## Dlaczego sztuczki z ery cloudscraper przestają działać

[cloudscraper](https://github.com/VeNoMouS/cloudscraper) został zbudowany dla starszej strony 'I'm Under Attack' Cloudflare'a. Ta strona głównie sprawdzała, czy klient może wykonać obliczenie JavaScript, więc biblioteka pobierała wyzwanie, rozwiązywała skrypt w wbudowanym interpreterze, wysyłała odpowiedź z powrotem i zachowywała ciasteczko, wszystko na wierzchu `requests`. Przez długi czas to wystarczało i to jest powód, dla którego 'cloudscraper alternative' jest teraz wyszukiwaniem, które ludzie wykonują.

Od tego czasu wiele się zmieniło i nie zależy to od żadnej wersji biblioteki:

- **Handshake nadal mówi Python.** Biblioteka zbudowana na requests łączy się przez stos TLS Pythona, więc ClientHello nie pasuje do przeglądarki, którą twierdzi, że jest jej User-Agent. Ta niezgodność jest widoczna, zanim jakikolwiek JavaScript się uruchomi.
- **Wyzwanie to już nie tylko arytmetyka.** Zarządzane wyzwania wybierają kontrolę z sygnałów żądania, a detekcje JavaScript Cloudflare'a czytają środowisko przeglądarki. Interpreter, który ocenia skrypt, nie jest przeglądarką, która renderuje stronę.
- **Clearance jest przypisane do klienta.** Dokumentacja [clearance Cloudflare'a](https://developers.cloudflare.com/cloudflare-challenges/concepts/clearance/) mówi, że ciasteczko cf_clearance jest związane z odwiedzającym i urządzeniem, na które zostało wydane, aby zapobiec ponownemu użyciu na różnych maszynach. Skopiowanie go z przeglądarki do skryptu na innej maszynie jest zaprojektowane, aby się nie powieść.
- **IP nadal jest twoje.** Rozwiązanie strony nie zmienia IP z zakresu hostingu, a niektóre strony odrzucają je, zanim jakiekolwiek wyzwanie zostanie podane.

Na dzień 29 września 2026, ostatnie przesłanie do repozytorium cloudscraper miało miejsce w czerwcu 2025. To nie jest werdykt na temat żadnej konkretnej strony, i nie przeprowadziliśmy benchmarku dla tego artykułu. Oznacza to jednak, że powinieneś testować go na swoich własnych celach, zamiast zakładać, że działa. Alternatywy rozwiązują każdą część problemu. curl_cffi odtwarza handshake TLS przeglądarki, ale nie uruchamia JavaScript. Playwright lub inna prawdziwa przeglądarka uruchamia wyzwanie, ale nadal potrzebuje czystego IP i jest ciężka do obsługi na dużą skalę. Unlocker łączy oba i informuje cię, gdy żadne z nich nie działało.

## Co przechodzi: ścieżka web unlocker

QuantumProxies.io Web Unlocker obsługuje GET w etapach. Najpierw do trzech prób TLS, każda na świeżym wyjściu rezydencyjnym pod innym odciskiem palca przeglądarki. Jeśli każda próba wraca z wyzwaniem, eskaluje do przeglądarki bezgłowej, która uruchamia wyzwanie. Jeśli strona jest nadal zablokowana po tym, otrzymujesz status błędu z `x-qp-unlocker-blocked` i klasą blokady, nigdy stronę wyzwania przebrane za 200. Z Pythona to ustawienie proxy:

```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"))
```

Nagłówki `x-qp-*` są odczytywane przez unlocker i nigdy nie są przekazywane do strony. Jeśli wolisz w ogóle nie zajmować się certyfikatem, punkt końcowy REST `POST https://app.quantumproxies.io/api/v1/scraper/unlock` przyjmuje URL w ciele JSON z twoim kluczem API i zwraca `blocked`, `blockClass` i `vendor` w odpowiedzi. Nasz [samouczek API web unlocker](https://quantumproxies.io/blog/web-unlocker-api-tutorial-python) przeprowadza przez oba.

## Zmierzono: dwa mury w stylu Cloudflare, które przeszły

Zmierzono 29 września 2026. Zwykłe żądania były curl z User-Agent Chrome, z serwera w centrum danych we Frankfurcie i przez proxy rezydencyjne z wyjściem w USA. Unlocker używał poziomu rezydencyjnego z wyjściem w USA. Czas to czas ścienny dla jednego żądania.

| Strona | Zwykłe, serwer w centrum danych | Zwykłe, proxy rezydencyjne | Web Unlocker |
| --- | --- | --- | --- |
| Glassdoor (recenzje firm) | 403, strona 'Security' | 403, 'Enable JavaScript and cookies to continue' | 200, 2 próby + przeglądarka bezgłowa, 17,2 s |
| Indeed (wyszukiwanie pracy) | 403, strona 'Security Check' | 403, 'Enable JavaScript and cookies to continue' | 200, 1 próba, bez przeglądarki, 2,6 s |

Glassdoor to pełna ścieżka. Dwie próby TLS były wyzwaniem, potem przeglądarka bezgłowa uruchomiła wyzwanie i zwróciła stronę z recenzjami. Indeed to interesujący przypadek: wyzwanie, które otrzymało zwykłe rezydencyjne żądanie, nigdy nie pojawiło się przy pierwszej próbie unlockera. Odcisk palca TLS przeglądarki na świeżym wyjściu rezydencyjnym wystarczył, bez przeglądarki.

[Przejdź przez wyzwania JavaScript z Web Unlocker](https://quantumproxies.io/web-unlocker)

## Ponowne użycie clearance: dlaczego drugie żądanie jest szybkie

Eskalacja przeglądarki to wolna część i nie chcesz za nią płacić na każdej stronie. Gdy przeglądarka bezgłowa przechodzi wyzwanie, zdobywa clearance. Wyślij tę samą wartość `x-qp-session`, lub zachowaj ten sam `-session-<id>` w nazwie użytkownika proxy, przy kolejnych żądaniach i wychodzą one z tego samego wyjścia, ponownie używając tego clearance zamiast ponownie uruchamiać przeglądarkę. Nagłówek `x-qp-clearance` mówi ci, co się stało przy każdym wywołaniu: `minted`, gdy zdobyto nowy clearance, `hit`, gdy ponownie użyto przechowywanego, `miss`, gdy nie było nic do ponownego użycia.

W teście Glassdoor 29 września 2026, z sesją przypiętą w nazwie użytkownika proxy i dwoma oddzielnymi połączeniami, pierwsze żądanie przeszło przez przeglądarkę w 14,0 sekund (`minted`), a drugie wróciło w 1,4 sekundy (`hit`). Przypięcie ma znaczenie ze względu na to, jak Cloudflare wiąże clearance: jest związane z odwiedzającym i urządzeniem, które je zdobyło, i pozostaje ważne przez czas, który strona konfiguruje, chyba że Cloudflare uzna, że sesja wygląda podejrzanie. Zmień wyjście lub odcisk palca, a jesteś nowym odwiedzającym.

![Dwa żądania do Glassdoor w jednej przypiętej sesji Web Unlocker: pierwsze przechodzi wyzwanie Cloudflare w przeglądarce bezgłowej i uzyskuje clearance w 14,0 s, drugie ponownie używa tego clearance na tym samym wyjściu i wraca w 1,4 s, według pomiaru z 29 września 2026.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1790701776/blog/generated/qp-unl-g3-diag2.png)
*Pierwsze żądanie płaci za przeglądarkę; późniejsze żądania w tej samej przypiętej sesji ponownie używają clearance.*

## Kiedy zwykłe requests nadal działa na stronie Cloudflare

Wiele stron działa za Cloudflare tylko jako CDN, lub z zasadami botów, które przepuszczają zwykły ruch, i zwykłe requests działa na nich. Bycie 'na Cloudflare' nie jest powodem, aby sięgać po przeglądarkę. Sygnałem jest odpowiedź. Jeśli nie ma nagłówka `cf-mitigated: challenge`, tytułu 'Just a moment' i 403, zachowaj zwykłe żądanie i eskaluj tylko URL-e, które faktycznie są wyzwaniem. Pomocnik plain-first w naszym samouczku robi dokładnie to.

Dwa sąsiednie problemy mają własne przewodniki. Strona, która mówi 'Error 1020 Access denied', to reguła zapory odmawiająca ci, a nie wyzwanie, i żadna ilość JavaScript tego nie naprawi; zobacz [co wywołuje błąd Cloudflare 1020 i co go naprawia](https://quantumproxies.io/blog/cloudflare-error-1020-access-denied). Dla szerszego obrazu obron Cloudflare poza Pythonem, przeczytaj [jak ominąć wyzwania Cloudflare w 2026](https://quantumproxies.io/blog/how-to-bypass-cloudflare-challenges-in-2026-what-actually-matters-now). Jeśli strona za ścianą to Glassdoor, nasz [przewodnik po skrobaniu wynagrodzeń i recenzji Glassdoor](https://quantumproxies.io/blog/scrape-glassdoor-salary-reviews) obejmuje stronę danych.

## Często zadawane pytania

### Dlaczego mój scraper działa lokalnie, ale jest blokowany przez Cloudflare w chmurze?

Ponieważ IP się zmienia. W domu twój skrypt wychodzi z adresu ISP rezydencyjnego; na chmurze VM wychodzi z zakresu hostingu, który obrony przed botami nie ufają na pierwszy rzut oka. Handshake TLS Pythona jest taki sam na obu, a na bardziej rygorystycznej stronie jest wyzwaniem nawet z domu. W naszym teście samo IP rezydencyjne nie przeszło Indeed ani Glassdoor.

### Dlaczego strona "Just a moment" Cloudflare'a zwraca 403?

Strona wyzwania jest serwowana zamiast strony, o którą prosiłeś, i w naszym teście przychodziła ze statusem 403, więc requests podnosi '403 Client Error: Forbidden'. Status nie jest specyficzny dla wyzwań. Sprawdź nagłówek odpowiedzi cf-mitigated, który Cloudflare dokumentuje jako ustawiony na challenge przy każdej odpowiedzi na stronę wyzwania, lub tytuł 'Just a moment'.

### Czy cloudscraper nadal działa, i jaka jest dobra alternatywa?

Może nadal działać na stronach z łagodnymi ustawieniami, więc przetestuj go na swoich celach. Działa na stosie TLS Pythona i rozwiązuje skrypty w interpreterze, podczas gdy obecne wyzwania również patrzą na handshake i środowisko przeglądarki. Alternatywy: curl_cffi dla handshake przeglądarki, prawdziwa przeglądarka dla JavaScript, lub web unlocker, który robi oba.

### Czy Python requests może samodzielnie przejść wyzwanie Cloudflare?

Nie. requests nie wykonuje JavaScript, więc nie może ukończyć wyzwania, które zależy od uruchomienia skryptu strony. Może pobierać strony z witryn Cloudflare, które cię nie wyzywają. Gdy pojawia się cf-mitigated: challenge, potrzebujesz prawdziwej przeglądarki, bezpośrednio lub przez usługę, która ją uruchamia, i najlepiej czystego rezydencyjnego IP.

### Jak długo trwa clearance Cloudflare?

Tak długo, jak strona to konfiguruje. Cloudflare nazywa to ustawienie Challenge Passage, a clearance może zakończyć się wcześniej, jeśli Cloudflare uzna, że sesja wygląda podejrzanie. Ciasteczko cf_clearance jest związane z odwiedzającym i urządzeniem, które je zdobyło, więc pomaga tylko, jeśli późniejsze żądania zachowują to samo wyjście i odcisk palca, co robi przypięcie x-qp-session.

Krótka wersja: 'Just a moment...' prosi o przeglądarkę, więc żadna sztuczka z nagłówkami w requests tego nie zadowoli. Wykryj to z `cf-mitigated`, zachowaj zwykłe requests dla wszystkiego, co nie jest wyzwaniem, wyślij wyzwanie URL-e przez coś, co uruchamia prawdziwą przeglądarkę z czystego IP, i przypnij sesję, aby zapłacić za tę przeglądarkę raz, a nie na każdej stronie.

[Wypróbuj Web Unlocker na wyjściach rezydencyjnych](https://quantumproxies.io/web-unlocker/residential)
