Dlaczego wyczerpały się próby żądania proxy
Problem
Wywołanie POST /api/proxy/ zwraca błąd i brak danych. Komunikat jest krótki i ma zawsze tę samą strukturę:
{
"error": "Download maxTry limit reached",
"total": 34.812,
"request": { "...": "..." }
}
To zdanie brzmi identycznie niezależnie od tego, czy każdy węzeł wyjściowy był zablokowany, każdy węzeł wyjściowy był martwy, czy też FourA pobrał właściwą stronę przy niemal każdej próbie, a Twoje własne reguły validate ją odrzuciły. Te trzy przypadki wymagają zupełnie innych rozwiązań.
Rozwiązanie: attemptReport
Każda nieudana odpowiedź proxy zawiera obiekt attemptReport obok błędu. Zlicza on to, na co rzeczywiście natrafiły próby:
{
"error": "Download maxTry limit reached",
"attemptReport": {
"total": 25,
"noResponse": 0,
"defense": 0,
"contentRejected": 25,
"statusRejected": 0,
"other": 0,
"vendors": [],
"profilesTried": ["default"],
"summary": "25 attempt(s): 25 returned HTTP 200 with no defense present and were rejected only by your validate.data - the page was fetched, your content rule did not match it"
},
"total": 34.812
}
Ciąg error został celowo pozostawiony bez zmian, aby klient dopasowujący się do niego nadal działał. Sprawdź attemptReport.summary, aby uzyskać jednoliniową odpowiedź, lub liczniki, gdy chcesz na ich podstawie tworzyć rozgałęzienia logiki.
Pola
| Pole | Typ | Co zlicza |
|---|---|---|
total |
integer | Liczba wykonanych prób |
noResponse |
integer | Węzeł wyjściowy nie odpowiedział, więc strona docelowa nie została osiągnięta |
defense |
integer | Strona odpowiedziała, a w odpowiedzi rozpoznano dostawcę ochrony przed botami |
contentRejected |
integer | HTTP 200, brak weryfikacji botów, odrzucono tylko przez Twoją regułę validate.data |
statusRejected |
integer | Strona odpowiedziała, brak weryfikacji botów, odrzucono przez Twoją regułę validate.status |
other |
integer | Uzyskano odpowiedź, brak dopasowania do powyższych |
vendors |
string[] | Wszyscy dostawcy ochrony przed botami rozpoznani w ramach zadania |
profilesTried |
string[] | Profile przeglądarek wysłane przez zadanie, w kolejności pierwszego użycia. default oznacza, że żądanie zostało wysłane dokładnie w podanej formie. |
summary |
string | Jedno zdanie zbudowane na podstawie liczników. Bezpieczne do zalogowania lub wyświetlenia użytkownikowi. |
Interpretacja wyników
Licznik contentRejected jest wysoki
Strony zostały pobrane. Twoja reguła validate.data ich nie dopasowała.
To problem, który możesz naprawić samodzielnie i który maskują wszystkie inne sygnały: żądania wyglądają na nieudane w każdej metryce, podczas gdy FourA przez cały czas dostarczało rzeczywistą treść. Pobierz stronę raz przez POST /api/single/ całkowicie bez parametru validate, sprawdź, co faktycznie jest zwracane, i napisz regułę na nowo.
Częstą przyczyną jest jedna reguła stosowana do zestawu stron, które nie mają jednolitej struktury. Selektor obecny na stronach artykułów, ale nieobecny na stronach wideo, zawiedzie za każdym razem na stronie wideo, bez końca, generując pełny koszt.
Licznik statusRejected jest wysoki
Strona odpowiedziała, a Twoja reguła validate.status ją odrzuciła. Jeśli te statusy to 401, 403, 429 lub 503, witryna odrzuca klienta, zamiast informować o braku strony. Wypróbuj:
- Inny profil przeglądarki (
browser,os,versionwewnątrz obiekturequest) exitCountries, jeśli treść ma blokadę regionalnąPOST /api/browser/, jeśli ominięcie blokady wymaga obsługi JavaScript
Licznik defense jest wysoki
W odpowiedziach rozpoznano mechanizm weryfikacji botów, a vendors wskazuje konkretnego dostawcę. Zobacz sekcję Anti-Bot Defenses, aby dowiedzieć się, co FourA aktualnie omija, a co jedynie raportuje. Jeśli dany dostawca nie jest omijany na tym punkcie końcowym, przenieś wywołanie do POST /api/browser/ lub POST /api/auto/.
Licznik noResponse jest wysoki
Węzły wyjściowe w ogóle nie odpowiedziały, więc nie uzyskano żadnych informacji o celu. Zwiększ maxTries, zwiększ timeout_ms i sprawdź, czy adres URL jest osiągalny z publicznego internetu.
Licznik other jest wysoki
Odpowiedź została zwrócona, ale nie pasuje do żadnej z powyższych kategorii. Porównaj total_time z parametrem timeout_ms: strona docelowa działająca wolniej niż przewidziany limit trafia do tej kategorii.
Rotacja profili przeglądarek
Gdy witryna odrzuca przeglądarkę wysłaną przez FourA, Proxy przestaje przy niej obstawać i próbuje innej rodziny z publicznego katalogu profili. Nie kosztuje to dodatkowej próby: rotacja zmienia to, co wysyła ponowienie, a nie to, czy w ogóle do niego dochodzi.
profilesTried pozwala zobaczyć, jak to przebiega. Jeden wpis oznacza, że request za każdym razem wychodził w pierwotnej postaci. Kilka wpisów oznacza, że rotacja została wykonana i witryna odrzuciła każdy z wariantów, co jest inną sytuacją niż brak jakiejkolwiek rotacji.
W udanej odpowiedzi Proxy pole profile pojawia się tylko wtedy, gdy rotacja wybrała przeglądarkę inną niż wskazana w zapytaniu:
{
"status": 200,
"data": "<!doctype html>...",
"proxy": "A1B2C3",
"profile": "...",
"total": 4.108
}
Wartość jest identyfikatorem z katalogu GET /api/profiles. Brak oznacza, że request został wysłany dokładnie w pierwotnej postaci. Obecność oznacza, że przeglądarka, która zadziałała, była inna niż podana, więc przekaż ten identyfikator jako profile w kolejnych wywołaniach zamiast ponawiać ten, który zawiódł. Dashboard Playground robi to automatycznie za pomocą opcji Carry.
Jawny parametr profile, browser, os lub version w Twoim requeście nigdy nie jest nadpisywany. Podobnie request zawierający Twój własny header User-Agent lub Cookie, ponieważ clearance jest powiązany z sygnaturą, która go uzyskała.
Odczytywanie w kodzie
import requests
API = "https://eu.api.foura.ai"
H = {"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"}
r = requests.post(f"{API}/api/proxy/", headers=H, json={
"maxTries": 5,
"request": {
"method": "GET",
"url": "https://example.com/product/42",
"validate": {"data": {"accept": ["Add to cart"]}},
},
}).json()
if "error" in r:
rep = r.get("attemptReport", {})
print(rep.get("summary", r["error"]))
if rep.get("contentRejected", 0) > rep.get("total", 0) / 2:
# The pages arrived. The validate rule is what threw them away.
raise SystemExit("validate.data did not match the real page")
if rep.get("defense", 0):
print("bot check met:", ", ".join(rep.get("vendors", [])))
Powiązane
- API Endpoints: Pełna dokumentacja requestów i response'ów Proxy
- Anti-Bot Defenses: Dostawcy,
defensei ponowne użycie clearance - Request Outcomes: Jak odrzucony response jest klasyfikowany i rozliczany
- Common Issues: Inne problemy i ich rozwiązania
- Choosing the Right Endpoint: Kiedy Proxy nie jest właściwym narzędziem