حلّ اختبار CAPTCHA برمجياً يتلخّص في حلقة من أربع خطوات ثابتة: استخرج معلمات التحدي من الصفحة، أرسلها إلى خدمة الحل، استطلع النتيجة، ثم احقن الرمز في النموذج. يأخذك هذا الدليل من أول عملية حل ناجحة إلى خط أنابيب جاهز للإنتاج باستخدام CaptchaAI وPython، مع التركيز على ما يهمّ فعلاً عند التشغيل الحقيقي: معالجة الأخطاء، ومراقبة الرصيد، والتوسّع تحت الحِمل.
أولاً: كيف تعمل اختبارات CAPTCHA ولماذا تنتشر
تعريف موجز لاختبار CAPTCHA
اختبار CAPTCHA — واختصاره يعني "اختبار تورينج العام الآلي بالكامل للتمييز بين الحاسوب والإنسان" — هو تحدٍّ يُدرَج في الصفحة لمنع الوصول الآلي غير المرغوب مع السماح للمستخدم البشري بالمرور. من وجهة نظر المطوّر، هو حاجز يجب اجتيازه برمجياً قبل إكمال طلب مشروع.
لماذا تعتمد المواقع على هذه الاختبارات
فهم سبب وجود الاختبار يساعدك على توقّع نوعه وسلوكه:
- منع إنشاء الحسابات آلياً بكميات كبيرة
- الحدّ من استخراج البيانات وجمعها دون إذن
- إيقاف الرسائل غير المرغوبة في النماذج والتعليقات
- تحديد معدل الوصول إلى الـ API
أنواع اختبارات CAPTCHA التي ستقابلها
تنقسم الاختبارات إلى أربع عائلات، لكلٍّ منها أسلوب استخراج وحلّ مختلف:
| النوع | أمثلة | التحدي |
|---|---|---|
| نص/Image | الحروف المشوهة، والتعابير الرياضية | اكتب ما تراه |
| خانة الاختيار | reCAPTCHA v2 | انقر فوق خانة الاختيار، وربما حل شبكة الصور |
| غير مرئية | reCAPTCHA v3، Turnstile | لا يوجد تفاعل من قبل المستخدم - التسجيل السلوكي |
| تفاعلية | شريحة GeeTest، شبكة BLS | اسحب العناصر أو انقر عليها أو رتّبها |
يغطّي CaptchaAI عائلات reCAPTCHA (v2 وv3 وEnterprise) وCloudflare Turnstile وChallenge وGeeTest v3 والصور وBLS. في المقابل، لا يدعم حالياً hCaptcha أو FunCaptcha (Arkose Labs)، ودعم GeeTest v4 معلن أنه قادم قريباً وليس متاحاً بعد.
آلية عمل خدمات حل اختبار CAPTCHA
مسار الحل من طرفك إلى الخدمة
الفكرة أنك لا تحلّ التحدي بنفسك، بل تفوّضه إلى الخدمة وتنتظر الرمز الناتج:
Your Code → Submit CAPTCHA to API → Solving Service → Return Token/Text → Your Code Injects Result
الخطوات الخمس بالتفصيل
تتكرّر الحلقة نفسها مهما اختلف نوع الاختبار، فتكفي طبقة تجريد واحدة:
- استخرج معلمات CAPTCHA من الصفحة المستهدفة (مفتاح الموقع، التحدي، الصورة)
- أرسل المعلمات إلى الـ API للحل
- استطلع النتيجة دورياً (رمز أو نص)
- احقن النتيجة مرة أخرى في الصفحة
- أرسل النموذج
إعداد CaptchaAI في مشروعك
تثبيت المكتبات المطلوبة
مكتبة requests وحدها تكفي للبدء:
pip install requests
فئة الحل الأساسية
الفئة التالية تلخّص الحلقة كاملة: submit لإرسال المهمة، وget_result للاستطلاع الدوري، وsolve كواجهة مختصرة، وbalance لقراءة الرصيد. أعِد استخدامها في كل مشروع:
import time
import requests
class CaptchaAI:
BASE = "https://ocr.captchaai.com"
def __init__(self, api_key):
self.api_key = api_key
def submit(self, params):
params["key"] = self.api_key
params["json"] = 1
resp = requests.post(f"{self.BASE}/in.php", data=params)
data = resp.json()
if data["status"] != 1:
raise Exception(f"Submit failed: {data['request']}")
return data["request"]
def get_result(self, task_id, timeout=300, interval=5, initial_wait=10):
time.sleep(initial_wait)
deadline = time.time() + timeout
while time.time() < deadline:
resp = requests.get(
f"{self.BASE}/res.php",
params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1,
},
).json()
if resp["request"] == "CAPCHA_NOT_READY":
time.sleep(interval)
continue
if resp["status"] == 1:
return resp["request"]
raise Exception(f"Solve failed: {resp['request']}")
raise TimeoutError("Solve timed out")
def solve(self, params, **kwargs):
task_id = self.submit(params)
return self.get_result(task_id, **kwargs)
def balance(self):
resp = requests.get(
f"{self.BASE}/res.php",
params={"key": self.api_key, "action": "getbalance"},
)
return float(resp.text)
حل كل نوع من أنواع CAPTCHA عبر API
مع وجود الفئة السابقة، يصبح الفرق بين الأنواع مجرد اختلاف في حقول params، وحقل method هو ما يحدّد نوع المعالجة.
reCAPTCHA v2
يكفي مفتاح الموقع (googlekey) وعنوان الصفحة، دون الحاجة إلى متصفح:
solver = CaptchaAI("YOUR_API_KEY")
token = solver.solve({
"method": "userrecaptcha",
"googlekey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
"pageurl": "https://example.com/login",
})
reCAPTCHA v3
النسخة السلوكية تحتاج إلى version وaction، وغالباً إلى مهلة انتظار أولية أطول:
token = solver.solve({
"method": "userrecaptcha",
"googlekey": "SITE_KEY",
"pageurl": "https://example.com",
"version": "v3",
"action": "submit",
}, initial_wait=20)
Cloudflare Turnstile
token = solver.solve({
"method": "turnstile",
"sitekey": "0x4AAAAAAAC3a...",
"pageurl": "https://example.com",
})
GeeTest v3
يتطلّب هذا النوع قيمتَي gt وchallenge اللتين تُستخرجان من الصفحة قبل الإرسال:
result = solver.solve({
"method": "geetest",
"gt": "GT_VALUE",
"challenge": "CHALLENGE_VALUE",
"pageurl": "https://example.com",
})
الصور والتعرّف الضوئي (Image/OCR)
هنا ترسل بيانات الصورة مُرمّزة بصيغة base64 وتصف خصائص النص المتوقّع:
import base64
with open("captcha.png", "rb") as f:
img_b64 = base64.b64encode(f.read()).decode()
text = solver.solve({
"method": "base64",
"body": img_b64,
"numeric": "1",
"minLen": "4",
"maxLen": "6",
})
استخراج معلمات التحدي من الصفحة
في الواقع عليك استخراج مفتاح الموقع من الصفحة أولاً، وغالباً باستخدام Selenium.
مفتاح موقع reCAPTCHA
عادةً يكون المفتاح في سمة data-sitekey، وإن غاب فيمكن قراءته من رابط الـ iframe:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com/login")
# Method 1: From div attribute
sitekey = driver.find_element(
By.CSS_SELECTOR, "[data-sitekey]"
).get_attribute("data-sitekey")
# Method 2: From iframe URL
import re
iframe = driver.find_element(By.CSS_SELECTOR, "iframe[src*='recaptcha']")
src = iframe.get_attribute("src")
sitekey = re.search(r"k=([^&]+)", src).group(1)
مفتاح موقع Turnstile
sitekey = driver.find_element(
By.CSS_SELECTOR, "[data-sitekey], .cf-turnstile"
).get_attribute("data-sitekey")
معلمات GeeTest
نقرأ القيم مباشرة عبر JavaScript لأنها قد لا تظهر في سمات مباشرة:
import json
gt_data = driver.execute_script("""
return {
gt: document.querySelector('[data-gt]')?.getAttribute('data-gt'),
challenge: document.querySelector('[data-challenge]')?.getAttribute('data-challenge')
};
""")
حقن الحل داخل الصفحة
بعد استلام الرمز، أدخِله في الحقل المخفي الذي يتوقّعه الموقع ثم أكمِل الإرسال.
الحقن المعتمد على الرمز (reCAPTCHA وTurnstile)
driver.execute_script(f"""
document.querySelector('[name="g-recaptcha-response"]').value = '{token}';
document.querySelector('[name="cf-turnstile-response"]').value = '{token}';
""")
التعامل مع دوال رد النداء (Callbacks)
بعض عمليات التكامل لا تكتفي بتعبئة الحقل، بل تنتظر استدعاء دالة رد النداء لتفعيل الزر:
driver.execute_script(f"""
if (typeof ___grecaptcha_cfg !== 'undefined') {{
Object.keys(___grecaptcha_cfg.clients).forEach(function(key) {{
var client = ___grecaptcha_cfg.clients[key];
// Find and call the callback
}});
}}
""")
معالجة الأخطاء بثبات
الفرق بين سكربت تجريبي وخدمة إنتاجية هو غالباً في تعامله مع الفشل. ميّز بين الأخطاء التي تستحق إعادة المحاولة وتلك التي لا فائدة من تكرارها.
منطق إعادة المحاولة
خطأ UNSOLVABLE قد يُحلّ بمحاولة جديدة، أما ZERO_BALANCE فيعني نفاد الرصيد ولا معنى لإعادة المحاولة معه:
def solve_with_retry(solver, params, max_retries=3):
for attempt in range(max_retries):
try:
return solver.solve(params)
except Exception as e:
error = str(e)
if "ZERO_BALANCE" in error:
raise # Don't retry — need funds
if "UNSOLVABLE" in error:
print(f"Attempt {attempt + 1} failed, retrying...")
continue
raise
raise Exception(f"Failed after {max_retries} attempts")
مراقبة الرصيد قبل الإرسال
فحص الرصيد قبل بدء دُفعة كبيرة يجنّبك سلسلة إخفاقات مكلفة في منتصف التشغيل:
def check_balance_before_solve(solver, min_balance=0.10):
balance = solver.balance()
if balance < min_balance:
raise Exception(f"Low balance: ${balance:.2f}")
return balance
أنماط جاهزة للإنتاج
عند الحجم الكبير يصبح تنظيم الاتصالات والتزامن أهمّ من سرعة الحل الفردي.
تجميع الاتصالات (Connection Pooling)
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_session():
session = requests.Session()
retry = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503])
adapter = HTTPAdapter(max_retries=retry, pool_connections=10, pool_maxsize=20)
session.mount("https://", adapter)
return session
الحل المتزامن عبر عدة مسارات
عدد العمال المتزامنين هنا يجب أن يتوافق مع عدد مسارات المعالجة (Threads) في خطتك؛ فتجاوزه لن يزيد السرعة:
from concurrent.futures import ThreadPoolExecutor, as_completed
def solve_batch(solver, captcha_list, max_workers=5):
results = {}
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {
executor.submit(solver.solve, params): url
for url, params in captcha_list
}
for future in as_completed(futures):
url = futures[future]
try:
results[url] = future.result()
except Exception as e:
results[url] = f"ERROR: {e}"
return results
تحديد معدل الطلبات
import threading
class RateLimiter:
def __init__(self, max_per_second=10):
self.interval = 1.0 / max_per_second
self.lock = threading.Lock()
self.last_call = 0
def wait(self):
with self.lock:
now = time.time()
wait_time = self.last_call + self.interval - now
if wait_time > 0:
time.sleep(wait_time)
self.last_call = time.time()
مراقبة التشغيل وقياس الأداء
ما لا تقيسه لا تحسّنه. سجّل كل عملية وتتبّع معدل النجاح والزمن لتكتشف أي تراجع مبكراً.
التسجيل (Logging)
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger("captcha")
def solve_logged(solver, params):
start = time.time()
logger.info(f"Submitting {params.get('method')} CAPTCHA")
try:
result = solver.solve(params)
elapsed = time.time() - start
logger.info(f"Solved in {elapsed:.1f}s")
return result
except Exception as e:
elapsed = time.time() - start
logger.error(f"Failed after {elapsed:.1f}s: {e}")
raise
تتبّع المقاييس
class SolveMetrics:
def __init__(self):
self.total = 0
self.success = 0
self.failures = 0
self.total_time = 0.0
def record(self, success, elapsed):
self.total += 1
self.total_time += elapsed
if success:
self.success += 1
else:
self.failures += 1
def summary(self):
rate = (self.success / self.total * 100) if self.total else 0
avg = (self.total_time / self.total) if self.total else 0
return {
"total": self.total,
"success_rate": f"{rate:.1f}%",
"avg_time": f"{avg:.1f}s",
}
مثال تطبيقي: أتمتة اختبار الجودة لبوابة حجوزات
تخيّل فريقاً في شركة سفر أو تجارة إلكترونية عربية يريد اختبار مسار تسجيل الدخول وإتمام الشراء آلياً كل ليلة. الصفحات محمية بـ reCAPTCHA v2 على تسجيل الدخول وبـ Turnstile على خطوة الدفع. باستخدام الفئة أعلاه، يمرّ كل سيناريو بالحلقة نفسها: استخراج مفتاح الموقع، الإرسال بالطريقة المناسبة، حقن الرمز، ثم متابعة التدفق.
السؤال العملي هو حجم التزامن. يعتمد تسعير CaptchaAI على عدد مسارات المعالجة المتزامنة (Threads) مع حلول غير محدودة لكل مسار شهرياً، لا على عدد العمليات. فتكفي خطة BASIC ($15 شهرياً، 5 مسارات) لاختبارات ليلية صغيرة، بينما تناسب ADVANCE ($90 شهرياً، 50 مساراً) خطوط الأنابيب الأكبر. الأسعار بالدولار الأمريكي والتكلفة ثابتة ومتوقّعة.
قائمة تحقّق قبل الإطلاق
| خطوة | المهمة |
|---|---|
| 1 | ثبّت requests واحصل على مفتاح API |
| 2 | حدّد نوع CAPTCHA في الصفحة المستهدفة |
| 3 | استخرج مفتاح الموقع والمعلمات |
| 4 | أرسل إلى CaptchaAI بالطريقة الصحيحة |
| 5 | استطلع النتيجة بالتوقيت المناسب |
| 6 | احقن الرمز وأرسل النموذج |
| 7 | أضف منطق إعادة المحاولة للإنتاج |
| 8 | راقب معدل النجاح والتكاليف |
| 9 | وسّع عبر تجميع الاتصالات والتزامن |
الأسئلة الشائعة
هل استخدام خدمة حل CAPTCHA قانوني ومسموح؟
يعتمد الأمر على الغرض. حلّ الاختبارات لأغراض مشروعة مثل اختبار الجودة وأتمتة سير العمل واختبار التكامل على مواقعك أو مواقع تملك إذناً بالوصول إليها هو استخدام معتمد. تجنّب أي استخدام يتعارض مع شروط الموقع أو يمسّ بيانات لا تملكها.
هل يدعم CaptchaAI جميع أنواع اختبارات CAPTCHA؟
لا. يدعم CaptchaAI عائلات reCAPTCHA وCloudflare Turnstile وChallenge وGeeTest v3 والصور وBLS، لكنه لا يدعم حالياً hCaptcha أو FunCaptcha (Arkose Labs)، بينما دعم GeeTest v4 معلن أنه قادم قريباً. تحقّق من النوع المستخدم في صفحتك قبل بناء التكامل.
كم عدد مسارات المعالجة (Threads) التي أحتاجها لمشروعي؟
يتحدّد العدد بذروة التزامن لديك، لا بإجمالي الحلول. إذا كنت تحلّ خمسة اختبارات في آنٍ واحد كحد أقصى فخطة بخمسة مسارات كافية. وإذا بدأت الطلبات تصطف في قائمة الانتظار، فتلك إشارة إلى الحاجة لمسارات أكثر.
لماذا تظهر أخطاء مثل UNSOLVABLE وكيف أعالجها؟
يعني UNSOLVABLE أن الخدمة لم تحلّ هذه المحاولة تحديداً، وغالباً ما تنجح إعادة المحاولة. تأكّد من صحة مفتاح الموقع وعنوان الصفحة، واعتمد منطق إعادة محاولة محدوداً مع تمييز الأخطاء غير القابلة للإصلاح مثل ZERO_BALANCE.
كيف أتفادى انتهاء صلاحية الرمز قبل استخدامه؟
احلّ الاختبار قبل الحاجة إليه مباشرةً. تنتهي صلاحية رموز reCAPTCHA خلال 120 ثانية تقريباً، وTurnstile خلال 300 ثانية. لا تحلّ مسبقاً بكميات كبيرة، بل اربط توقيت الحل بلحظة الإرسال الفعلي.
أدلة ذات صلة
من الأساسيات إلى الإنتاج في دليل واحد —ابدأ بـ CaptchaAI.