عندما يصل سكربت الأتمتة إلى صفحة تسجيل دخول، غالباً ما يتوقّف عند اختبار CAPTCHA. الحل مباشر وفي أربع خطوات: يدير Selenium المتصفح ويستخرج مفتاح الموقع، ويتولّى CaptchaAI حل الاختبار وإعادة التوكن، ثم تحقن التوكن في الصفحة وترسل النموذج. الدورة نفسها — اكتشاف، حل، حقن، إرسال — تعمل مع reCAPTCHA v2 وv3 وCloudflare Turnstile وCAPTCHA الصور. في هذا الشرح نبني الدالة المساعدة مرة واحدة، ثم ننتهي بفئة Python تكتشف النوع وتحلّه وترسل النموذج تلقائياً.
مثال من المنطقة العربية: فريق يختبر آلياً تدفّق التسجيل في منتجه المحمي بـ Cloudflare Turnstile ضمن اختبارات الجودة (QA). يكفيه worker واحد على خطة BASIC ($15 شهرياً، 5 threads)، والفوترة على الـ threads المتزامنة مع حلول غير محدودة لكل thread، لا لكل عملية حل.
التثبيت والمتطلبات
ثبّت المكتبات الثلاث التي يعتمد عليها المثال: Selenium لقيادة المتصفح، وrequests للاتصال بـ API، وwebdriver-manager لتنزيل درايفر Chrome المطابق تلقائياً.
pip install selenium requests webdriver-manager
تهيئة متصفح Selenium لتشغيل مستقر
بعض المواقع تفحص علامة navigator.webdriver وتغيّر سلوكها بناءً عليها. الإعدادات التالية تُهيّئ Chrome بحيث لا يُعلن عن نفسه كمتصفح مُؤتمت، وتزيل هذه العلامة عبر أمر CDP قبل تحميل أي صفحة، ما يجعل جلسات الاختبار أكثر استقراراً.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def create_driver():
"""Create a Selenium driver with stealth-configuredion settings."""
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options,
)
# Remove webdriver flag
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
return driver
دالة الحل عبر CaptchaAI
هذه الدالة هي القلب المشترك لكل الأنواع: ترسل المهمة إلى in.php، تحتفظ بمعرّفها، ثم تستطلع res.php كل 5 ثوانٍ حتى يجهز التوكن أو تنتهي المهلة. يتغيّر method والمعاملات فقط بين نوع وآخر.
import time
import requests
API_KEY = "YOUR_API_KEY"
def solve_captcha(method, **params):
"""Generic CaptchaAI solver — works for all supported CAPTCHA types."""
submit_data = {
"key": API_KEY,
"method": method,
"json": 1,
**params,
}
submit = requests.post("https://ocr.captchaai.com/in.php", data=submit_data, timeout=30)
data = submit.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}, timeout=30).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
raise Exception("CAPTCHA unsolvable")
raise TimeoutError("Solve timed out")
حل reCAPTCHA v2 داخل Selenium
الدورة الكاملة: اكتشاف، حل، حقن التوكن، إرسال
الخطوات أربع: افتح الصفحة، استخرج مفتاح الموقع عبر تعبير نمطي، مرّره إلى CaptchaAI بالطريقة userrecaptcha، ثم احقن التوكن في الحقل g-recaptcha-response. وإن اعتمد النموذج على دالة callback، استدعها صراحةً قبل الإرسال.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
def solve_recaptcha_v2_selenium(driver, url):
"""Complete reCAPTCHA v2 solve in Selenium."""
driver.get(url)
# Wait for page to load
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Extract sitekey
page_source = driver.page_source
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', page_source)
if not match:
raise ValueError("reCAPTCHA sitekey not found")
sitekey = match.group(1)
print(f"Sitekey: {sitekey}")
# Solve via CaptchaAI
token = solve_captcha(
"userrecaptcha",
googlekey=sitekey,
pageurl=url,
)
print(f"Token received: {token[:50]}...")
# Inject token into the page
driver.execute_script(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
document.getElementById('g-recaptcha-response').style.display = 'block';
""")
# If there's a callback function, call it
driver.execute_script(f"""
if (typeof ___grecaptcha_cfg !== 'undefined') {{
var clients = ___grecaptcha_cfg.clients;
for (var key in clients) {{
var client = clients[key];
if (client.rr && client.rr.l) {{
client.rr.l.callback('{token}');
}}
}}
}}
""")
# Submit the form
submit_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], input[type='submit']")
submit_button.click()
return token
# Usage
driver = create_driver()
try:
solve_recaptcha_v2_selenium(driver, "https://example.com/login")
print(f"Current URL: {driver.current_url}")
finally:
driver.quit()
حل Cloudflare Turnstile داخل Selenium
يتبع Turnstile النمط نفسه مع اختلافين: مفتاح الموقع يبدأ عادةً بالمقطع 0x، والتوكن يُكتب في الحقل المخفي cf-turnstile-response. وإن غاب عن السمة data-sitekey، استخرجه من استدعاء JavaScript.
def solve_turnstile_selenium(driver, url):
"""Complete Turnstile solve in Selenium."""
driver.get(url)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Extract sitekey
page_source = driver.page_source
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', page_source)
if not match:
# Try JavaScript API pattern
match = re.search(r"sitekey\s*:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", page_source)
if not match:
raise ValueError("Turnstile sitekey not found")
sitekey = match.group(1)
print(f"Turnstile sitekey: {sitekey}")
# Solve via CaptchaAI
token = solve_captcha(
"turnstile",
sitekey=sitekey,
pageurl=url,
)
print(f"Turnstile token: {token[:50]}...")
# Inject token
driver.execute_script(f"""
// Set the hidden input value
var inputs = document.querySelectorAll('[name="cf-turnstile-response"]');
inputs.forEach(function(input) {{ input.value = '{token}'; }});
// Also try the callback approach
if (typeof turnstile !== 'undefined' && turnstile.getResponse) {{
// Widget already rendered
}}
""")
# Submit form
submit_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], input[type='submit']")
submit_button.click()
return token
حل CAPTCHA الصور داخل Selenium
لاختبارات الصور التقليدية (اكتب الحروف الظاهرة)، التقط لقطة للعنصر وحوّلها إلى base64، أرسلها بالطريقة base64، ثم اكتب الإجابة في حقل الإدخال.
import base64
def solve_image_captcha_selenium(driver, captcha_selector):
"""Solve image CAPTCHA visible in the browser."""
# Find the CAPTCHA image element
captcha_img = driver.find_element(By.CSS_SELECTOR, captcha_selector)
# Get image as base64
img_base64 = captcha_img.screenshot_as_base64
# Solve via CaptchaAI
answer = solve_captcha("base64", body=img_base64)
print(f"CAPTCHA answer: {answer}")
# Type the answer into the input field
captcha_input = driver.find_element(
By.CSS_SELECTOR, "input[name='captcha'], input[name='code'], input.captcha-input"
)
captcha_input.clear()
captcha_input.send_keys(answer)
return answer
حل reCAPTCHA v3 داخل Selenium
لا يعرض reCAPTCHA v3 مربع اختيار؛ يعمل في الخلفية ويعيد درجة ثقة مرتبطة بـ action محدد. مرّر مفتاح الموقع وقيمة الـ action إلى CaptchaAI، ثم احقن التوكن في الحقل g-recaptcha-response أو في أي حقل مخفي يحمل الاسم ذاته.
def solve_recaptcha_v3_selenium(driver, url, sitekey, action="verify"):
"""Solve reCAPTCHA v3 in Selenium."""
driver.get(url)
# Solve via CaptchaAI
token = solve_captcha(
"userrecaptcha",
googlekey=sitekey,
pageurl=url,
version="v3",
action=action,
)
# Inject token
driver.execute_script(f"""
// Set reCAPTCHA response
var textarea = document.getElementById('g-recaptcha-response');
if (textarea) {{
textarea.value = '{token}';
textarea.style.display = 'block';
}}
// Set any hidden input fields
var inputs = document.querySelectorAll('input[name="g-recaptcha-response"]');
inputs.forEach(function(input) {{ input.value = '{token}'; }});
""")
return token
فئة أتمتة متكاملة تكتشف النوع وتحلّه
تجمع فئة SeleniumCaptchaSolver كل ما سبق في مسار واحد: تفتح الصفحة، تكتشف نوع CAPTCHA، تستدعي دالة الحل المناسبة، تملأ الحقول، ثم ترسل النموذج — وهي ما ستستخدمه فعلياً في الإنتاج.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
import time
import requests
API_KEY = "YOUR_API_KEY"
class SeleniumCaptchaSolver:
"""Complete Selenium + CaptchaAI automation class."""
def __init__(self, api_key):
self.api_key = api_key
self.driver = None
def start(self):
"""Initialize the browser."""
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
self.driver = webdriver.Chrome(options=options)
self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
def stop(self):
"""Close the browser."""
if self.driver:
self.driver.quit()
def navigate(self, url):
"""Navigate to URL and wait for load."""
self.driver.get(url)
WebDriverWait(self.driver, 15).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
def detect_captcha(self):
"""Detect which CAPTCHA type is on the page."""
source = self.driver.page_source
if re.search(r'data-sitekey=["\'][A-Za-z0-9_-]{40}["\']', source):
if "recaptcha/api.js" in source or "grecaptcha" in source:
return "recaptcha_v2"
if "cf-turnstile" in source or "challenges.cloudflare.com/turnstile" in source:
return "turnstile"
if re.search(r'recaptcha.*v3|render=[A-Za-z0-9_-]{40}', source):
return "recaptcha_v3"
captcha_imgs = self.driver.find_elements(
By.CSS_SELECTOR, "img.captcha, img[alt*='captcha'], img[src*='captcha']"
)
if captcha_imgs:
return "image"
return None
def solve_and_submit(self, url, form_data=None):
"""Navigate, solve CAPTCHA, fill form, and submit."""
self.navigate(url)
captcha_type = self.detect_captcha()
if not captcha_type:
print("No CAPTCHA detected")
return self._fill_and_submit(form_data)
print(f"Detected: {captcha_type}")
if captcha_type == "recaptcha_v2":
self._solve_recaptcha_v2()
elif captcha_type == "turnstile":
self._solve_turnstile()
elif captcha_type == "image":
self._solve_image()
return self._fill_and_submit(form_data)
def _solve_recaptcha_v2(self):
source = self.driver.page_source
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', source)
sitekey = match.group(1)
token = self._api_solve("userrecaptcha", googlekey=sitekey, pageurl=self.driver.current_url)
self.driver.execute_script(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
""")
def _solve_turnstile(self):
source = self.driver.page_source
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', source)
sitekey = match.group(1)
token = self._api_solve("turnstile", sitekey=sitekey, pageurl=self.driver.current_url)
self.driver.execute_script(f"""
document.querySelectorAll('[name="cf-turnstile-response"]')
.forEach(function(el) {{ el.value = '{token}'; }});
""")
def _solve_image(self):
img = self.driver.find_element(
By.CSS_SELECTOR, "img.captcha, img[alt*='captcha'], img[src*='captcha']"
)
answer = self._api_solve("base64", body=img.screenshot_as_base64)
captcha_input = self.driver.find_element(
By.CSS_SELECTOR, "input[name='captcha'], input[name='code']"
)
captcha_input.clear()
captcha_input.send_keys(answer)
def _fill_and_submit(self, form_data):
if form_data:
for name, value in form_data.items():
try:
field = self.driver.find_element(By.NAME, name)
field.clear()
field.send_keys(value)
except Exception:
pass
submit = self.driver.find_element(
By.CSS_SELECTOR, "button[type='submit'], input[type='submit']"
)
submit.click()
time.sleep(3)
return self.driver.current_url
def _api_solve(self, method, **params):
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key, "method": method, "json": 1, **params,
}, timeout=30)
data = submit.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key, "action": "get", "id": task_id, "json": 1,
}, timeout=30).json()
if result.get("status") == 1:
return result["request"]
raise TimeoutError("Solve timed out")
# Usage
solver = SeleniumCaptchaSolver(API_KEY)
solver.start()
try:
result_url = solver.solve_and_submit(
"https://example.com/login",
form_data={"username": "user@example.com", "password": "pass123"},
)
print(f"Result: {result_url}")
finally:
solver.stop()
استكشاف الأخطاء الشائعة
| العرض (المشكلة) | السبب المحتمل | الحل |
|---|---|---|
| تم اكتشاف الاختبار لكن حقن التوكن يفشل | الحقل g-recaptcha-response غير موجود في الصفحة |
تحقّق من وجود iframe؛ قد يكون reCAPTCHA داخل إطار منفصل |
| تم حقن التوكن لكن النموذج لا يُرسَل | لم تُستدعَ دالة الـ callback | استدعِ دالة callback الخاصة بـ reCAPTCHA صراحةً |
| الموقع يُبلّغ عن "webdriver detected" | إعدادات التشغيل المستقر غير مُطبّقة | أضف أمر CDP الذي يزيل علامة webdriver |
| لقطة شاشة CAPTCHA فارغة | العنصر خارج نطاق العرض | مرّر العنصر إلى داخل الشاشة أولاً |
| رفض توكن Turnstile | مفتاح الموقع غير صحيح | أعد استخراجه من مصدر الصفحة المباشر |
الأسئلة الشائعة
هل تكفي دالة واحدة لحل reCAPTCHA وTurnstile وCAPTCHA الصور؟
نعم. الدالة solve_captcha تستقبل اسم الطريقة والمعاملات فقط، فتعمل مع userrecaptcha وturnstile وbase64 دون تغيير في منطقها — لذلك تبقى فئة SeleniumCaptchaSolver قصيرة.
كم يكلّف تشغيل هذا الحل عبر CaptchaAI؟
الفوترة على الـ threads المتزامنة لا على كل عملية حل، وكل خطة تشمل حلولاً غير محدودة لكل thread. تبدأ BASIC من $15 شهرياً مع 5 threads؛ راجع صفحة الأسعار الرسمية لاختيار الخطة الأنسب لحجمك.
هل يمكن حل hCaptcha أو FunCaptcha عبر CaptchaAI؟
لا، لا يدعم CaptchaAI حل hCaptcha ولا FunCaptcha (Arkose Labs). لكنه يحل reCAPTCHA v2/v3 بما فيها Enterprise، وCloudflare Turnstile وChallenge، وGeeTest v3، وCAPTCHA الصور والشبكية، وBLS، مع CaptchaFox وFriendly Captcha وLemin في مرحلة beta.
كيف أتعامل مع reCAPTCHA الموجود داخل iframe؟
انتقل إلى إطار reCAPTCHA أولاً عبر driver.switch_to.frame(...)، استخرج مفتاح الموقع، ثم عُد إلى المحتوى الأصلي بـ driver.switch_to.default_content().
هل يؤثر التشغيل بدون واجهة (headless) على نجاح الحل؟
الحل نفسه يجري على خوادم CaptchaAI فلا يتأثر بوضع headless. لكن بعض المواقع تكتشف هذا الوضع وتغيّر سلوكها، فاستخدم --headless=new وتأكّد من صحة بصمات WebGL/Canvas.
الخلاصة
يمنحك دمج CaptchaAI مع Selenium وPython مساراً واحداً لأي اختبار CAPTCHA في أتمتة المتصفح: اكتشف النوع من مصدر الصفحة، احصل على التوكن عبر API، احقنه بـ JavaScript، ثم أرسل النموذج. وفئة SeleniumCaptchaSolver تختصر هذا المسار في استدعاء واحد قابل لإعادة الاستخدام.
مقالات ذات صلة
- الفرق بين GeeTest وCloudflare Turnstile
- دمج CaptchaAI مع Google Cloud Functions
- دليل CaptchaAI مع Python وPlaywright