لحل reCAPTCHA v2 الذي يعتمد على رد النداء لا تحتاج إلى استدعاء مختلف لـ CaptchaAI API؛ أرسل الطلب نفسه كأي reCAPTCHA v2 عادي، لكن بدل كتابة الرمز الناتج في الحقل المخفي g-recaptcha-response، تستدعي دالة JavaScript التي سجّلها الموقع وتمرّر إليها الرمز. هذه الخطوة الأخيرة وحدها هي ما يميّز هذا النوع.
المشكلة التي تقود معظم المطوّرين إلى هنا واضحة: تحصل على رمز صحيح، تحقنه في الحقل المخفي، ثم لا يتفاعل النموذج إطلاقاً. السبب أن الموقع لا يقرأ ذلك الحقل أصلاً، بل ينتظر تشغيل دالة رد النداء. في الأسطر التالية نغطّي كيف تتعرّف على مواقع رد النداء، وكيف تحلّها عبر CaptchaAI، وكيف تستدعي الدالة بشكل صحيح، مع أمثلة جاهزة في Python وNode.js وPHP.
جديد على reCAPTCHA v2؟ ابدأ من دليل حل reCAPTCHA v2 القياسي عبر API لفهم التدفّق الأساسي، ثم عُد إلى هنا لتتعلّم متغيّر رد النداء.
الفرق بين المسار القياسي ومسار رد النداء
النداء إلى CaptchaAI متطابق في الحالتين؛ الفرق الوحيد هو ما تفعله بالرمز بعد استلامه. الجدول التالي يوضّح أين تتفرّع الخطوات:
| الخطوة | reCAPTCHA v2 القياسي | reCAPTCHA v2 برد النداء |
|---|---|---|
| 1. الإرسال إلى CaptchaAI | method=userrecaptcha + مفتاح الموقع + رابط الصفحة |
مطابق |
| 2. استطلاع النتيجة | action=get + معرّف الكابتشا |
مطابق |
| 3. استلام الرمز | تنسيق الرمز نفسه | مطابق |
| 4. حقن الرمز | تعيين قيمة الحقل g-recaptcha-response |
استدعاء دالة رد النداء وتمرير الرمز إليها |
| 5. إرسال النموذج | تشغيل إرسال النموذج | تلقائي غالباً — تتكفّل به دالة رد النداء |
مهم: لا تُعيّن قيمة
g-recaptcha-responseفي المواقع التي تعتمد على رد النداء. تتجاهل الصفحة هذا الحقل وتنتظر تشغيل دالة رد النداء، وتعيينه دون استدعاء الدالة سيجعل الأمر يبدو وكأن الكابتشا لم تُحلّ إطلاقاً.
ما الذي تحتاجه قبل أن تبدأ
| المتطلّب | التفاصيل |
|---|---|
| مفتاح CaptchaAI API | احصل عليه من captchaai.com/api.php. سلسلة من 32 حرفاً. |
| رابط الصفحة المستهدفة | الرابط الكامل للصفحة التي تُحمَّل فيها أداة reCAPTCHA v2. |
| مفتاح موقع reCAPTCHA v2 | المفتاح العام المرتبط بأداة reCAPTCHA على الصفحة. |
| أداة أتمتة متصفح | Selenium أو Puppeteer أو Playwright — تحتاج إلى تنفيذ JavaScript لاستدعاء الدالة. |
| اسم دالة رد النداء | دالة JavaScript التي يتوقّع الموقع أن تستقبل الرمز. |
كيف تعرف أن الموقع يستخدم رد النداء
يكتب reCAPTCHA v2 القياسي الرمز المحلول داخل منطقة نص مخفية اسمها g-recaptcha-response، بينما تتخطّى تطبيقات رد النداء هذا الحقل وتستدعي دالة JavaScript مباشرة. للتمييز بينهما أمامك ثلاث طرق مرتّبة من الأسرع إلى الأعمق:
- فحص السمة
data-callbackعلى عنصر الأداة في مصدر الصفحة. - قراءة خاصية
callbackداخل أي استدعاءgrecaptcha.render(). - تفتيش إعدادات reCAPTCHA الداخلية في الكائن
___grecaptcha_cfg.
الطريقة الأولى: فحص السمة data-callback
افحص عنصر أداة reCAPTCHA في مصدر الصفحة؛ فإن حمل السمة data-callback فالموقع يعتمد رد النداء، وقيمتها — SubmitToken في المثال التالي — هي اسم الدالة التي تحتاجها:
<div class="g-recaptcha"
data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
data-callback="SubmitToken">
</div>
الطريقة الثانية: فحص استدعاءات grecaptcha.render()
ابحث في شيفرة JavaScript الخاصة بالصفحة عن grecaptcha.render؛ الخاصية callback هي التي تسمّي الدالة المطلوبة — وهي userVerified في المثال التالي:
grecaptcha.render('recaptcha-container', {
sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
callback: userVerified
});
الطريقة الثالثة: فحص إعدادات reCAPTCHA الداخلية
افتح وحدة تحكم المتصفح (Console) على الصفحة المستهدفة، ونفّذ الأمر التالي ثم تنقّل داخل شجرة الكائن للوصول إلى الخاصية callback. يختلف المسار الدقيق من موقع لآخر — قد يكون clients[0].aa.l.callback أو غيره تبعاً لإصدار reCAPTCHA ودرجة تصغيره، وإن احتوت الصفحة على أكثر من أداة reCAPTCHA فافحص clients[1] وclients[2] وهكذا:
___grecaptcha_cfg.clients[0]
سكربت كشف سريع
نفّذ هذا في وحدة تحكم المتصفح للعثور على أسماء دوال رد النداء تلقائياً:
// Check data-callback attributes
document.querySelectorAll('[data-callback]').forEach(el => {
console.log('data-callback:', el.getAttribute('data-callback'));
});
// Check internal config
if (typeof ___grecaptcha_cfg !== 'undefined') {
Object.keys(___grecaptcha_cfg.clients).forEach(key => {
const client = ___grecaptcha_cfg.clients[key];
console.log(`Client ${key}:`, JSON.stringify(client, null, 2));
});
}
مخطط مسار الحل
يلخّص المخطط التالي الدورة كاملة، من استخراج مفتاح الموقع حتى معالجة الموقع للرمز تلقائياً:
Page → extract sitekey + pageurl + callback name
↓
POST to in.php (method=userrecaptcha)
↓
receive captcha ID
↓
wait 15–20 seconds
↓
GET res.php (action=get, id=…)
↓ ↓
CAPCHA_NOT_READY status=1 → token
(wait 5s, retry) ↓
invoke callback(token)
↓
site processes token automatically
تنفيذ الحل بلغة Python باستخدام Selenium
import time
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGE_URL = "https://example.com/login"
CALLBACK_NAME = "SubmitToken" # The callback function name from the page
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
def solve_recaptcha_v2(api_key, sitekey, pageurl):
"""Submit a reCAPTCHA v2 task and return the solved token."""
# Step 1: Submit the captcha
submit_resp = requests.post(
SUBMIT_URL,
data={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
},
timeout=30,
)
submit_resp.raise_for_status()
submit_data = submit_resp.json()
if submit_data.get("status") != 1:
raise RuntimeError(f"Submit failed: {submit_data}")
captcha_id = submit_data["request"]
print(f"Task created — captcha ID: {captcha_id}")
# Step 2: Wait before first poll
time.sleep(15)
# Step 3: Poll for result
for _ in range(60):
result_resp = requests.get(
RESULT_URL,
params={
"key": api_key,
"action": "get",
"id": captcha_id,
"json": 1,
},
timeout=30,
)
result_resp.raise_for_status()
result_data = result_resp.json()
if result_data.get("request") == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if result_data.get("status") == 1:
return result_data["request"]
raise RuntimeError(f"Polling error: {result_data}")
raise TimeoutError("reCAPTCHA v2 solve timed out")
def detect_callback_name(driver):
"""Detect the reCAPTCHA callback function name from the page."""
# Try data-callback attribute first
callback = driver.execute_script("""
const el = document.querySelector('[data-callback]');
if (el) return el.getAttribute('data-callback');
return null;
""")
if callback:
return callback
# Try internal reCAPTCHA config
callback = driver.execute_script("""
if (typeof ___grecaptcha_cfg === 'undefined') return null;
const clients = ___grecaptcha_cfg.clients;
for (const key of Object.keys(clients)) {
const client = clients[key];
// Walk the object tree to find a callback function
const json = JSON.stringify(client);
const match = json.match(/"callback":"(\\w+)"/);
if (match) return match[1];
}
return null;
""")
return callback
# Main workflow
driver = webdriver.Chrome()
driver.get(PAGE_URL)
# Detect the callback name (or use the known name)
detected = detect_callback_name(driver)
callback_name = detected or CALLBACK_NAME
print(f"Using callback: {callback_name}")
# Solve the CAPTCHA
token = solve_recaptcha_v2(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")
# Invoke the callback with the token
driver.execute_script(f"{callback_name}(arguments[0]);", token)
print("Callback invoked — site should process the token automatically")
# Wait for the page to process
time.sleep(3)
driver.quit()
ماذا يفعل هذا الكود:
- يرسل مفتاح الموقع ورابط الصفحة إلى
in.phpعبرmethod=userrecaptcha— بشكل مطابق تماماً للإصدار القياسي. - يستطلع
res.phpكل 5 ثوانٍ حتى يجهز الرمز. - يكتشف اسم دالة رد النداء من DOM الصفحة.
- يستدعي الدالة ويمرّر إليها الرمز المحلول عبر
execute_script. - تتكفّل شيفرة JavaScript الخاصة بالموقع بالباقي — إرسال النموذج أو التحقق أو إعادة توجيه الصفحة.
تنفيذ الحل بلغة Node.js باستخدام Puppeteer
النداء إلى CaptchaAI هو نفسه؛ ما يتغيّر فقط هو أسلوب حقن الرمز داخل المتصفح:
const puppeteer = require("puppeteer");
const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const PAGE_URL = "https://example.com/login";
const CALLBACK_NAME = "SubmitToken";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function solveRecaptchaV2(apiKey, sitekey, pageurl) {
// Step 1: Submit the captcha
const submitResp = await fetch(SUBMIT_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
key: apiKey,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageurl,
json: "1",
}),
});
const submitData = await submitResp.json();
if (submitData.status !== 1) {
throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
}
const captchaId = submitData.request;
console.log(`Task created — captcha ID: ${captchaId}`);
// Step 2: Wait before first poll
await sleep(15_000);
// Step 3: Poll for result
for (let i = 0; i < 60; i++) {
const resultResp = await fetch(
`${RESULT_URL}?${new URLSearchParams({
key: apiKey,
action: "get",
id: captchaId,
json: "1",
})}`
);
const resultData = await resultResp.json();
if (resultData.request === "CAPCHA_NOT_READY") {
await sleep(5_000);
continue;
}
if (resultData.status === 1) {
return resultData.request;
}
throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
}
throw new Error("reCAPTCHA v2 solve timed out");
}
async function detectCallbackName(page) {
return page.evaluate(() => {
// Try data-callback attribute
const el = document.querySelector("[data-callback]");
if (el) return el.getAttribute("data-callback");
// Try internal config
if (typeof ___grecaptcha_cfg !== "undefined") {
const clients = ___grecaptcha_cfg.clients;
for (const key of Object.keys(clients)) {
const json = JSON.stringify(clients[key]);
const match = json.match(/"callback":"(\w+)"/);
if (match) return match[1];
}
}
return null;
});
}
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto(PAGE_URL, { waitUntil: "networkidle2" });
// Detect callback
const detected = await detectCallbackName(page);
const callbackName = detected || CALLBACK_NAME;
console.log(`Using callback: ${callbackName}`);
// Solve the CAPTCHA
const token = await solveRecaptchaV2(API_KEY, SITEKEY, PAGE_URL);
console.log(`Solved token: ${token.slice(0, 80)}...`);
// Invoke the callback
await page.evaluate(
(name, tkn) => {
window[name](tkn);
},
callbackName,
token
);
console.log("Callback invoked — site should process the token automatically");
await sleep(3_000);
await browser.close();
})();
تنفيذ الحل بلغة PHP
النداء إلى API متطابق في PHP، لكن استدعاء دالة رد النداء يتطلّب سياق متصفح، لذا يغطّي هذا المثال الحل من جانب الخادم. استخدم أداة متصفح بلا واجهة — مثل PHP WebDriver — لخطوة الحقن.
<?php
$apiKey = "YOUR_CAPTCHAAI_API_KEY";
$sitekey = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
$pageurl = "https://example.com/login";
// Step 1: Submit
$submit = file_get_contents("https://ocr.captchaai.com/in.php?" . http_build_query([
"key" => $apiKey,
"method" => "userrecaptcha",
"googlekey" => $sitekey,
"pageurl" => $pageurl,
"json" => 1,
]));
$submitData = json_decode($submit, true);
if ($submitData["status"] !== 1) {
die("Submit failed: " . $submit);
}
$captchaId = $submitData["request"];
echo "Task created — captcha ID: $captchaId\n";
// Step 2: Wait and poll
sleep(15);
for ($i = 0; $i < 60; $i++) {
$result = file_get_contents("https://ocr.captchaai.com/res.php?" . http_build_query([
"key" => $apiKey,
"action" => "get",
"id" => $captchaId,
"json" => 1,
]));
$resultData = json_decode($result, true);
if ($resultData["request"] === "CAPCHA_NOT_READY") {
sleep(5);
continue;
}
if ($resultData["status"] === 1) {
$token = $resultData["request"];
echo "Solved token: " . substr($token, 0, 80) . "...\n";
// Pass $token to your browser automation to invoke the callback
break;
}
die("Polling error: " . $result);
}
بعد الحصول على الرمز في PHP، استخدم أداة أتمتة متصفح — مثل php-webdriver — لتنفيذ ما يلي:
SubmitToken("TOKEN_FROM_CAPTCHAAI");
سيناريو عملي: أتمتة اختبار الجودة لبوابة حجز مواعيد
تخيّل فريق هندسة في شركة بالقاهرة أو الرياض يبني اختبارات جودة (QA) لبوابة حجز مواعيد داخلية تعرض reCAPTCHA v2. عند الضغط على "تأكيد"، لا تكتب البوابة الرمز في حقل مخفٍ، بل تستدعي دالة اسمها confirmBooking تُرسل النموذج مباشرة. وعندما يحاول الفريق أتمتة الاختبار عبر حقن g-recaptcha-response لا يحدث شيء، فتبدو الحالة وكأن الكابتشا لم تُحلّ.
الحل هنا هو المسار نفسه الموضّح أعلاه: أرسل الطلب إلى CaptchaAI، انتظر الرمز، ثم استدعِ confirmBooking ومرّر إليه الرمز. وللفرق التي تُشغّل مجموعات اختبار ليلية بأحجام كبيرة، تبدأ خطط CaptchaAI المعتمدة على الـ Threads من 15 دولاراً شهرياً (خطة BASIC، 5 threads) بحلول غير محدودة، ما يجعل تكلفة التشغيل ثابتة ويمكن توقّعها بغضّ النظر عن عدد مرّات إعادة تشغيل الاختبارات.
أشهر الأخطاء وكيفية تفاديها
| # | الخطأ | ماذا يحدث | الإصلاح |
|---|---|---|---|
| 1 | تعيين g-recaptcha-response بدل استدعاء الدالة |
تتجاهل الصفحة الرمز — ولا يُرسَل النموذج أبداً | اعثر على اسم دالة رد النداء واستدعِها بالرمز |
| 2 | اسم دالة رد النداء خاطئ | خطأ JavaScript: الدالة غير معرّفة | راجع data-callback أو grecaptcha.render() أو الإعدادات الداخلية |
| 3 | الدالة موجودة على فهرس عميل مختلف | استهداف أداة reCAPTCHA خاطئة في الصفحات متعددة الأدوات | افحص ___grecaptcha_cfg.clients[1] وclients[2] وهكذا |
| 4 | استدعاء الدالة قبل جاهزية الصفحة | لم تُعرَّف الدالة بعد في سياق الصفحة | انتظر DOMContentLoaded أو networkidle قبل الاستدعاء |
| 5 | الاعتماد على اسم مبهم/مصغّر | اسم الدالة في المصدر مشوّه بسبب التصغير | استخدم وحدة تحكم المتصفح وقت التشغيل لإيجاد مرجع الدالة الفعلي |
| 6 | الخلط بين رد النداء والنسخة غير المرئية | بعض التطبيقات غير المرئية تستخدم رد النداء أيضاً | تحقّق من وجود data-size="invisible" — وإن وُجد فراجع حل reCAPTCHA غير المرئي عبر API |
رسائل الخطأ الشائعة ومعناها
الجدول السابق يغطّي الأخطاء المفاهيمية في أثناء الإعداد؛ أمّا هنا فنركّز على رسائل الخطأ الحرفية التي قد تظهر لك وقت التشغيل، وما الذي تعنيه، وكيف تتصرّف حيالها مباشرة:
| رسالة الخطأ أو العرض | المعنى | الإجراء |
|---|---|---|
ReferenceError: SubmitToken is not defined |
لم تُحمَّل دالة رد النداء بعد، أو اسمها خاطئ | أكّد الاسم من data-callback أو الإعدادات الداخلية، وانتظر اكتمال تحميل الصفحة، وتحقّق من window.SubmitToken في المواقع المصغّرة |
ERROR_BAD_TOKEN_OR_PAGEURL |
زوج مفتاح الموقع/رابط الصفحة غير صالح — خطأ في API لا علاقة له بمسألة رد النداء مقابل القياسي | أعد استخراج مفتاح الموقع ورابط الصفحة من الصفحة المستهدفة |
ERROR_CAPTCHA_UNSOLVABLE |
تعذّر حل التحدي، وهذا ليس خاصاً برد النداء | أعد المحاولة بطلب جديد |
| الرمز يعمل على reCAPTCHA v2 القياسي لكنه يفشل هنا — دون أي رسالة خطأ | الصفحة على الأرجح تعتمد رد النداء | اتبع خطوات الكشف للتأكيد، ثم انتقل من تعيين الحقل إلى استدعاء الدالة |
للرجوع إلى مرجع الأخطاء الكامل، راجع أخطاء حل reCAPTCHA v2 الشائعة.
لماذا يناسب CaptchaAI هذه الحالة
خمسة عوامل تجعل CaptchaAI ملائماً تحديداً لمتغيّر رد النداء:
- النداء نفسه لـ API: تدفّق الإرسال والاستطلاع مطابق لـ reCAPTCHA v2 القياسي، دون أي معطيات إضافية.
- معدل حل مرتفع: يُطبَّق على reCAPTCHA v2 المدعوم، إذ يعتمد رد النداء والنسخة القياسية المحلّل نفسه.
- سرعة الحل: أقل من 60 ثانية للرمز الواحد.
- توافق الرمز: الرمز الناتج يعمل مع حقن
g-recaptcha-responseواستدعاء رد النداء معاً. - تسعير ثابت: خطط معتمدة على الـ Threads تبدأ من 15 دولاراً شهرياً بحلول غير محدودة.
الرمز الذي يُرجعه CaptchaAI واحد بغضّ النظر عن طريقة تنفيذ الموقع لـ reCAPTCHA v2؛ الفرق كله في شيفرتك من جانب العميل، أي في كيفية تسليم الرمز إلى الصفحة.
مثال كامل جاهز للتشغيل
هل تريد مشروعاً كاملاً يتضمّن إعداد البيئة والاستطلاع وإعادة المحاولة ومعالجة الأخطاء؟ راجع المثال الكامل الجاهز للتشغيل على GitHub →
الأسئلة الشائعة
هل تكلفة حل النسخة المعتمدة على رد النداء أعلى من reCAPTCHA v2 العادي؟
لا. يستخدم CaptchaAI الطلب نفسه (method=userrecaptcha) والمحلّل نفسه للنوعين، والتسعير معتمد على الـ Threads لا على نوع الكابتشا؛ لذلك لا توجد رسوم إضافية لمتغيّر رد النداء. تبدأ الخطط من 15 دولاراً شهرياً بحلول غير محدودة.
كم يستغرق حل reCAPTCHA v2 عبر CaptchaAI؟
عادةً أقل من 60 ثانية للرمز الواحد، مع معدل حل مرتفع على reCAPTCHA v2. ويتأثّر الوقت الفعلي بحِمل التشغيل وعدد الـ Threads المتاحة في خطتك.
هل أحتاج إلى بروكسي (proxy) لحل reCAPTCHA v2 برد النداء؟
لا تتطلّب الطريقة الموضّحة أعلاه تمرير بروكسي؛ يكفي مفتاح الموقع ورابط الصفحة. ورد النداء لا يغيّر ذلك، لأنه يخصّ خطوة تسليم الرمز داخل المتصفح فقط.
ماذا أفعل إذا كان اسم دالة رد النداء مبهماً أو مصغّراً (minified)؟
لا تعتمد على المصدر المصغّر؛ ابحث عن مرجع الدالة الفعلي وقت التشغيل على الصفحة الحيّة عبر ثلاث خطوات مرتّبة:
- تحقّق من السمة
data-callbackعلى عنصر الأداة أولاً. - راجع
___grecaptcha_cfg.clientsفي وحدة تحكم المتصفح. - تحقّق مما إذا كانت الدالة مُسندة إلى
windowباسم يمكنك استدعاؤه مباشرة.
خطوات البدء السريع
- احصل على مفتاح API — captchaai.com/api.php
- حدّد اسم دالة رد النداء — افحص
data-callbackأوgrecaptcha.render()أو الإعدادات الداخلية - انسخ كود Python أو Node.js أعلاه — واستبدل العناصر النائبة بمفتاحك ومفتاح الموقع ورابط الصفحة واسم الدالة
- شغّله — يصل الرمز في أقل من 60 ثانية، تُستدعى الدالة، ويعالج الموقع النتيجة
- واجهت مشكلة؟ ابدأ من أخطاء حل reCAPTCHA v2 الشائعة أو اقرأ مستندات CaptchaAI API كاملة
مقالات ذات صلة
- حل reCAPTCHA غير المرئي بلغة Python
- التعامل مع reCAPTCHA v2 وTurnstile في الموقع نفسه
- نظرة معمّقة على reCAPTCHA Enterprise Assessment API