لإبقاء سكربت الاستخراج يعمل حين يعترضه reCAPTCHA أو Cloudflare Turnstile أو صورة CAPTCHA، مرّر التحدي إلى CaptchaAI ليعيد رمزاً يواصل به الطلب دون تدخل يدوي بدل أن يتوقف الجمع عند أول اختبار. تتلخص المعالجة في أربع خطوات مترابطة:
- حدّد نوع الاختبار الذي يعرضه الموقع من مصدر الصفحة
- استخرج مفتاح الموقع المرتبط بذلك النوع
- أرسل التحدي إلى CaptchaAI واستطلع النتيجة حتى تعود بالرمز
- مرّر الرمز ضمن الطلب إلى الموقع المستهدف
لماذا يوقف CAPTCHA أدوات استخراج البيانات
لا يظهر الاختبار عشوائياً؛ فالموقع يستجيب لإشارات سلوكية توحي بأن الزائر برنامج آلي لا إنسان:
- معدل الطلبات: عدد كبير من الطلبات المتتالية من عنوان IP واحد
- ملفات تعريف الارتباط: غياب ملفات الجلسة أو التفضيلات المتوقعة
- الرؤوس: غياب
Accept-LanguageأوRefererكالروبوتات - بصمة JavaScript: لا يوجد تنفيذ JS أو تم رصد متصفح بلا واجهة
- سمعة عنوان IP: عنوان تابع لمركز بيانات أو موسوم كخادم وسيط
ما الذي تحتاجه قبل البدء
| المتطلب | التفاصيل |
|---|---|
| مفتاح CaptchaAI API | من captchaai.com |
| Python 3.7+ أو Node.js 16+ | لتشغيل أمثلة الشيفرة |
requests / axios |
مكتبة عميل HTTP |
| رابط الموقع المستهدف | الصفحة التي تعرض الاختبار |
| مفتاح موقع CAPTCHA | مُستخرَج من مصدر الصفحة |
اقصر هذا المسار على بيانات عامة أو مواقع تملكها أو تملك تصريحاً بجمعها؛ فهو لاختبار الجودة وأتمتة سير العمل لا لتجاوز حدود لا تملك حقها.
الخطوة 1: تحديد نوع اختبار CAPTCHA
افحص مصدر الصفحة أولاً لتعرف نوع الاختبار، فلكل نوع معلمة method مختلفة عند الإرسال:
reCAPTCHA v2:
<div class="g-recaptcha" data-sitekey="6Le-wvkS..."></div>
reCAPTCHA v3:
<script src="https://www.google.com/recaptcha/api.js?render=6Le-wvkS..."></script>
Cloudflare Turnstile:
<div class="cf-turnstile" data-sitekey="0x4AAAAA..."></div>
إذا كان الموقع محمياً بـ Cloudflare بالكامل فراجع دليل حل Cloudflare Turnstile عبر API لضبط المعلمة الصحيحة.
الخطوة 2: استخراج مفتاح الموقع
Python (باستخدام requests وBeautifulSoup):
from bs4 import BeautifulSoup
import requests
page = requests.get("https://example.com/protected-page", headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
soup = BeautifulSoup(page.text, "html.parser")
# reCAPTCHA v2
recaptcha_div = soup.find("div", class_="g-recaptcha")
if recaptcha_div:
site_key = recaptcha_div["data-sitekey"]
print(f"reCAPTCHA v2 site key: {site_key}")
Node.js (باستخدام cheerio):
const axios = require("axios");
const cheerio = require("cheerio");
const { data } = await axios.get("https://example.com/protected-page");
const $ = cheerio.load(data);
const siteKey = $(".g-recaptcha").attr("data-sitekey");
console.log("Site key:", siteKey);
الخطوة 3: إرسال التحدي إلى CaptchaAI
أرسل مفتاح الموقع ورابط الصفحة إلى in.php، ثم استطلع النتيجة دورياً من res.php حتى تعود بالرمز المحلول:
Python:
import requests
import time
API_KEY = "YOUR_API_KEY"
SITE_KEY = "6Le-wvkS..."
PAGE_URL = "https://example.com/protected-page"
# Submit
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": SITE_KEY,
"pageurl": PAGE_URL
})
if not resp.text.startswith("OK|"):
raise Exception(f"Submit error: {resp.text}")
task_id = resp.text.split("|")[1]
print(f"Task submitted: {task_id}")
# Poll for result
while True:
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
token = result.text.split("|")[1]
print(f"Solved! Token: {token[:50]}...")
break
raise Exception(f"Solve error: {result.text}")
Node.js:
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
const SITE_KEY = "6Le-wvkS...";
const PAGE_URL = "https://example.com/protected-page";
// Submit
const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
params: {
key: API_KEY,
method: "userrecaptcha",
googlekey: SITE_KEY,
pageurl: PAGE_URL,
},
});
const taskId = submitResp.data.split("|")[1];
// Poll
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
while (true) {
await sleep(5000);
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId },
});
if (result.data === "CAPCHA_NOT_READY") continue;
if (result.data.startsWith("OK|")) {
const token = result.data.split("|")[1];
console.log("Token:", token.substring(0, 50));
break;
}
throw new Error(`Error: ${result.data}`);
}
الخطوة 4: تمرير الرمز إلى الموقع المستهدف
بعد استلام الرمز، أرسله ضمن بيانات النموذج التي يتوقعها الموقع في الحقل g-recaptcha-response:
Python:
# Submit the solved token with the form
form_data = {
"g-recaptcha-response": token,
"username": "user@example.com",
"password": "password123"
}
response = requests.post(PAGE_URL, data=form_data, headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
print(f"Status: {response.status_code}")
الخطوة 5: تغليف منطق الحل في دالة قابلة لإعادة الاستخدام
اجمع الإرسال والاستطلاع في دالة واحدة تستدعيها من أي موضع في السكربت:
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_captcha(site_key, page_url, method="userrecaptcha"):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": method,
"googlekey": site_key,
"pageurl": page_url
})
if not resp.text.startswith("OK|"):
raise Exception(resp.text)
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError("CAPTCHA solve timed out")
# Use in your scraper
def scrape_page(url, site_key):
token = solve_captcha(site_key, url)
response = requests.post(url, data={"g-recaptcha-response": token})
return response.text
سيناريو عملي: مراقبة أسعار متجر إلكتروني
تخيّل فريقاً في المنطقة العربية يراقب أسعار المنافسين على متجر إلكتروني إقليمي يعرض Cloudflare Turnstile بعد عشرات الطلبات. بدل توقف الجمع، تُستدعى solve_captcha مع method=turnstile عند كل اعتراض فيتواصل العمل. وحين يكبر الحجم، أرسل عدة مهام دفعة واحدة كما في دليل حل عدة اختبارات CAPTCHA بالتوازي بدل انتظار كل رمز على حدة:
- ثبّت قيمة
methodحسب نوع اختبار كل صفحة مستهدفة - خزّن الرموز الصالحة لإعادة استخدامها ضمن نافذة صلاحيتها
- وزّع الطلبات على وكلاء سكنيين لتقليل ظهور الاختبار أصلاً
نصائح لتشغيل موثوق
- دوّر وكلاء المستخدم — استخدم سلاسل User-Agent واقعية للمتصفحات
- أضف فواصل زمنية — باعد بين الطلبات من 2 إلى 5 ثوانٍ لتفادي تحديد معدل الطلبات
- استخدم خوادم وسيطة — دوّر الوكلاء السكنيين لتوزيع الطلبات
- احتفظ بملفات تعريف الارتباط — حافظ على ملفات الجلسة عبر الطلبات المتتالية
- خزّن الرموز مؤقتاً — بعض الرموز تصلح لأكثر من طلب ضمن نافذة صلاحيتها
معالجة الأخطاء الشائعة
| الخطأ | السبب | الإصلاح |
|---|---|---|
ERROR_WRONG_USER_KEY |
مفتاح API غير صالح | تحقق من المفتاح في لوحة التحكم على captchaai.com |
ERROR_ZERO_BALANCE |
الرصيد صفر | أضف رصيداً إلى حسابك |
ERROR_CAPTCHA_UNSOLVABLE |
تعذّر حل التحدي | تأكد من صحة مفتاح الموقع والرابط |
CAPCHA_NOT_READY (يدور بلا نهاية) |
حل بطيء أو معلمات خاطئة | ارفع مهلة الانتظار وتأكد من مطابقة مفتاح الموقع للصفحة |
| رفض الموقع للرمز | انتهت صلاحية الرمز أو مفتاح خاطئ | استخدم الرمز خلال 120 ثانية وأكّد مفتاح الموقع |
الأسئلة الشائعة
كيف أتعامل مع reCAPTCHA v3 الذي يعتمد على درجة ثقة بدل النقر؟
أرسله بالطريقة نفسها عبر method=userrecaptcha؛ يعيد CaptchaAI رمزاً بدرجة ثقة يقرر الموقع قبوله النهائي، وحافظ على سلوك واقعي لرفع الدرجة.
لماذا يُرفض الرمز أحياناً رغم نجاح الحل؟
غالباً للأسباب التالية:
- انتهاء صلاحية الرمز قبل إرساله إلى الموقع
- عدم تطابق مفتاح الموقع مع الصفحة الفعلية التي تُرسل إليها الطلب
- إرسال الرمز إلى نموذج غير النموذج المحمي بالاختبار
هل تختلف تكلفة حل صور CAPTCHA عن reCAPTCHA؟
لا. يعتمد CaptchaAI تسعيراً قائماً على الـ Threads لا على كل حل؛ فخطة BASIC ($15 شهرياً، 5 Threads) تمنح حلولاً غير محدودة لأي نوع مدعوم، فتصبح تكلفة الحجم الكبير ثابتة ومتوقعة.
هل أحتاج إلى متصفح بلا واجهة لكل موقع؟
ليس دائماً؛ فطلبات HTTP البسيطة تكفي لعمليات إرسال نماذج reCAPTCHA المباشرة، بينما تحتاج مواقع JavaScript إلى دمج CaptchaAI مع Selenium أو Puppeteer.