التعامل مع صفحة تعرض أكثر من اختبار CAPTCHA يقوم على أربع خطوات مرتبة: اكتشف كل أداة على حدة، وأرسلها جميعاً للحل في وقت واحد، ثم استلم الرموز، وأخيراً احقن كل رمز في الحقل الذي يخصّه. المشكلة الحقيقية ليست في الحل نفسه، بل في الربط الصحيح بين كل رمز محلول والنموذج الذي طلبه؛ فأي خلط في الفهارس يجعل النموذج يرفض الإرسال رغم أن الرمز سليم. هذا الدليل يعرض المسار كاملاً بأمثلة عملية بلغة Python مع Selenium وبـ JavaScript مع Puppeteer.
متى تظهر عدة اختبارات في صفحة واحدة
من الشائع في مواقع المنطقة العربية أن تجمع صفحة واحدة أكثر من أداة تحقق. تخيّل بوابة توظيف مصرية فيها نموذج تسجيل دخول محمي بـ reCAPTCHA v2 في الأعلى، ونموذج اشتراك في النشرة البريدية أسفل الصفحة يحمل reCAPTCHA ثانياً بمفتاح موقع مختلف. أو متجراً إلكترونياً خليجياً يضع reCAPTCHA على شاشة الدخول وCloudflare Turnstile على خطوة الدفع. في الحالتين، لكل أداة مفتاح موقع (sitekey) فريد وعنصر مستهدف مستقل، ولا يمكن افتراض أنها تتشارك المفتاح نفسه.
لهذا لا يكفي أن تكتشف أول أداة وتتوقف. عليك حصر كل الأدوات الموجودة فعلاً على الصفحة، وحفظ فهرس ومفتاح موقع لكل واحدة، قبل أن تبدأ أي عملية حل. إن كنت جديداً على استخراج مفاتيح المواقع، فابدأ بإتقان قراءة مفتاح الموقع من شيفرة الصفحة أولاً.
الخطوة 1: اكتشاف كل اختبارات CAPTCHA في الصفحة
ابدأ بمسح الصفحة بحثاً عن جميع إطارات reCAPTCHA أو عناصرها، واستخرج مفتاح الموقع من كل عنصر مع الاحتفاظ بفهرسه. الفهرس هو ما سيربط لاحقاً بين الرمز المحلول وحقله الصحيح، لذلك احرص على ثباته من البداية.
Python مع Selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com/multi-captcha-page")
# Find all reCAPTCHA iframes
captcha_iframes = driver.find_elements(
By.CSS_SELECTOR, 'iframe[src*="recaptcha/api2/anchor"]'
)
# Extract sitekeys from each iframe's src
import re
captchas = []
for i, iframe in enumerate(captcha_iframes):
src = iframe.get_attribute("src")
match = re.search(r"k=([A-Za-z0-9_-]+)", src)
if match:
captchas.append({
"index": i,
"sitekey": match.group(1),
"iframe": iframe
})
print(f"Found {len(captchas)} CAPTCHAs on page")
for c in captchas:
print(f" [{c['index']}] sitekey: {c['sitekey']}")
الناتج المتوقع:
Found 2 CAPTCHAs on page
[0] sitekey: 6LcXyzABCDEF-login
[1] sitekey: 6LcAbcDEFGHI-signup
JavaScript مع Puppeteer
مع Puppeteer، اقرأ سمة data-sitekey من كل عنصر يحمل الفئة .g-recaptcha، واحتفظ باسم رد النداء (callback) إن وُجد، لأنك ستحتاجه عند حقن الرمز لاحقاً.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/multi-captcha-page', {
waitUntil: 'networkidle2'
});
// Extract all reCAPTCHA widgets from the page
const captchas = await page.evaluate(() => {
const widgets = document.querySelectorAll('.g-recaptcha');
return Array.from(widgets).map((el, i) => ({
index: i,
sitekey: el.getAttribute('data-sitekey'),
elementId: el.id || `captcha-${i}`,
callbackName: el.getAttribute('data-callback') || null
}));
});
console.log(`Found ${captchas.length} CAPTCHAs`);
captchas.forEach(c => console.log(` [${c.index}] ${c.sitekey}`));
})();
الخطوة 2: حل اختبارات CAPTCHA المتعددة بالتوازي
الخطأ الأكثر شيوعاً هو حل الأدوات واحدةً تلو الأخرى، فيتضاعف الزمن مع كل اختبار إضافي. الأفضل أن ترسلها جميعاً إلى CaptchaAI دفعةً واحدة، ثم تستطلع نتيجة كلٍّ منها حتى تكتمل. بما أن كل عملية استطلاع مستقلة، فإن حل اختبارين بالتوازي يستغرق تقريباً وقت حل اختبار واحد بدلاً من ضعفه.
هنا يظهر أثر نموذج تسعير CaptchaAI: الفوترة تقوم على عدد المسارات المتزامنة (threads) وليس على عدد عمليات الحل، ولكل مسار عدد غير محدود من عمليات الحل خلال الشهر. كل عملية حل تجري بالتوازي تشغل مساراً واحداً أثناء تنفيذها، فإذا كنت تحل ثلاثة اختبارات في اللحظة نفسها احتجت إلى ثلاثة مسارات متاحة على الأقل. حتى الخطة الأساسية BASIC (15 دولاراً شهرياً، 5 مسارات) تكفي لمعظم الصفحات التي تحمل اختبارين أو ثلاثة.
Python
import requests
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
API_KEY = "YOUR_API_KEY"
PAGE_URL = "https://example.com/multi-captcha-page"
def submit_captcha(sitekey):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": PAGE_URL,
"json": "1"
})
result = resp.json()
if result["status"] != 1:
raise Exception(f"Submit error: {result['request']}")
return result["request"]
def poll_result(task_id, timeout=120):
deadline = time.time() + timeout
while time.time() < deadline:
time.sleep(5)
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": "1"
})
result = resp.json()
if result["status"] == 1:
return result["request"]
if result["request"] != "CAPCHA_NOT_READY":
raise Exception(f"Poll error: {result['request']}")
raise TimeoutError(f"Task {task_id} timed out")
def solve_all(captchas):
# Submit all in parallel
task_ids = {}
with ThreadPoolExecutor(max_workers=len(captchas)) as pool:
futures = {
pool.submit(submit_captcha, c["sitekey"]): c["index"]
for c in captchas
}
for future in as_completed(futures):
idx = futures[future]
task_ids[idx] = future.result()
print(f"[captcha-{idx}] Submitted → task {task_ids[idx]}")
# Poll all in parallel
tokens = {}
with ThreadPoolExecutor(max_workers=len(task_ids)) as pool:
futures = {
pool.submit(poll_result, tid): idx
for idx, tid in task_ids.items()
}
for future in as_completed(futures):
idx = futures[future]
tokens[idx] = future.result()
print(f"[captcha-{idx}] Solved")
return tokens
# Example usage
captchas = [
{"index": 0, "sitekey": "6LcXyzABCDEF-login"},
{"index": 1, "sitekey": "6LcAbcDEFGHI-signup"}
]
tokens = solve_all(captchas)
الناتج المتوقع:
[captcha-0] Submitted → task 71823456
[captcha-1] Submitted → task 71823457
[captcha-1] Solved
[captcha-0] Solved
لاحظ أن ترتيب اكتمال الحل قد يختلف عن ترتيب الإرسال، وهذا طبيعي في التنفيذ المتوازي. المهم أن يُخزَّن كل رمز مقابل فهرسه الصحيح كما في القاموس tokens، لا مقابل ترتيب وصوله.
الخطوة 3: حقن كل رمز في الحقل الصحيح
لكل أداة reCAPTCHA منطقة نص g-recaptcha-response خاصة بها داخل حاويتها. عند وجود أدوات متعددة على الصفحة، تتكرر هذه المنطقة داخل كل حاوية، لذا يجب أن تستهدف المنطقة النصية داخل حاوية الأداة نفسها لا أول منطقة تجدها في الصفحة. بعد ضبط قيمة الرمز، شغّل رد النداء (callback) الخاص بالأداة إن كان معرّفاً حتى يتعرّف النموذج على أن التحقق قد اكتمل.
Python (Selenium)
def inject_tokens(driver, captchas, tokens):
for c in captchas:
idx = c["index"]
token = tokens[idx]
# Find the textarea within the widget's container
container = driver.find_elements(By.CSS_SELECTOR, ".g-recaptcha")[idx]
textarea = container.find_element(
By.CSS_SELECTOR, 'textarea[name="g-recaptcha-response"]'
)
driver.execute_script(
"arguments[0].value = arguments[1];", textarea, token
)
# Trigger the callback if defined
callback = c.get("callback")
if callback:
driver.execute_script(f"{callback}('{token}');")
print(f"[captcha-{idx}] Token injected")
inject_tokens(driver, captchas, tokens)
JavaScript (Puppeteer)
async function injectTokens(page, captchas, tokens) {
for (const captcha of captchas) {
const token = tokens[captcha.index];
await page.evaluate((idx, tkn, callbackName) => {
const widgets = document.querySelectorAll('.g-recaptcha');
const textarea = widgets[idx].querySelector(
'textarea[name="g-recaptcha-response"]'
);
textarea.value = tkn;
if (callbackName && typeof window[callbackName] === 'function') {
window[callbackName](tkn);
}
}, captcha.index, token, captcha.callbackName);
console.log(`[captcha-${captcha.index}] Token injected`);
}
}
await injectTokens(page, captchas, tokens);
التعامل مع أنواع CAPTCHA المختلطة في صفحة واحدة
ليست كل الأدوات على الصفحة من النوع نفسه. قد تجمع صفحة الدفع في متجر إلكتروني بين reCAPTCHA على شاشة الدخول وCloudflare Turnstile على خطوة إتمام الشراء. في هذه الحالة اكتشف كل نوع على حدة عبر مُحدِّد الفئة الخاص به: .g-recaptcha لـ reCAPTCHA و.cf-turnstile لـ Turnstile.
def detect_all_captchas(driver):
detected = []
# reCAPTCHA
recaptchas = driver.find_elements(By.CSS_SELECTOR, ".g-recaptcha")
for i, el in enumerate(recaptchas):
detected.append({
"type": "userrecaptcha",
"sitekey": el.get_attribute("data-sitekey"),
"label": f"recaptcha-{i}"
})
# Turnstile
turnstiles = driver.find_elements(By.CSS_SELECTOR, ".cf-turnstile")
for i, el in enumerate(turnstiles):
detected.append({
"type": "turnstile",
"sitekey": el.get_attribute("data-sitekey"),
"label": f"turnstile-{i}"
})
return detected
عند الإرسال، مرّر لكل أداة قيمة method المطابقة لنوعها: userrecaptcha مع reCAPTCHA وturnstile مع Turnstile. كلا النوعين مدعوم بالكامل في CaptchaAI، ولا فرق في التكلفة بينهما ما دامت الفوترة على المسارات وليس على النوع.
نصائح لتشغيل موثوق في الإنتاج
- اربط الرموز بمفاتيح المواقع لا بترتيب الوصول. خزّن كل رمز مقابل فهرس أو مفتاح موقع الأداة، حتى لا يذهب رمز الدخول إلى نموذج الاشتراك عند اختلاف ترتيب اكتمال الحل.
- انتظر ظهور كل الأدوات قبل المسح. كثير من الصفحات تحمّل الأداة الثانية بشكل كسول (lazy) بعد التمرير أو بعد إرسال الخطوة الأولى، فاستخدم
WebDriverWaitأوpage.waitForSelectorقبل الحصر. - اضبط مهلة انتهاء واقعية. الأمثلة أعلاه تستخدم مهلة 120 ثانية لكل عملية، وهو هامش مريح يستوعب التأخر العرضي دون تعليق السكربت.
- أعد المسح بعد كل إرسال. في النماذج متعددة الخطوات قد تظهر أداة جديدة بعد كل خطوة، فأعد الاكتشاف بدل الاعتماد على أول مسح.
استكشاف الأخطاء الشائعة وإصلاحها
الجدول التالي يلخّص أكثر المشكلات تكراراً عند التعامل مع عدة اختبارات على الصفحة نفسها وسببها والإصلاح المناسب لها:
| مشكلة | السبب | إصلاح |
|---|---|---|
| تم إدخال الرمز لكن النموذج لا يزال محظوراً | لم يُشغَّل رد النداء | تحقق من data-callback واستدعِه بالرمز |
| اكتشاف الاختبار الأول فقط | تحميل الاختبار الثاني بشكل كسول | انتظر ظهور كل إطارات iframe/widgets قبل المسح |
| رمز خاطئ في حقل خاطئ | عدم تطابق الفهرس | اربط الرموز بمفاتيح المواقع لا بالترتيب الموضعي |
ERROR_WRONG_GOOGLEKEY |
استخراج مفتاح الموقع بشكل غير صحيح | تحقق من مفتاح الموقع في سمة src أو data-sitekey |
الأسئلة الشائعة
كم عدد المسارات (threads) التي أحتاجها لحل عدة اختبارات معاً؟
بعدد الاختبارات التي تحلّها في اللحظة نفسها. كل عملية حل متوازية تشغل مساراً واحداً أثناء تنفيذها، فصفحة بثلاثة اختبارات تحتاج ثلاثة مسارات متاحة. الخطة الأساسية BASIC توفّر 5 مسارات، وهو كافٍ لأغلب الصفحات المتعددة.
هل تختلف تكلفة حل reCAPTCHA وTurnstile في الصفحة نفسها؟
لا. تقوم فوترة CaptchaAI على عدد المسارات المتزامنة وليس على نوع الاختبار، ولا توجد رسوم إضافية حسب النوع. حل reCAPTCHA وTurnstile معاً على الصفحة يستهلك مساراً لكل عملية جارية بصرف النظر عن النوع.
ما المهلة المناسبة التي أضبطها لكل عملية حل؟
مهلة 120 ثانية هامش آمن، إذ يستغرق الحل غالباً بين 15 و30 ثانية. اجعل فترة الاستطلاع الدوري نحو 5 ثوانٍ بين المحاولة والأخرى حتى لا تُرهق نقطة النهاية بطلبات متلاحقة.
ماذا أفعل إذا احتوت الصفحة على reCAPTCHA v3 إلى جانب v2؟
اكتشف كل نوع على حدة وأرسله بالطريقة المناسبة له. الطريقة userrecaptcha تخدم إصدارات reCAPTCHA المدعومة، لكن انتبه إلى أن v3 يعتمد على قيمة action ودرجة ثقة، لذا استخرج هذه المعطيات من الصفحة وأرسلها مع الطلب.
حلّ أي عدد من اختبارات CAPTCHA في صفحتك عبر CaptchaAI
أنشئ مفتاح API واحداً وابدأ بحل كل الأدوات في الصفحة دفعةً واحدة بالتوازي. احصل على مفتاحك من captchaai.com.