Защо proxy заявката изчерпа опитите си

Проблемът

POST /api/proxy/ извикване се връща с грешка и без данни. Съобщението е кратко и винаги в същия формат:

{
  "error": "Download maxTry limit reached",
  "total": 34.812,
  "request": { "...": "..." }
}

Това изречение звучи по един и същ начин, независимо дали всеки изходен възел е бил блокиран, всеки изходен възел не е работил или FourA е извлякъл реалната страница при почти всеки опит, а вашите собствени validate правила са я отхвърлили. Тези три случая изискват напълно противоположни решения.

Отговорът: attemptReport

Всяко Proxy извикване, което е изпълнило своите опити и се е провалило, съдържа attemptReport обект заедно с грешката, включително и такова, което е завършило с "error": "Timeout". Име на хост, което не може да бъде резолвнато, се проваля преди какъвто и да е опит, с status: 0 и без отчет. Той отчита с какво всъщност са се сблъскали опитите:

{
  "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
}

Низът error е умишлено непроменен, така че клиент, който прави съпоставка по него, да продължи да работи. Прочетете attemptReport.summary за отговор в един ред или броячите, когато искате да разклонявате логиката според тях.

Полета

Поле Тип Какво брои
total integer Направени опити
noResponse integer Изходната точка не отговори или сайтът не отговори навреме
defense integer Сайтът отговори и при този отговор беше разпознат доставчик на защита срещу ботове
contentRejected integer HTTP 200, без защита срещу ботове, отхвърлено единствено от вашето validate.data
statusRejected integer Сайтът отговори, без защита срещу ботове, отхвърлено от вашето validate.status
other integer Получен е отговор и нито едно от горните не е налице
vendors string[] Всеки доставчик на защита срещу ботове, разпознат някъде в рамките на задачата
profilesTried string[] Профилите на браузъра, които задачата изпрати, подредени по първо използване. default означава, че заявката е изпратена точно както сте я написали.
summary string Едно изречение, съставено от броячите. Безопасно за записване в логове или показване на потребител.

Разчитане

contentRejected е с висока стойност

Страниците са получени. Вашето правило validate.data не съвпада с тях.

Това е проблемът, който можете да поправите сами, и е този, който всеки друг сигнал скрива: заявките изглеждат като неуспешни във всяка метрика, а FourA през цялото време е доставял реално съдържание. Изтеглете страницата веднъж през POST /api/single/ без никакво validate, вижте какво всъщност се връща и пренапишете правилото спрямо него.

Честа причина е прилагането на едно правило към набор от страници, които не са напълно еднакви. Селектор, който съществува на страници с новини, но не и на страници с видеоклипове, се проваля всеки път, когато попадне на страница с видео, непрекъснато, при пълна цена.

statusRejected е с висока стойност

Сайтът отговори и вашето правило validate.status върна отказ. Ако тези статуси са 401, 403, 429 или 503, сайтът отказва достъп на клиента, вместо да казва, че страницата липсва. Опитайте:

  • Друг браузърен профил (browser, os, version във вътрешния обект request)
  • exitCountries, ако съдържанието е ограничено по регион
  • POST /api/browser/, ако отказът изисква JavaScript за преодоляване

defense е с висока стойност

В отговорите беше разпозната защита срещу ботове, а vendors посочва коя точно. Вижте Site checks за това какво FourA преодолява в момента и за какво само докладва. Ако доставчикът не е сред тези, които се преодоляват на тази крайна точка, преместете извикването към POST /api/browser/ или POST /api/auto/.

noResponse е с висока стойност

Изходните точки изобщо не отговориха, така че нищо не беше научено за целта. Увеличете maxTries, увеличете timeout_ms и проверете дали URL адресът се разрешава от публичния интернет.

other е с висока стойност

Сайтът отговори със статус, не беше разпозната защита срещу ботове и опитът беше неуспешен по друга причина, като например правило validate.headers. Цел, която е по-бавна от вашето timeout_ms, се отчита в noResponse.

Ротация на профила на браузъра

Когато даден сайт отхвърли браузъра, изпратен от FourA, Proxy спира да настоява за него и опитва друга фамилия от публичния каталог с профили. Това не струва допълнителен опит: ротацията променя това, което изпраща повторният опит, а не дали изобщо се извършва такъв.

Proxy също така запомня за всеки сайт фамилията, която последно е сработила там, след като сайтът е отказал браузъра по подразбиране. Следващ request към този сайт може да стартира с тази фамилия още от първия си опит, като FourA преминава към следващата фамилия, щом сайтът започне да отхвърля и нея. Мобилен браузър се запомня само за сайт, който връща JSON.

profilesTried показва как се случва това. Един запис означава, че всеки опит е изпратил същия браузър: default е подаденият request, а catalogue id е фамилията, която FourA вече е научил за този сайт. Няколко записа означават, че ротацията е била изпълнена и сайтът е отхвърлил всеки от тях, което е различна ситуация от това изобщо да не е имало ротация.

При успешен Proxy response полето profile се появява само когато ротацията е избрала браузър, който не сте заявили:

{
  "status": 200,
  "data": "<!doctype html>...",
  "proxy": "A1B2C3",
  "profile": "...",
  "total": 4.108
}

Стойността е catalogue id от GET /api/profiles. Липсата му означава, че заявката е изпратена точно както е написана. Наличието му означава, че браузърът, който е сработил, не е бил този, който сте въвели, така че подайте това id обратно като profile при следващи извиквания, вместо да повтаряте неуспешния. Playground в таблото прави това вместо вас чрез Carry.

Изрично зададен profile, browser, os или version във вашата заявка никога не се презаписва. Същото важи и за заявка, съдържаща ваш собствен User-Agent или Cookie header, тъй като clearance е обвързан с подписа, чрез който е получен.

Четене в код

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", [])))
Обновено: 30 септември 2026 г.