Почему исчерпаны попытки выполнения proxy-request
Проблема
Вызов POST /api/proxy/ возвращает ошибку без данных. Сообщение короткое и всегда имеет одну и ту же структуру:
{
"error": "Download maxTry limit reached",
"total": 34.812,
"request": { "...": "..." }
}
Эта фраза выглядит одинаково независимо от того, были ли заблокированы все выходные узлы, были ли они нерабочими, или FourA успешно получал реальную страницу почти при каждой попытке, а ваши собственные правила validate ее отбрасывали. Для этих трех случаев требуются совершенно разные решения.
Ответ: attemptReport
Каждый неудачный ответ Proxy содержит объект attemptReport рядом с ошибкой. Он подсчитывает, с чем именно столкнулись попытки:
{
"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 указывает конкретную систему. Смотрите Anti-Bot Defenses, чтобы узнать, какие системы FourA обходит автоматически, а о каких только сообщает. Если провайдер защиты не обходится на этом endpoint, перенаправьте вызов в POST /api/browser/ или POST /api/auto/.
Высокое значение noResponse
Выходные узлы вообще не ответили, поэтому информацию о целевом ресурсе получить не удалось. Увеличьте maxTries, увеличьте timeout_ms и проверьте доступность URL из публичного интернета.
Высокое значение other
Ответ получен, но не классифицирован ни одной из категорий выше. Проверьте total_time относительно вашего timeout_ms: слишком медленный ответ целевого ресурса попадает сюда.
Ротация профилей браузера
Когда сайт отклоняет браузер, отправленный FourA, Proxy прекращает его использовать и пробует другое семейство из каталога публичных профилей. Это не расходует дополнительную попытку: ротация меняет параметры повторного запроса, но не влияет на сам факт его отправки.
profilesTried позволяет отслеживать этот процесс. Одна запись означает, что запрос каждый раз отправлялся в исходном виде. Несколько записей означают, что ротация сработала и сайт отклонил каждую попытку, что отличается от ситуации полного отсутствия ротации.
В успешном ответе Proxy поле profile появляется только тогда, когда в процессе ротации был выбран браузер, который вы не запрашивали:
{
"status": 200,
"data": "<!doctype html>...",
"proxy": "A1B2C3",
"profile": "...",
"total": 4.108
}
Значение представляет собой идентификатор каталога из GET /api/profiles. Отсутствие означает, что request был отправлен в точности как указано. Наличие означает, что сработавший браузер отличался от указанного вами, поэтому передавайте этот id как profile в последующих вызовах вместо повторной отправки завершившегося ошибкой. Playground в дашборде делает это автоматически с помощью опции Carry.
Явно указанные в вашем request параметры profile, browser, os или version никогда не перезаписываются. То же касается и request с вашим собственным header User-Agent или Cookie, поскольку clearance привязан к сигнатуре, с помощью которой он был получен.
Reading It in Code
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", [])))
Связанные разделы
- API Endpoints: Полный справочник по request и response в Proxy
- Anti-Bot Defenses: Вендоры,
defenseи повторное использование clearance - Request Outcomes: Классификация и тарификация отклоненных response
- Common Issues: Другие проблемы и способы их решения
- Choosing the Right Endpoint: Когда Proxy не подходит