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 taką 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ło 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żde wywołanie Proxy, które wykonało swoje próby i zakończyło się niepowodzeniem, zawiera obiekt attemptReport obok błędu, w tym także takie, które zakończyło się kodem "error": "Timeout". Nazwa hosta, która się nie rozwiązuje, kończy się błędem przed jakąkolwiek próbą, ze statusem status: 0 i bez raportu. Zlicza to, na co faktycznie 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 celowo pozostaje niezmieniony, aby klient dopasowujący się do niego nadal działał. Odczytaj attemptReport.summary, aby uzyskać jednozdaniową odpowiedź, lub użyj liczników, jeśli chcesz na ich podstawie tworzyć warunki logiczne.

Pola

Pole Typ Co zlicza
total integer Podjęte próby
noResponse integer Węzeł wyjściowy nie odpowiedział lub strona nie odpowiedziała na czas
defense integer Strona odpowiedziała i w tej odpowiedzi rozpoznano dostawcę weryfikacji botów
contentRejected integer HTTP 200, brak weryfikacji botów, odrzucono tylko przez Twoje validate.data
statusRejected integer Strona odpowiedziała, brak weryfikacji botów, odrzucono przez Twoje validate.status
other integer Odpowiedziano i żaden z powyższych przypadków nie wystąpił
vendors string[] Każdy dostawca weryfikacji botów rozpoznany w dowolnym miejscu zadania
profilesTried string[] Profile przeglądarek wysłane przez zadanie, w kolejności pierwszego użycia. default oznacza, że żądanie wyszło dokładnie tak, jak zostało napisane.
summary string Jedno zdanie zbudowane na podstawie liczników. Bezpieczne do rejestrowania w logach lub wyświetlenia użytkownikowi.

Interpretacja wyników

contentRejected ma wysoką wartość

Strony zostały pobrane. Twoja reguła validate.data nie została do nich dopasowana.

To problem, który możesz naprawić samodzielnie, i który jest maskowany przez każdy inny sygnał: żądania wyglądają na nieudane w każdej metryce, a FourA przez cały czas dostarczało rzeczywistą treść. Pobierz stronę raz przez POST /api/single/ całkowicie bez validate, zobacz, co faktycznie wraca, i napisz regułę na nowo na podstawie otrzymanej odpowiedzi.

Częstą przyczyną jest jedna reguła zastosowana do zestawu stron, które nie są identyczne. Selektor, który istnieje na stronach artykułów, a nie istnieje na stronach wideo, zawiedzie za każdym razem, gdy trafi na stronę wideo, bez końca, generując pełny koszt.

statusRejected ma wysoką wartość

Strona odpowiedziała, a Twoja reguła validate.status ją odrzuciła. Jeśli te statusy to 401, 403, 429 lub 503, strona odrzuca klienta, zamiast informować, że strona nie istnieje. Wypróbuj:

  • Inny profil przeglądarki (browser, os, version w wewnętrznym obiekcie request)
  • exitCountries, jeśli treść ma blokadę regionalną
  • POST /api/browser/, jeśli odrzucenie wymaga uruchomienia JavaScriptu do przejścia

defense ma wysoką wartość

W odpowiedziach rozpoznano weryfikację botów, a vendors wskazuje którego dostawcę. Zobacz Site checks, aby dowiedzieć się, co FourA obecnie omija, a co jedynie raportuje. Jeśli dostawca nie jest omijany na tym punkcie końcowym, przenieś wywołanie do POST /api/browser/ lub POST /api/auto/.

noResponse ma wysoką wartość

Węzły wyjściowe w ogóle nie odpowiedziały, więc niczego nie ustalono na temat celu. Zwiększ maxTries, zwiększ timeout_ms i sprawdź, czy adres URL jest osiągalny z publicznego internetu.

other ma wysoką wartość

Strona odpowiedziała ze statusem, nie rozpoznano weryfikacji botów, a próba nie powiodła się z innego powodu, takiego jak reguła validate.headers. Cel wolniejszy niż Twój timeout_ms jest zliczany w noResponse.

Rotacja profili przeglądarki

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 żadnej dodatkowej próby: rotacja zmienia to, co wysyła ponowienie, a nie to, czy w ogóle do niego dochodzi.

Proxy zapamiętuje również dla każdej witryny rodzinę, która ostatnio tam zadziałała po odrzuceniu wartości domyślnej. Kolejny request do tej witryny może wystartować z tej rodziny już przy pierwszej próbie, a FourA przechodzi do następnej rodziny, gdy witryna zacznie odrzucać również tę. Przeglądarka mobilna jest zapamiętywana tylko dla witryny zwracającej JSON.

profilesTried pozwala sprawdzić ten proces. Jeden wpis oznacza, że każda próba wysłała tę samą przeglądarkę: default to request w pierwotnej postaci, a identyfikator z katalogu to rodzina, której FourA nauczyło się wcześniej dla tej witryny. Kilka wpisów oznacza, że uruchomiono rotację i witryna odrzuciła każdą z nich, co jest inną sytuacją niż brak jakiejkolwiek rotacji.

W udanym response 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ść to identyfikator katalogowy z GET /api/profiles. Brak oznacza, że request został wysłany dokładnie w podanej postaci. Obecność oznacza, że przeglądarka, która zadziałała, była inna niż wpisana, więc w kolejnych wywołaniach przekaż ten identyfikator jako profile zamiast powtarzać ten, który zawiódł. Dashboard Playground robi to automatycznie za pomocą opcji Carry.

Jawnie zdefiniowane parametry profile, browser, os lub version w Twoim requeście nigdy nie są nadpisywane. Dotyczy to również requestu zawierającego 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", [])))
Aktualizacja: 30 września 2026