# curl zwraca 403, ale przeglądarka działa: znajdź brakujący element

Przeglądarka ładuje stronę. curl zwraca 403. Różnica między tymi dwoma żądaniami jest zawsze skończona i zawsze możliwa do znalezienia — oto jak ją podzielić w pięć minut.

Wklejasz URL do Chrome i strona się ładuje. Wklejasz ten sam URL do curl i otrzymujesz 403 Forbidden. Nic się nie zmieniło w zasobie między tymi dwoma sekundami, więc różnica leży całkowicie w żądaniu — a żądanie to skończona, możliwa do zbadania rzecz. Ten przewodnik to procedura podziału: odtwórz dokładnie to, co wysłała przeglądarka, a następnie usuwaj elementy, aż 403 powróci. Cokolwiek usunąłeś ostatnio, to jest twoja odpowiedź. Podejrzani, w kolejności, w jakiej zwykle są winni, to User-Agent, Referer, cookies, TLS fingerprint i JavaScript.

## Krok 0: udowodnij, że żądania naprawdę się różnią

Zanim zaczniesz teoretyzować, zobacz, co curl faktycznie wysyła. Dzięki `-v` widzisz linię żądania, każdy nagłówek i handshake TLS. Domyślne żądanie curl jest zaskakująco skromne — zazwyczaj `Host`, `User-Agent: curl/8.x` i `Accept: */*`. Przeglądarka wysyła kilkanaście więcej.

```bash
# what you send, what you get back, and the TLS details
curl -v -o /dev/null https://target.example/page

# just the response headers, quickly
curl -sS -o /dev/null -D - https://target.example/page
```

Przeczytaj nagłówki odpowiedzi tak uważnie, jak linię statusu. Jeden z nich rozstrzyga pytanie od razu w najczęstszym przypadku: `Vary: User-Agent` oznacza, że serwer celowo serwuje różne odpowiedzi w zależności od tego, kim twierdzisz, że jesteś. W dobrze udokumentowanym przypadku na Stack Overflow, `curl -f` przeciwko zwykłemu hostowi Apache 2.4.38 zwrócił 403, podczas gdy `wget` pobrał identyczny plik z 200 — a udana odpowiedź zawierała dokładnie ten nagłówek `Vary: User-Agent`. Przekazanie `-A 'Wget/1.21.2'` do curl naprawiło to natychmiast. Właściciel witryny zablokował user agent curl po nadużyciach; nic innego w żądaniu nie miało znaczenia.

Podczas czytania wyjścia: `curl: (22) The requested URL returned error: 403` nie jest osobnym problemem. Kod wyjścia 22 to to, co `-f/--fail` robi z każdym błędem HTTP — flaga tłumi ciało i powoduje niepowodzenie komendy. Usuń tymczasowo `-f`, aby móc faktycznie przeczytać stronę blokady, która zazwyczaj podaje nazwę systemu, który cię zatrzymał.

## Krok 1: Kopiuj jako cURL, 30-sekundowa odpowiedź

Obie główne przeglądarki mogą przekazać ci dokładne żądanie, które właśnie wykonały. Otwórz DevTools, przejdź do zakładki Network, kliknij prawym przyciskiem myszy żądanie i wybierz "Copy as cURL". Chrome wprowadziło to od wersji 26, a Firefox od 31, a wyjście zawiera każdy nagłówek, każde ciasteczko i referer. Wklej to do swojego terminala: jeśli zwróci 200, twój problem leży definitywnie w kształcie żądania, a krok 2 znajdzie, która część.

Jedna pułapka marnuje tu dużo czasu. Jeśli URL przekierowuje, panel Network czyści się przy nawigacji i kopiujesz złe żądanie. Zaznacz "Preserve log" w Chrome lub "Persistent Logs" w Firefox najpierw, aby móc zobaczyć zarówno żądanie, które przekierowało, jak i to, które ostatecznie serwowało treść. Łańcuchy przekierowań mają znaczenie: w dobrze znanym wątku na Unix Stack Exchange serwer sprawdzał `Referer`, a następnie przeskakiwał przez 302 do lokalizacji, która niczego nie sprawdzała — co sprawiało, że niepowodzenie wyglądało na losowe, dopóki cały łańcuch nie był widoczny.

![Domyślne żądanie curl obok żądania Chrome dla tego samego URL: curl wysyła około trzech nagłówków, bez ciasteczek i z handshake OpenSSL, i dostaje 403, Chrome wysyła około dwunastu nagłówków, zapisane ciasteczka i handshake Chrome, i dostaje 200; karta wymienia różnice kolumna po kolumnie, od nagłówków po JavaScript.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335151/blog/generated/qp-b9-013-diag1.png)
*Każde 403 w tym scenariuszu ukrywa się w tej luce. Zamknij ją kolumna po kolumnie.*

## Krok 2: podziel nagłówki

Zacznij od działającej komendy "Copy as cURL" i usuwaj nagłówki jeden po drugim, uruchamiając ponownie po każdym usunięciu. Pierwsze usunięcie, które przywraca 403, wskazuje twojego winowajcę. W praktyce jest to prawie zawsze jeden z czterech.

