استكشاف الأخطاء

رمز Turnstile غير صالح بعد الحل: التشخيص والإصلاحات

عبارة «الرمز غير صالح» في Turnstile نادراً ما تعني أن الحل نفسه فشل. الرمز الذي أعادته لك CaptchaAI سليم؛ ما ينكسر هو الطريق بين لحظة استلامه ولحظة وصوله إلى خادم الموقع. وستّ نقاط فقط قادرة على كسر هذا الطريق: مهلة صلاحية انقضت أثناء الانتظار، مفتاح موقع لا يخصّ النموذج الذي ترسله، اسم حقل لا يقرأه الخادم، جلسة غير التي حمّلت الصفحة، رمز مستهلَك أُعيد إرساله، ومعاملات action أو cData لم تُمرَّر عند الحل. نمرّ عليها بالترتيب الذي يوفّر أطول وقت تشخيص، بدءاً بفحص سريع يحدّد أيّها يخصّك.

فحص سريع قبل أن تفتح الكود

اسأل نفسك هذه الأسئلة بالترتيب، وتوقّف عند أول إجابة بـ«لا» — فهي سببك على الأرجح:

  1. هل أرسلت الرمز خلال ثوانٍ من استلامه، لا بعد دقائق من الانتظار؟
  2. هل جاء مفتاح الموقع من نفس عنصر <form> الذي ترسل إليه الطلب؟
  3. هل يظهر الاسم cf-turnstile-response حرفياً في حمولة الطلب؟
  4. هل حمّلت الصفحة وأرسلت النموذج داخل الجلسة نفسها؟
  5. هل هذا رمز جديد لم يسبق إرساله في أي محاولة؟

إن كانت الإجابات الخمس «نعم»، فالمشكلة شبه محصورة في معاملات action وcData — وهي السبب السادس والأخير هنا.

اربط ما تراه في السجلّ بالسبب الأرجح

لكل شكل من أشكال الرفض بصمة مختلفة في مخرجات السكربت:

ما يظهر في السجلّ السبب الأرجح
استجابة 403 مباشرة بعد إرسال الرمز انتهت مهلة الرمز قبل وصوله إلى الخادم
النموذج يُرسَل ولا شيء يحدث ولا رسالة خطأ اسم الحقل الذي وضعت فيه الرمز غير صحيح
الرمز يُقبل ثم يُحظر الإجراء نفسه مفتاح الموقع يخصّ أداة أخرى في الصفحة
المحاولة الأولى تنجح والثانية تفشل إعادة استخدام رمز مستهلَك
يعمل يدوياً في المتصفح ويفشل داخل السكربت ملفات تعريف ارتباط أو رؤوس ناقصة

مهلة رمز Turnstile: 300 ثانية على الورق وأقل عملياً

تُصدر Cloudflare رمز Turnstile بصلاحية قصيرة — 300 ثانية في الإعداد الافتراضي، وبعض التطبيقات تختصرها أكثر. والمهم أن العدّاد يبدأ لحظة إصدار الرمز لا لحظة وصوله إليك: زمن الاستطلاع الدوري للنتيجة وأي انتظار داخل سكربتك يُقتطعان من الرصيد نفسه. يُحلّ Turnstile لدى CaptchaAI عادةً في أقل من 10 ثوانٍ، فالثواني الضائعة بعد ذلك تعود إلى تصميم سير عملك.

الإصلاح: اجعل إرسال النموذج الخطوة التالية مباشرة بعد استلام الرمز، بلا خطوات وسيطة مثل تخزينه أو تمريره إلى عملية أخرى.

import requests
import time

API_KEY = "YOUR_API_KEY"

# Submit Turnstile task
submit = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": "0x4AAAAAAADnPIDROz1234",
    "pageurl": "https://example.com/login",
    "json": 1
}).json()

task_id = submit["request"]
time.sleep(10)

# Poll for result
for _ in range(24):
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY, "action": "get", "id": task_id, "json": 1
    }).json()
    if result.get("status") == 1:
        token = result["request"]
        # USE TOKEN IMMEDIATELY — do not delay
        response = requests.post("https://example.com/login", data={
            "username": "user",
            "password": "pass",
            "cf-turnstile-response": token
        })
        break
    time.sleep(5)

مفتاح الموقع الصحيح عندما تحمل الصفحة أكثر من أداة

