أسباب استنفاد محاولات Proxy Request
المشكلة
يعود استدعاء 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 حاليًا وما تكتفي بالإبلاغ عنه فقط. إذا لم يكن المزود من بين المزودين الذين يتم تجاوزهم على هذا الـ endpoint، فانقل الاستدعاء إلى POST /api/browser/ أو POST /api/auto/.
noResponse مرتفع
لم تستجب عقد الخروج على الإطلاق، لذا لم يتم معرفة أي شيء عن الهدف. ارفع قيمة maxTries، وارفع قيمة timeout_ms، وتحقق من إمكانية حل عنوان URL عبر شبكة الإنترنت العامة.
other مرتفع
استجاب الموقع برمز حالة، ولم يتم التعرف على أي فحص بوتات، وفشلت المحاولة لسبب آخر، مثل قاعدة validate.headers. يُحسب الهدف الأبطأ من قيمة timeout_ms الخاصة بك ضمن noResponse.
تدوير ملف تعريف المتصفح (Browser Profile Rotation)
عندما يرفض موقع ما المتصفح الذي أرسلته FourA، يتوقف Proxy عن الإصرار عليه ويجرب عائلة أخرى من public profile catalogue. لا يكلف ذلك أي محاولة إضافية: يغير التدوير ما يرسله retry، ولا يحدد أبدا ما إذا كان سيحدث.
يتذكر Proxy أيضا، لكل موقع، العائلة التي نجحت هناك مؤخرا بعد أن رفض الموقع الإعداد الافتراضي. يمكن لـ request لاحق إلى ذلك الموقع أن يبدأ بتلك العائلة من محاولته الأولى، وتنتقل FourA إلى العائلة التالية بمجرد أن يبدأ الموقع في رفض تلك أيضا. يتم تذكر متصفح الهاتف فقط للموقع الذي يستجيب بـ JSON.
profilesTried هي الطريقة التي ترى بها حدوث ذلك. إدخال واحد يعني أن كل محاولة أرسلت نفس المتصفح: default هو الـ request كما هو مكتوب، و catalogue id هو العائلة التي تعلمتها FourA بالفعل لذلك الموقع. وجود عدة إدخالات يعني أن التدوير قد تم ورفض الموقع كل منها، وهي حالة مختلفة عن عدم التدوير على الإطلاق.
في response الـ Proxy الناجحة، يظهر حقل profile فقط عندما يختار التدوير متصفحا لم تطلبه:
{
"status": 200,
"data": "<!doctype html>...",
"proxy": "A1B2C3",
"profile": "...",
"total": 4.108
}
القيمة هي معرف كتالوج من GET /api/profiles. الغياب يعني أن الطلب قد أُرسل تمامًا كما كُتب. الوجود يعني أن المتصفح الذي نجح لم يكن هو المتصفح الذي أدخلته، لذا مرر هذا المعرف كـ profile في الاستدعاءات اللاحقة بدلًا من إعادة إرسال المتصفح الذي فشل. تقوم لوحة تحكم Playground بذلك نيابة عنك عبر Carry.
لا يتم أبدًا تجاوز أي تعيين صريح لـ profile أو browser أو os أو version في طلبك. ولا ينطبق التجاوز أيضًا على طلب يحمل ترويسة User-Agent أو Cookie الخاصة بك، نظرًا لأن التصريح (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", [])))
ذات صلة
- API Endpoints: مرجع كامل لطلبات واستجابات Proxy
- Site checks: المزودون، و
defense، وإعادة تشغيل التصريح - Request Outcomes: كيفية تصنيف الاستجابة المرفوضة واحتساب تكلفتها
- Common Issues: مشكلات أخرى وحلولها
- Choosing the Right Endpoint: متى يكون Proxy هو الأداة غير المناسبة