Cloudflare Turnstile بديل للكابتشا يركّز على الخصوصية ويعمل بصمت في الخلفية. على عكس الكابتشا التقليدية، نادراً ما يعرض تحدياً مرئياً؛ بل يجمع إشارات المتصفح ويُصدر رمزاً (token) يتحقق منه الخادم الخلفي للموقع.
يوضح هذا الدليل كيف تحلّ Turnstile برمجياً عبر واجهة CaptchaAI. إن لم تقرأ بعدُ دليل البدء السريع لـ CaptchaAI فابدأ به لفهم تدفّق الخطوات الأربع العام.
المتطلبات
| العنصر | القيمة |
|---|---|
| مفتاح CaptchaAI API | من لوحة التحكم على captchaai.com |
| sitekey الخاص بـ Turnstile | يُستخرج من الصفحة (يبدأ بـ 0x) |
| رابط الصفحة | الرابط الكامل الذي يظهر فيه Turnstile |
| اللغة | Python 3.7+ أو Node.js 14+ |
الخطوة 1: استخرج sitekey
عادةً يوجد sitekey داخل HTML الصفحة، ضمن وسم div أو script:
<div class="cf-turnstile" data-sitekey="0x4AAAAAAAC3DHQFLr1GavNl"></div>
أو يُرسم عبر JavaScript:
turnstile.render('#widget', {
sitekey: '0x4AAAAAAAC3DHQFLr1GavNl',
callback: function(token) { /* ... */ }
});
ثلاث طرق للاستخراج:
- أدوات المطور: تبويب Elements، ابحث عن
data-sitekeyأوcf-turnstile. - شيفرة المصدر:
Ctrl+U، ثم ابحث عن سلاسل تبدأ بـ0x. - تبويب Network: فلتر بـ
challenges.cloudflare.com؛ يظهر sitekey ضمن وسائط الطلب.
sitekey الخاص بـ Turnstile يبدأ دائماً بـ
0xوطوله غالباً 22 محرفاً، مما يميّزه عن مفاتيح reCAPTCHA التي تبدأ بـ6L.
الخطوة 2: أرسل المهمة
أرسل طلب POST إلى https://ocr.captchaai.com/in.php بقيمة method=turnstile:
import requests
API_KEY = "YOUR_CAPTCHAAI_KEY"
SITEKEY = "0x4AAAAAAAC3DHQFLr1GavNl"
PAGEURL = "https://example.com/login"
r = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile",
"sitekey": SITEKEY,
"pageurl": PAGEURL,
"json": 1,
})
data = r.json()
if data["status"] != 1:
raise RuntimeError(f"submit failed: {data}")
task_id = data["request"]
print("task id:", task_id)
نظيره بـ Node.js:
const axios = require("axios");
const { data } = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: {
key: process.env.CAPTCHAAI_KEY,
method: "turnstile",
sitekey: "0x4AAAAAAAC3DHQFLr1GavNl",
pageurl: "https://example.com/login",
json: 1,
},
});
if (data.status !== 1) throw new Error(`submit failed: ${JSON.stringify(data)}`);
const taskId = data.request;
استجابة النجاح: {"status": 1, "request": "<task_id>"}. احفظ task_id للاستطلاع.
الخطوة 3: استطلع النتيجة
يحلّ Turnstile عادةً خلال 10–25 ثانية. انتظر 10 ثوانٍ ثم استطلع كل 5 ثوانٍ بحدّ أقصى 40 محاولة:
import time
time.sleep(10)
for _ in range(40):
r = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
})
res = r.json()
if res["status"] == 1:
token = res["request"]
break
if res["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(f"solver error: {res}")
time.sleep(5)
else:
raise TimeoutError("turnstile solving timed out")
print("token (أوّل 60 محرفاً):", token[:60])
الرمز المُعاد سلسلة Base64 تبدأ غالباً بمقدمة من الصفر متبوعة بنقطة، ويتراوح طولها بين 400 و600 محرف.
الخطوة 4: احقن الرمز في الصفحة
ضع الرمز داخل الحقل المخفي cf-turnstile-response في نموذج Turnstile ثم أرسل النموذج.
Selenium:
driver.execute_script(
"document.querySelector('[name=cf-turnstile-response]').value = arguments[0];",
token,
)
driver.find_element("css selector", "form").submit()
Playwright:
page.evaluate(
"(t) => document.querySelector('[name=cf-turnstile-response]').value = t",
token,
)
page.click("button[type=submit]")
HTTP خام: أضف cf-turnstile-response=<token> إلى جسم الطلب application/x-www-form-urlencoded.
صلاحية رمز Turnstile حوالي 120–300 ثانية. استخدمه فور استلامه وإلا سيرجع الخادم خطأ
timeout-or-duplicate.
مثال Python كامل
import os, time, requests
API = "https://ocr.captchaai.com"
KEY = os.environ["CAPTCHAAI_KEY"]
def solve_turnstile(sitekey: str, pageurl: str) -> str:
r = requests.post(f"{API}/in.php", data={
"key": KEY, "method": "turnstile",
"sitekey": sitekey, "pageurl": pageurl, "json": 1,
}, timeout=30)
j = r.json()
if j["status"] != 1:
raise RuntimeError(f"submit: {j}")
tid = j["request"]
time.sleep(10)
for _ in range(40):
r = requests.get(f"{API}/res.php", params={
"key": KEY, "action": "get", "id": tid, "json": 1,
}, timeout=30)
j = r.json()
if j["status"] == 1:
return j["request"]
if j["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(f"poll: {j}")
time.sleep(5)
raise TimeoutError("timeout")
if __name__ == "__main__":
print(solve_turnstile("0x4AAAAAAAC3DHQFLr1GavNl", "https://example.com/login"))
الأخطاء الشائعة
| الكود | المعنى | الإجراء |
|---|---|---|
ERROR_WRONG_USER_KEY |
تنسيق المفتاح غير صحيح | تأكد من اكتمال CAPTCHAAI_KEY |
ERROR_KEY_DOES_NOT_EXIST |
المفتاح غير موجود | انسخه من جديد من لوحة التحكم |
ERROR_ZERO_BALANCE |
الرصيد صفر | اشحن الحساب وأعد المحاولة |
ERROR_PAGEURL |
وسيط pageurl ناقص | أرسل الرابط الكامل مع https:// |
ERROR_CAPTCHA_UNSOLVABLE |
فشل الحل بعد عدة محاولات | تحقق من تطابق sitekey وpageurl وأعد المحاولة |
تجد جدول الأخطاء الكامل في دليل reCAPTCHA v2.
حين لا يعمل
- sitekey ديناميكي. بعض مواقع Cloudflare تُصدر sitekey جديداً مع كل زيارة؛ أعد جلب الصفحة قبل كل مهمة.
- pageurl دقيق. يقارن خادم Turnstile الرابط بصرامة؛ أرسل المسار الفعلي بدون معاملات الاستعلام.
- بصمة TLS. قد ترفض Cloudflare العميل بناءً على بصمة TLS. استعن بـ
curl_cffiأو Playwright أو متصفح حقيقي. - انتهاء صلاحية الرمز. استخدم الرمز خلال دقيقتين وإلا ستحتاج إلى إعادة الحل.
- جودة البروكسي. عناوين IP الرخيصة لمراكز البيانات تستفز تحديات إضافية؛ يُفضّل البروكسي السكني أو الجوّال.