PHP cURL Proxy Scraping: CURLOPT_PROXY, Auth i Guzzle
Większość fragmentów kodu proxy w PHP dostępnych online wciąż zawiera te same trzy błędy z 2011 roku. Oto czysta konfiguracja CURLOPT_PROXY — autoryzacja, SOCKS5, rotacja curl_multi, Guzzle i limity czasu — która sprawdza się w produkcji.
Kod proxy PHP cURL ma specyficzny problem: najwyżej oceniane fragmenty mają dekadę, a wiele z nich zawiera prawdziwe błędy — podwójne wywołania curl_exec(), które uruchamiają każde żądanie dwa razy, CURLOPT_SSL_VERIFYPEER wyłączone "aby HTTPS działało", opcje ustawione na wartości, które już były domyślne. Ten przewodnik to aktualna, poprawna wersja: CURLOPT_PROXY z autoryzacją, SOCKS5, równoległa rotacja z curl_multi, ta sama konfiguracja w Guzzle i limity czasu, które zapobiegają zawieszaniu się pracownika na całą noc.
Minimalny, poprawny przykład proxy PHP cURL
<?php
function fetch(string $url): string|false {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_PROXY => 'http://gate.quantumproxies.io:8000',
CURLOPT_PROXYUSERPWD => 'USER:PASS',
CURLOPT_RETURNTRANSFER => true, // return the body, don't echo it
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3,
CURLOPT_CONNECTTIMEOUT => 10, // seconds to reach the proxy
CURLOPT_TIMEOUT => 30, // seconds for the whole transfer
CURLOPT_ENCODING => '', // accept gzip/br, decode automatically
]);
$body = curl_exec($ch);
if ($body === false) {
error_log('cURL error ' . curl_errno($ch) . ': ' . curl_error($ch));
}
curl_close($ch);
return $body;
}
echo fetch('https://httpbin.org/ip'); // -> the proxy exit IP
Dane uwierzytelniające mogą być umieszczone w CURLOPT_PROXYUSERPWD, jak pokazano, lub w linii w URL proxy (http://USER:PASS@host:port) — obie metody działają. CURLOPT_RETURNTRANSFER to opcja, której początkujący często nie zauważają: bez niej curl_exec() wyświetla odpowiedź bezpośrednio na wyjściu i zwraca true, co nigdy nie jest tym, czego chce scraper. W PHP 8 uchwyt to obiekt CurlHandle, a nie zasób; wywołania opcji pozostają bez zmian.
Opcje, które ludzie kopiują bez zrozumienia (i jeden prawdziwy błąd bezpieczeństwa)
CURLOPT_HTTPPROXYTUNNEL— niepotrzebne dla celów HTTPS. cURL automatycznie ustanawia tunel CONNECT, gdy cel tohttps://; ta opcja wymusza tunelowanie dla celów HTTP, co prawie nigdy nie jest wymagane podczas scrapingu.CURLOPT_CUSTOMREQUEST => 'GET'— GET jest już domyślną metodą; ustawienie jej nic nie zmienia, poza psuciem obsługi przekierowań w skrajnych przypadkach.- Podwójne wywołanie
curl_exec()— klasyczny błąd z Stack Overflow: żądanie uruchamia się dwa razy, a druga wartość zwrotna nadpisuje pierwszą. Raz na uchwyt. CURLOPT_SSL_VERIFYPEER => false— naprawdę niebezpieczny. "Naprawia" błędy certyfikatów, pozwalając na ataki typu man-in-the-middle przy każdym żądaniu. Prawdziwa naprawa, zgodnie z podręcznikiem PHP, polega na wskazaniucurl.cainfow php.ini na aktualny pakietcacert.pem.

SOCKS5 proxy w PHP
<?php
// scheme style: socks5h = DNS resolved by the proxy (use for scraping)
curl_setopt($ch, CURLOPT_PROXY, 'socks5h://USER:PASS@gate.quantumproxies.io:1080');
// split style: same result via CURLOPT_PROXYTYPE
curl_setopt($ch, CURLOPT_PROXY, 'gate.quantumproxies.io:1080');
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'USER:PASS');
Schemat decyduje, gdzie odbywa się rozwiązywanie DNS: socks5:// (i CURLPROXY_SOCKS5) rozwiązuje nazwy hostów na twoim serwerze, ujawniając każdą docelową domenę twojemu lokalnemu resolverowi; socks5h:// (CURLPROXY_SOCKS5_HOSTNAME) rozwiązuje na wyjściu proxy. Preferuj to drugie. QuantumProxies oferuje HTTP i SOCKS5 w każdym planie, więc zmiana protokołów to zmiana jednej linii, a nie nowa subskrypcja. Ta sama zasada DNS dotyczy wiersza poleceń — zobacz nasze przepisy curl proxy dla odpowiedników powłoki wszystkiego na tej stronie.
Rotacja i równoległe żądania z curl_multi
PHP nie ma async/await, ale nie potrzebuje ich do równoległego scrapingu — curl_multi uruchamia dziesiątki transferów jednocześnie w jednym procesie. Skieruj każdy uchwyt na rotującą bramę, a każde żądanie automatycznie wychodzi z innego adresu IP rezydencyjnego, bez konieczności prowadzenia księgowości listy proxy w twoim kodzie:
<?php
$urls = ['https://example.com/p/1', 'https://example.com/p/2', 'https://example.com/p/3'];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
// one gateway, a fresh residential exit per request
CURLOPT_PROXY => 'http://USER:PASS@rotating.quantumproxies.io:8000',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_ENCODING => '',
]);
curl_multi_add_handle($mh, $ch);
$handles[$url] = $ch;
}
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh); // wait for activity instead of spinning
} while ($running > 0);
$results = [];
foreach ($handles as $url => $ch) {
$results[$url] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
Utrzymuj partie umiarkowane — 8 do 16 równoczesnych uchwytów wystarczy dla większości celów, a tempo jest ważniejsze niż czysta prędkość: usleep() o kilka setek milisekund między partiami kosztuje cię niewiele i utrzymuje tempo żądań poniżej progów, które wyzwalają 429. Sprawdź curl_getinfo($ch, CURLINFO_HTTP_CODE) dla każdego uchwytu i kieruj niepowodzenia do kolejki ponownych prób zamiast ponownego pobierania w linii. Gdy przepływ obejmuje kilka żądań, które muszą dzielić jedną tożsamość (logowanie, koszyk, paginacja z ciasteczkami), przełącz ten uchwyt na sesję klejącą, dodając do nazwy użytkownika: USER-session-a1b2c3 utrzymuje ten sam adres IP wyjścia przez cały czas trwania zamiast rotacji.

Nagłówki i ciasteczka: wyglądaj jak przeglądarka, którą twierdzisz, że jesteś
Czysty adres IP wyjściowy z domyślnymi nagłówkami cURL wciąż wygląda jak bot — PHP ogłasza się, chyba że ubierzesz żądanie. Trzy opcje zamykają większość luki: CURLOPT_USERAGENT z aktualnym ciągiem przeglądarki, CURLOPT_HTTPHEADER dla Accept-Language i podobnych, oraz para ciasteczek CURLOPT_COOKIEJAR / CURLOPT_COOKIEFILE wskazująca na ten sam plik, która utrzymuje sesyjne ciasteczka między uchwytami tak, jak robi to przeglądarka. Trwałość ciasteczek ma większe znaczenie, niż się spodziewają ludzie: wiele stron ustawia token przy pierwszym trafieniu i cicho wyzywa klientów, którzy nigdy go nie zwracają. Utrzymuj spójną tożsamość — User-Agent Chrome bez Accept-Language i nagie ustawienie nagłówków to samo w sobie odcisk palca, a sprawdzanie spójności to dokładnie sposób, w jaki średniej klasy dostawcy anty-botów łapią scrapery PHP przy drugim żądaniu.
Guzzle: to samo proxy, lepsza ergonomia
<?php
use GuzzleHttp\Client;
$client = new Client([
'proxy' => 'http://USER:PASS@gate.quantumproxies.io:8000',
'timeout' => 30,
'connect_timeout' => 10,
]);
$res = $client->get('https://httpbin.org/ip');
echo $res->getBody();
// per-request override, e.g. a sticky session for a login flow
$res = $client->get('https://example.com/account', [
'proxy' => 'http://USER-session-a1b2c3:PASS@gate.quantumproxies.io:8000',
]);
Guzzle napędza cURL pod spodem, więc wszystko powyżej nadal ma zastosowanie — po prostu lepiej się czyta. Jedno ostrzeżenie: domyślny timeout w Guzzle to 0, co oznacza czekanie na zawsze. Wyjście proxy, które zatrzymuje się w trakcie transferu, przypnie pracownika PHP-FPM na czas nieokreślony, więc ustaw oba limity czasu na każdym kliencie, którego tworzysz. Opcja proxy akceptuje również tablicę z kluczami http, https i no, gdy potrzebujesz routingu per schemat lub wykluczeń hostów wewnętrznych.
Kiedy PHP cURL przestaje wystarczać
cURL pobiera HTML; nie wykonuje JavaScriptu. Jeśli odpowiedź wraca jako szkielet strony z pustymi divami, dane są renderowane po stronie klienta — nasz przewodnik na temat odpowiedzi pustej strony pokazuje, jak to wykryć. A na twardych celach, sam handshake TLS cURL zdradza cię, niezależnie od tego, jak czysty jest IP (zagadkę przeglądarka działa, cURL 403). PHP nie może rozsądnie uruchamiać przeglądarki bezgłowej na każde żądanie, więc pragmatycznym wyjściem awaryjnym jest Scraper API: jedno wywołanie cURL do jednego punktu końcowego, a renderowanie, odciski palców przeglądarki, rotacja i parsowanie wracają jako czysty markdown, JSON lub HTML.
Często zadawane pytania
Jak używać proxy z PHP cURL?
Ustaw CURLOPT_PROXY na pełny URL proxy, dodaj CURLOPT_PROXYUSERPWD, jeśli wymaga danych uwierzytelniających, i zawsze włącz CURLOPT_RETURNTRANSFER plus wyraźne limity czasu. To cały wymagany zestaw — cele HTTPS tunelują automatycznie, a wszystko inne to opcjonalne dostrajanie.
Jak przekazać nazwę użytkownika i hasło proxy w PHP?
Albo curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'user:pass'), albo osadź je w URL: http://user:pass@host:port. Jeśli otrzymasz HTTP 407, proxy odrzuciło te dane uwierzytelniające — sprawdź literówki i zakoduj specjalne znaki w URL. Dostawcy, którzy używają autoryzacji białej listy IP, nie potrzebują żadnych danych uwierzytelniających, gdy tylko IP twojego serwera jest autoryzowane.
Czy PHP cURL może używać proxy SOCKS5?
Tak. Przekaż URL socks5h:// do CURLOPT_PROXY, lub ustaw CURLOPT_PROXYTYPE na CURLPROXY_SOCKS5_HOSTNAME. Preferuj warianty z nazwą hosta nad zwykłym socks5, aby DNS rozwiązywał się na wyjściu proxy, a nie na twoim serwerze — w przeciwnym razie każda docelowa domena wycieka przez twój lokalny resolver.
Co to jest CURLOPT_HTTPPROXYTUNNEL i czy go potrzebuję?
Wymusza na cURL tunelowanie przez proxy za pomocą CONNECT zamiast proszenia proxy o pobranie URL. Dla celów https:// cURL tuneluje automatycznie, więc opcja jest zbędna w prawie całym kodzie scrapingu. Ustaw ją tylko wtedy, gdy potrzebujesz semantyki tunelu dla celu HTTP.
Jak ustawić limit czasu dla PHP cURL przez proxy?
Ustaw oba: CURLOPT_CONNECTTIMEOUT obejmuje dotarcie do proxy i otwarcie tunelu, CURLOPT_TIMEOUT ogranicza cały transfer. Istnieją warianty milisekundowe (_MS) dla bardziej rygorystycznych budżetów. Bez nich zatrzymane wyjście utrzymuje żądanie — a pod PHP-FPM, całego pracownika — do momentu, gdy limit samego serwera WWW go nie zabije.
Skopiuj pierwszy fragment, miej na uwadze listę kontrolną, a PHP jest doskonale solidnym językiem do scrapingu: curl_multi dla równoległości, rotująca brama dla tożsamości, Guzzle dla ergonomii i Scraper API dla stron, które się bronią.
Uruchom swój scraper PHP na adresach IP rezydencyjnych QuantumProxies