لكل أداة Turnstile في الصفحة مفتاح موقع خاص بها. صفحة تسجيل دخول تحوي أيضاً نموذج اشتراك بريدي أو بحثاً محمياً تحمل مفتاحين أو أكثر، ونسخ أول مفتاح تجده يعطيك رمزاً صالحاً تقنياً لا يخصّ النموذج الذي ترسله — فيمرّ شكلياً ويُحظر الإجراء.

استخرج كل المفاتيح الموجودة في الصفحة أولاً:

// In browser console on the target page
document.querySelectorAll('[data-sitekey]').forEach(el => {
    console.log('Sitekey:', el.getAttribute('data-sitekey'));
    console.log('Element:', el);
});

إن ظهر أكثر من مفتاح، اختر المفتاح الموجود داخل نفس عنصر <form> الذي ترسل إليه الطلب، لا الأول في ترتيب الصفحة.

اسم الحقل الذي يقرأه الخادم

أكثر خطأ يتكرر عند الانتقال من reCAPTCHA إلى Turnstile هو نسخ منطق الإرسال كما هو. يتوقع Turnstile الرمز في cf-turnstile-response، وليس g-recaptcha-response. والخادم يقرأ الحقل باسمه فقط؛ وإن لم يجده عامل الطلب وكأنه بلا تحقق، وغالباً يفشل بصمت بلا خطأ واضح.

# WRONG — this is for reCAPTCHA
data = {"g-recaptcha-response": token}

# CORRECT — this is for Turnstile
data = {"cf-turnstile-response": token}

وبعض المواقع تغلّف الحقل باسم مخصّص داخل بنية النموذج. افحص ما تملؤه الأداة فعلياً قبل أن تفترض الاسم:

// Check what field the Turnstile widget populates
document.querySelector('[name*="turnstile"], [name*="cf-"]')

الجلسة نفسها من تحميل الصفحة حتى الإرسال

تربط Cloudflare الرمز بسياق الجلسة التي عُرض فيها التحدي، وفي مقدمته ملفات تعريف الارتباط. فإن حمّلت الصفحة بعميل HTTP وأرسلت النموذج بعميل آخر — أو أنشأت Session جديدة بين الخطوتين — فأنت ترسل رمزاً صحيحاً من هوية شبكية لا تعرفها Cloudflare، والنتيجة رفض يصعب إعادة إنتاجه.

القاعدة العملية: كائن جلسة واحد، وخادم وسيط واحد، وسلسلة User-Agent واحدة، من أول طلب حتى آخره.

# Use the SAME session for page load and token submission
session = requests.Session()

# Load the page first to establish cookies
session.get("https://example.com/login")

# Then solve and submit using the same session
token = solve_turnstile(sitekey, pageurl)
session.post("https://example.com/login", data={
    "cf-turnstile-response": token
})

معاملات action وcData: التفاصيل التي تُنسى

بعض تطبيقات Turnstile تربط الرمز بقيمة action — مثل login أو checkout — أو ببيانات cData تُولَّد داخل الصفحة. وإن لم تمرّرها لحظة الحل، سيُرفض الرمز مهما أصلحت قبله، لأن الخادم يقارن ما بداخله بما يتوقعه.

ابحث في مصدر الصفحة عن turnstile.render أو عن السمتين data-action وdata-cdata، ثم مرّر ما تجده مع طلب الحل:

submit = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": "0x4AAAAAAADnPIDROz1234",
    "pageurl": "https://example.com/login",
    "action": "login",           # If required by the site
    "data": "custom_cdata_value", # If required by the site
    "json": 1
}).json()

أعد المحاولة بدون إعادة استخدام الرمز

يُستهلك رمز Turnstile عند أول تحقق يصل إلى الخادم، فلا يصلح لمحاولة ثانية. والمشكلة أن أغلب طبقات إعادة المحاولة الجاهزة تعيد إرسال الحمولة نفسها كما هي، فيظهر الرفض وكأنه تدهور في جودة الحل.

اجعل دورة إعادة المحاولة تبدأ من الحل لا من الإرسال:

  1. اطلب رمزاً جديداً من الـ API في كل محاولة.
  2. أعد بناء حمولة الطلب بالرمز الجديد بدل تعديل نسخة قديمة.
  3. أضف تراجعاً أسياً بين المحاولات كي لا تستهلك الـ threads بلا فائدة.
  4. سجّل معرّف مهمة الحل مع كل محاولة ليبقى تتبّع أي رمز رُفض ولماذا ممكناً.