```bash
curl -sS -o /dev/null -w '%{http_code}\n' \
  -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
  -H 'Accept-Language: en-GB,en;q=0.9' \
  -e 'https://target.example/' \
  -b 'session=abc123; consent=1' \
  -L \
  'https://target.example/page'
```

- **User-Agent** (`-A`) — zablokowany bezpośrednio, lub serwer rozgałęzia się na jego podstawie. Przetestuj aktualny ciąg Chrome, potem wget, potem nonsensowny; wzór wyników powie ci, czy trafiasz na czarną listę, czy na białą listę.
- **Referer** (`-e`) — zasoby i linki do pobrania często zwracają 403, chyba że żądanie wygląda, jakby pochodziło z własnej strony witryny. Nagłówek jest opcjonalny według specyfikacji, co jest dokładnie powodem, dla którego ludzie o nim zapominają.
- **Cookies** (`-b`) — ciasteczko zgody, sesji lub anty-bot ustawione na wcześniejszej stronie. Potwierdź to w kilka sekund: otwórz URL w oknie prywatnym. Jeśli przeglądarka również zwraca 403, ciasteczka są twoją odpowiedzią.
- **Authorization** (`-u`, lub nagłówek bearer) — podpisane lub tokenizowane URL-e często zwracają 403, gdy są kopiowane poza kontekst, ponieważ token był powiązany z sesją lub już wygasł.