سيناريو تطبيقي: مراقبة توافر منتجات في متاجر الخليج

فريق في الرياض يتابع توافر المنتجات ليلياً على متاجر إقليمية يحمي بعضها نماذج البحث بـ Turnstile. كان السكربت يعمل على دفعتين: يحلّ الرموز أولاً لكل الروابط، ثم يرسل بالتسلسل. النتيجة أن أول عشرة روابط تمرّ والبقية تُرفض، لأن آخر رمز في الدُفعة أمضى أكثر من خمس دقائق في الانتظار قبل دوره.

الإصلاح لم يكن في جودة الحل بل في التزامن: اربط كل رمز بطلبه مباشرة، وشغّل مسارات متوازية بدل الدُفعة الواحدة. خطة ADVANCE — $90 شهرياً مع 50 thread — تتيح خمسين عملية حل متزامنة، فتنكمش المسافة بين الحل والإرسال إلى ثوانٍ. والفوترة على عدد الـ threads لا على عدد عمليات الحل، فلا يرفع التزامن تكلفة الرمز الواحد.

ولحجم أصغر — سكربت اختبار جودة يومي — تكفي خطة BASIC — $15 شهرياً مع 5 threads — والقاعدة نفسها: لا تفصل بين الحل والإرسال.

شجرة قرار سريعة

Token solved but rejected
    ↓
Used within 5 minutes? → No → Solve again, submit immediately
    ↓ Yes
Correct sitekey? → No → Find the correct sitekey from the page
    ↓ Yes
Using cf-turnstile-response field? → No → Change field name
    ↓ Yes  
Same session for page load + submit? → No → Use session persistence
    ↓ Yes
Token used only once? → No → Solve a new token per submission
    ↓ Yes
Site requires action/cData? → Check page source, add to API call

أسئلة شائعة

هل يمكن تخزين رمز Turnstile وإعادة استخدامه في طلب آخر؟

لا. الرمز صالح لتحقق واحد فقط، وتنتهي مهلته خلال 300 ثانية من إصداره. أي محاولة لحفظه في ذاكرة مؤقتة أو مشاركته بين عمليتين تنتهي بالرفض. اطلب رمزاً جديداً لكل عملية إرسال.

أرسلت المهمة بطريقة cloudflare_challenge بدل turnstile — هل هذا سبب الرفض؟

نعم، وهو سبب شائع. turnstile مخصّص للأداة المضمّنة داخل الصفحة، وcloudflare_challenge للصفحة الاعتراضية الكاملة التي تسبق المحتوى. الطريقة الخطأ تعيد رمزاً سليم الشكل لا يطابق ما ينتظره الخادم، فيُرفض دون رسالة واضحة.

هل يؤثر الخادم الوسيط أو موقع عنوان IP على قبول الرمز؟

نعم، بشكل غير مباشر. تقيّم Cloudflare سمعة عنوان IP وسياق الجلسة لحظة التحقق، فاستخدام عنوان لتحميل الصفحة وآخر للإرسال يرفع احتمال الرفض حتى لو كان الرمز سليماً. ثبّت الخادم الوسيط طوال دورة الطلب الواحدة.

كيف أميّز مشكلة في الرمز عن مشكلة في الحساب أو الرصيد؟

افحص استجابة res.php أولاً. إذا أعادت الرمز بحالة نجاح، فالحل تمّ والخلل في مرحلة الإرسال. أما أخطاء الحساب أو نفاد الرصيد فتظهر كرمز خطأ نصّي داخل استجابة الـ API نفسها، لا كرفض قادم من الموقع المستهدف.

كم عدد الـ threads الذي أحتاجه لتشغيل عشرات الطلبات بالتوازي؟

عدد الـ threads يساوي عدد عمليات الحل المتزامنة المسموح بها. ولأن Turnstile يُحلّ عادةً في أقل من 10 ثوانٍ، فإن 50 thread في خطة ADVANCE — $90 شهرياً — تكفي لعشرات الطلبات المتوازية دون انتظار. وكل الخطط تشمل عمليات حل غير محدودة داخل الـ thread.

ابدأ بحلّ Turnstile مع CaptchaAI

أنشئ حسابك على captchaai.com واحصل على مفتاح API يعيد رموز Turnstile في أقل من 10 ثوانٍ، جاهزة للإرسال فوراً داخل جلستك.

أدلة ذات صلة

التعليقات غير مفعّلة لهذا المقال.