Dwa zamykające szczegóły dla tego szczebla. Cytuj URL: ciąg zapytania zawierający `&` lub token dostępu zostaje zniekształcony przez twoją powłokę inaczej, a wynikowe 403 nie ma nic wspólnego z serwerem. A jeśli debugujesz z PHP lub Node zamiast z powłoki, odtwórz ten sam zestaw nagłówków tam — domyślne ustawienia libcurl wewnątrz PHP różnią się od narzędzia wiersza poleceń, co jest powodem, dla którego identyczne żądanie może przejść w terminalu i nie powieść się w kodzie. Nasze [przepisy curl z proxy](https://quantumproxies.io/blog/curl-with-proxy-examples) obejmują pełną składnię flagi.

## Krok 3: gdy identyczne nagłówki nadal zwracają 403

Jeśli kopia bajt po bajcie nagłówków przeglądarki nadal nie działa, decyzja została podjęta przed przetworzeniem twoich nagłówków. Pod nimi znajdują się dwie warstwy.

**TLS fingerprint.** Twój ClientHello — zestawy szyfrów, rozszerzenia, preferencje krzywych, ALPN, plus ramka ustawień HTTP/2, która następuje — haszuje się do wartości JA3 lub JA4. curl zbudowany na OpenSSL produkuje taki, którego żadna przeglądarka nigdy nie produkuje, a systemy anty-bot porównują go z twoim deklarowanym User-Agent. Twierdzenie, że jesteś Chrome, podczas gdy handshake wygląda jak OpenSSL, to sprzeczność, którą są zbudowane, aby wychwycić. Rozwiązaniem jest klient, który odtwarza handshakes przeglądarki: `curl-impersonate` w wierszu poleceń, lub `curl_cffi` z Python.

```python
# pip install curl_cffi
from curl_cffi import requests

proxy = "http://USER:PASS@residentialpremium.quantumproxies.io:8080"

r = requests.get(
    "https://target.example/page",
    impersonate="chrome",          # browser ClientHello + HTTP/2 settings
    proxies={"http": proxy, "https": proxy},
    timeout=20,
)
print(r.status_code, r.headers.get("content-type"))
```

**Twój IP.** Przeglądarka, która działa, zazwyczaj jest na twoim domowym połączeniu, podczas gdy curl działa na VPS. Hosting ASNs są publikowane i oceniane, więc to samo żądanie z adresu rezydencjalnego jest oceniane inaczej, zanim zostanie nawet przeczytane. Zmiana wyjścia to jednolinijkowa zmiana z [residential proxies](https://quantumproxies.io/residential-proxies) — ponad 90 milionów IP w ponad 200 krajach, HTTP i SOCKS5 w każdym planie — i jest to najszybszy sposób, aby wykluczyć sieć. Mechanika warstwy fingerprint jest opisana w [JA3/JA4 TLS fingerprinting](https://quantumproxies.io/blog/tls-ja3-fingerprinting-scraping).

[Wyklucz sieć za pomocą residential proxies](https://quantumproxies.io/residential-proxies)

![Cztery kroki od 403 w curl do 200: skopiuj żądanie przeglądarki jako cURL, zawężaj nagłówki metodą bisekcji, po jednej fladze naraz, naśladuj handshake TLS przeglądarki przez wyjście rezydencjalne, a potem renderuj lub użyj Scraper API dla wyzwania JavaScript; karta mówi, by zatrzymać się, gdy tylko status zmieni się na 200.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335152/blog/generated/qp-b9-013-diag2.png)
*Cztery kroki, każdy to test. Zatrzymaj się, gdy tylko status zmieni się na 200 — nie wspinaj się wyżej niż to konieczne.*

## Krok 4: strona potrzebuje przeglądarki, nie klienta

Czasami 403 nie jest oceną ciebie w ogóle — to tryb awaryjny wyzwania, którego nigdy nie próbowałeś. Publiczna dyskusja na GitHub o sprawdzaniu linków na npmjs.com ujmuje to jasno: curl nie może wygenerować poprawnego rozwiązania wyzwania, więc żądanie jest blokowane z 403. Serwer wydaje mały problem JavaScript, czeka chwilę na odpowiedź i odrzuca wszystko, co nie może go wykonać. Żaden zestaw nagłówków, żaden fingerprint i żaden IP nie przejdzie testu, który wymaga uruchomienia kodu.

W tym momencie masz trzy uczciwe opcje: uruchomić prawdziwą przeglądarkę i ponieść koszt, znaleźć punkt końcowy JSON, który sama strona wywołuje (często znajdujący się w tej samej zakładce Network, którą już masz otwartą), lub przekazać URL do usługi, która renderuje na żądanie. QuantumProxies [Scraper API](https://quantumproxies.io/scraper-api) robi to ostatnie — TLS na poziomie przeglądarki, wyjścia rezydencjalne, renderowanie JavaScript tylko tam, gdzie strona tego potrzebuje, i markdown, JSON lub surowe HTML z jednego żądania. Jeśli to, co otrzymujesz, to pusta strona zamiast zabronionej, to inna diagnoza: zobacz [dlaczego twój scraper zwraca pustą stronę](https://quantumproxies.io/blog/scraper-returns-empty-page-javascript). A jeśli strona blokady zawiera Cloudflare Ray ID, przejdź do [Cloudflare error 1020](https://quantumproxies.io/blog/cloudflare-error-1020-access-denied).

## Najczęściej zadawane pytania

### Dlaczego curl dostaje 403, gdy moja przeglądarka nie?

Ponieważ curl wysyła około trzech nagłówków, bez ciasteczek, bez referera i nieprzeglądarkowy TLS fingerprint, podczas gdy twoja przeglądarka wysyła kilkanaście nagłówków, słoik ciasteczek i handshake Chrome. Serwer odrzuca żądanie, nie zasób. Odtwórz dokładne żądanie przeglądarki za pomocą "Copy as cURL", a następnie usuwaj nagłówki jeden po drugim, aby znaleźć, która różnica ma znaczenie.

### Dlaczego wget działa tam, gdzie curl dostaje 403?

Prawie zawsze User-Agent. Niektóre serwery blokują UA curl specjalnie po nadużyciach, pozostawiając wget bez zmian — udokumentowany przypadek pokazał nagłówek odpowiedzi `Vary: User-Agent` potwierdzający, że serwer rozgałęzia się na jego podstawie, a `curl -A 'Wget/1.21.2'` przywróciło 200. wget również domyślnie wysyła `Accept-Encoding` i `Connection`, co czasami ma znaczenie.

### Jak ustawić User-Agent w curl?

Użyj `-A 'string'`, lub równoważnego `-H 'User-Agent: string'`. Preferuj pełny, aktualny ciąg przeglądarki nad skróconym `Mozilla/5.0`, który niektóre serwery teraz odrzucają właśnie dlatego, że żadna prawdziwa przeglądarka nie wysyła tylko dwóch tokenów. Połącz go z odpowiadającymi wartościami `Accept` i `Accept-Language`, aby cały zestaw pozostał spójny.

### Co oznacza błąd curl 22?

Kod wyjścia 22 jest produkowany przez `-f/--fail` zawsze, gdy serwer zwraca błąd HTTP, a komunikat cytuje status — najczęściej 403. Jest to flaga raportująca, a nie odrębna usterka. Usuń `-f`, aby zobaczyć ciało odpowiedzi, które zazwyczaj lepiej wyjaśnia blokadę niż sam kod wyjścia.

### Czy proxy może naprawić curl 403?

Naprawia podzbiór spowodowany reputacją IP lub geografią — duży podzbiór, gdy twój skrypt działa na hostingu w chmurze, a przeglądarka nie. Nie naprawi brakującego referera, nieobecnego ciasteczka ani wyzwania JavaScript. Najpierw przetestuj nagłówki, ponieważ nic nie kosztują, a następnie zmień wyjściowy IP, aby wyizolować warstwę sieci.

Nie ma tu tajemnicy, tylko luka: przeglądarka wysłała jedno żądanie, a ty wysłałeś inne. Skopiuj to przeglądarki, zmniejsz je, aż się zepsuje, a zawsze znajdziesz element, który miał znaczenie — zazwyczaj nagłówek, czasami fingerprint, okazjonalnie wyzwanie, które wymaga prawdziwej przeglądarki do odpowiedzi.

[Pobierz dowolną stronę za pomocą Scraper API](https://quantumproxies.io/scraper-api)
