حين يفشل reCAPTCHA غير المرئي في الأتمتة، يكون الرمز في الغالب صحيحًا ومحلولًا بالفعل؛ العطل أنه لا يصل إلى النموذج عبر رد النداء وضمن مهلة الصلاحية. فالنسخة غير المرئية تُلغي مربع الاختيار وتنقل التحقق بالكامل إلى طبقة JavaScript ورد النداء، ومن هذه النقطة تحديدًا تبدأ أغلب الأعطال.
في الممارسة العملية، تتكرر أربعة أعطال أكثر من غيرها:
- الأداة غير المرئية لا تُكتشف أصلًا على الصفحة.
- رد النداء (callback) لا يُستدعى بعد حقن الرمز.
- الرمز يُرسَل بعد انتهاء صلاحيته.
- الطلب يُرسَل بمعاملات v2 القياسية دون
invisible=1.
يشرح هذا الدليل كل نمط من هذه الأخطاء مع الإصلاح الدقيق له. وإذا كنت بحاجة إلى فهم آلية عمل النسخة غير المرئية أولًا، فابدأ من كيف يعمل reCAPTCHA غير المرئي وطريقة حله.
ابدأ من هنا: الرمز الصحيح وحده لا يكفي؛ يجب أن يصل إلى النموذج عبر رد النداء وخلال 120 ثانية. ومعظم الإصلاحات التالية تدور حول هاتين النقطتين.
مرجع سريع لأكواد الخطأ
تبدأ عملية التشخيص من رسالة الخطأ نفسها. يلخّص الجدول التالي أكثر الأكواد ظهورًا مع سببها وإصلاحه السريع، ثم نفصّل كل حالة في الأقسام اللاحقة:
| الكود أو العرض | السبب المباشر | الإصلاح السريع |
|---|---|---|
ERROR_WRONG_GOOGLEKEY |
مفتاح موقع خاطئ أو منسوخ من نطاق مختلف | استخرج مفتاح الموقع من div الأداة غير المرئية أو من استدعاء grecaptcha.render() |
ERROR_PAGEURL |
عدم تطابق العنوان — أُرسل عنوان الصفحة الأم بدل عنوان الـ iframe | استخدم العنوان الدقيق الذي تُحمَّل عنده الأداة غير المرئية |
ERROR_CAPTCHA_UNSOLVABLE |
وسمت Google المهمة بأنها غير قابلة للحل | أعد المحاولة بوكيل وملفات ارتباط جديدة، وتحقق مما إذا كان الموقع قد انتقل إلى v3 |
ERROR_BAD_TOKEN_OR_PAGEURL |
رفض الموقع المستهدف الرمز | تأكد من تطابق pageurl تمامًا، واحقن الرمز عبر رد النداء لا الحقل المخفي |
CAPCHA_NOT_READY |
المهمة ما زالت قيد المعالجة | تابع الاستطلاع الدوري كل 5 ثوانٍ؛ يستغرق الحل غير المرئي من 10 إلى 30 ثانية |
ERROR_KEY_DOES_NOT_EXIST |
مفتاح CaptchaAI API غير صالح | تحقق من المفتاح في captchaai.com/account |
| قُبِل الرمز لكن فشل النموذج | لم يُنفَّذ رد النداء بعد حقن الرمز | ابحث عن دالة data-callback واستدعِها بالرمز |
لماذا يفشل reCAPTCHA غير المرئي بطريقة مختلفة عن v2
في مربع الاختيار v2، يكفي عادةً حقن الرمز في الحقل المخفي g-recaptcha-response ليقبله النموذج. أما النسخة غير المرئية فتنقل التحقق بالكامل إلى طبقة برمجية، ويتضح الفرق في نقطتين:
- الإطلاق: v2 القياسي ينتظر تفاعل المستخدم، بينما تُطلَق النسخة غير المرئية برمجيًا عبر
grecaptcha.execute()دون أي عنصر ظاهر. - التسليم: v2 يقبل الرمز في الحقل المخفي، بينما تشترط النسخة غير المرئية تنفيذ رد النداء بعد حقن الرمز.
قاعدة عملية: إذا كان الرمز يُقبل من CaptchaAI لكن النموذج لا يتقدّم، فالخلل في تسليم الرمز (رد النداء) لا في الحل نفسه.
مثال من الواقع: عند أتمتة اختبارات الجودة لبوابة حجوزات إقليمية تعمل بالعربية، قد تظهر صفحة تسجيل الدخول سليمة بصريًا دون أي مربع اختيار، فيُرفَض الدخول بصمت لأن السكربت لم يكتشف الأداة غير المرئية ولم يستدعِ رد النداء. والأقسام التالية مرتّبة حسب النقطة التي يتعطّل عندها سير العمل.
الخطأ 1: الصفحة تستخدم reCAPTCHA غير مرئي دون أن يكتشفه السكربت
النسخة غير المرئية بلا مربع اختيار ظاهر، لذلك قد يمرّ السكربت على الصفحة دون أن يلاحظ وجود تحقق أصلًا، فتفشل الطلبات المحمية بصمت عبر أخطاء إرسال النموذج أو عمليات إعادة توجيه غير متوقعة. علامات تدل على وجود أداة غير مرئية لم تُكتشَف:
- النموذج يُرسَل لكن لا شيء يحدث بعده.
- إعادة توجيه متكررة إلى الصفحة نفسها بعد الإرسال.
- استجابة الخادم تشير إلى فشل التحقق دون رسالة واضحة.
كيف تكتشف reCAPTCHA غير المرئي
ابحث عن هذه الأنماط في HTML الصفحة:
<!-- Pattern 1: div with data-size="invisible" -->
<div class="g-recaptcha" data-sitekey="6LdKlZEU..."
data-size="invisible"
data-callback="onSubmit"></div>
<!-- Pattern 2: button with data-sitekey and invisible size -->
<button class="g-recaptcha"
data-sitekey="6LdKlZEU..."
data-callback="onSubmit"
data-action="submit">Submit</button>
<!-- Pattern 3: programmatic render with size: invisible -->
<script>
grecaptcha.render('submit-btn', {
sitekey: '6LdKlZEU...',
callback: onSubmit,
size: 'invisible'
});
</script>
سكربت الكشف (Python):
import requests
from bs4 import BeautifulSoup
import re
def detect_invisible_recaptcha(url):
resp = requests.get(url)
soup = BeautifulSoup(resp.text, "html.parser")
# Check for data-size="invisible"
widget = soup.find("div", {"data-size": "invisible", "class": "g-recaptcha"})
if widget:
return {
"type": "invisible",
"sitekey": widget.get("data-sitekey"),
"callback": widget.get("data-callback")
}
# Check for programmatic render with invisible
scripts = soup.find_all("script")
for script in scripts:
if script.string and "size" in str(script.string) and "invisible" in str(script.string):
key_match = re.search(r"sitekey['\"]?\s*[:=]\s*['\"]([^'\"]+)", script.string)
if key_match:
return {
"type": "invisible-programmatic",
"sitekey": key_match.group(1),
"callback": "check grecaptcha.render() call"
}
return None
سكربت الكشف (Node.js):
const axios = require("axios");
const cheerio = require("cheerio");
async function detectInvisibleRecaptcha(url) {
const { data } = await axios.get(url);
const $ = cheerio.load(data);
// Check for data-size="invisible"
const widget = $(".g-recaptcha[data-size='invisible']");
if (widget.length) {
return {
type: "invisible",
sitekey: widget.attr("data-sitekey"),
callback: widget.attr("data-callback"),
};
}
// Check script tags for programmatic invisible render
const scriptContent = $("script")
.map((_, el) => $(el).html())
.get()
.join("\n");
if (scriptContent.includes("invisible")) {
const keyMatch = scriptContent.match(/sitekey['"]?\s*[:=]\s*['"]([^'"]+)/);
if (keyMatch) {
return {
type: "invisible-programmatic",
sitekey: keyMatch[1],
callback: "check grecaptcha.render() call",
};
}
}
return null;
}
الخطأ 2: مفتاح موقع خاطئ — ERROR_WRONG_GOOGLEKEY
يظهر هذا الكود عندما يكون مفتاح الموقع (sitekey) المُرسَل غير مطابق للأداة غير المرئية في الصفحة المستهدفة. من أكثر الأسباب تكرارًا:
| السبب | ما الذي حدث فعليًا |
|---|---|
| نُسخ المفتاح من مربع اختيار v2 | المفتاح يخص أداة أخرى في صفحة مختلفة |
| مفتاح من العنوان الأساسي لإصدار مختلف | لا يطابق الأداة غير المرئية المستهدفة |
| وجود أدوات reCAPTCHA متعددة | التُقط مفتاح الأداة الخطأ |
الإصلاح: استخرج مفتاح الموقع غير المرئي الصحيح
استهدف الأداة غير المرئية تحديدًا عند استخراج المفتاح، لا أول عنصر g-recaptcha تجده على الصفحة:
import requests
from bs4 import BeautifulSoup
def get_invisible_sitekey(url):
resp = requests.get(url)
soup = BeautifulSoup(resp.text, "html.parser")
# Priority 1: invisible widget
widget = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
if widget:
return widget["data-sitekey"]
# Priority 2: any g-recaptcha div (may be invisible without data-size)
widget = soup.find(class_="g-recaptcha")
if widget and widget.get("data-sitekey"):
return widget["data-sitekey"]
return None
sitekey = get_invisible_sitekey("https://example.com/login")
print(f"Sitekey: {sitekey}")
الخطأ 3: رد النداء لا يُستدعى — النموذج يُرسَل دون نتيجة
تنبيه: هذا هو العطل الأول الذي يغفله المطورون في reCAPTCHA غير المرئي. فخلافًا لمربع الاختيار v2 حيث يكفي حقن الرمز في
g-recaptcha-response، تعتمد النسخة غير المرئية دائمًا تقريبًا على دالة رد نداء بلغة JavaScript؛ فإن حقنت الرمز دون استدعاء رد النداء لن يُعالَج النموذج إطلاقًا.
كيف يعمل تدفق رد النداء
grecaptcha.execute()يُطلق التحدي غير المرئي- بعد الحل، يستدعي Google الدالة المحددة في
data-callback - تتولى دالة رد النداء إرسال النموذج أو تنفيذ استدعاء API
الإصلاح: ابحث عن رد النداء ونفّذه
الخطوة 1 — حدّد اسم رد النداء:
# From HTML: data-callback="onSubmit"
# From JS: callback: onSubmit
# From grecaptcha.render: second argument with callback property
الخطوة 2 — احقن الرمز واستدعِ رد النداء (Selenium):
from selenium import webdriver
import requests
import time
driver = webdriver.Chrome()
driver.get("https://example.com/form")
# Get sitekey
sitekey = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-sitekey")
callback_name = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
# Solve with CaptchaAI
task_id = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": driver.current_url,
"invisible": 1
}).text.split("|")[1]
# Poll for result
token = None
for _ in range(60):
time.sleep(5)
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY",
"action": "get",
"id": task_id
}).text
if resp.startswith("OK|"):
token = resp.split("|")[1]
break
# Inject token into the response field
driver.execute_script(
f'document.getElementById("g-recaptcha-response").value = "{token}";'
)
# CRITICAL: Call the callback function
driver.execute_script(f'{callback_name}("{token}");')
الخطوة 2 — احقن الرمز واستدعِ رد النداء (Puppeteer):
const puppeteer = require("puppeteer");
const axios = require("axios");
(async () => {
const browser = await puppeteer.launch({ headless: "new" });
const page = await browser.newPage();
await page.goto("https://example.com/form");
// Get sitekey and callback
const { sitekey, callback } = await page.evaluate(() => {
const el = document.querySelector(".g-recaptcha[data-size='invisible']");
return {
sitekey: el?.getAttribute("data-sitekey"),
callback: el?.getAttribute("data-callback"),
};
});
// Submit to CaptchaAI
const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
params: {
key: "YOUR_API_KEY",
method: "userrecaptcha",
googlekey: sitekey,
pageurl: page.url(),
invisible: 1,
},
});
const taskId = submitResp.data.split("|")[1];
// Poll for result
let token;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: "YOUR_API_KEY", action: "get", id: taskId },
});
if (result.data.startsWith("OK|")) {
token = result.data.split("|")[1];
break;
}
}
// Inject token and fire callback
await page.evaluate(
(tok, cb) => {
document.getElementById("g-recaptcha-response").value = tok;
if (cb && typeof window[cb] === "function") {
window[cb](tok);
}
},
token,
callback,
);
await browser.close();
})();
الخطأ 4: غياب المعامل invisible=1
مهم: عند حل النسخة غير المرئية عبر CaptchaAI يجب تضمين
invisible=1في الطلب. بدونه تُعامَل المهمة كتحدي مربع اختيار v2 قياسي، ما قد يؤدي إلىERROR_CAPTCHA_UNSOLVABLEأو إلى رموز يرفضها الموقع المستهدف.
الطلب الخاطئ مقابل الطلب الصحيح
# WRONG — missing invisible=1
params = {
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url
}
# CORRECT — includes invisible=1
params = {
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1 # Required for invisible reCAPTCHA
}
response = requests.get("https://ocr.captchaai.com/in.php", params=params)
الخطأ 5: انتهاء صلاحية الرمز قبل الإرسال
ملاحظة: تنتهي صلاحية رموز reCAPTCHA خلال 120 ثانية، تمامًا كما في v2 القياسي. لكن سير العمل غير المرئي غالبًا ما يضيف خطوات معالجة بين لحظة الحل ولحظة الإرسال، ما يجعل انتهاء الصلاحية أكثر احتمالًا.
الأعراض التي تدل على انتهاء الصلاحية:
- النموذج يُرجع خطأ عامًا بعد حقن الرمز.
- تحقق الخادم عبر
siteverifyيُرجعtimeout-or-duplicate. - الرمز كان صالحًا لكنه استغرق وقتًا طويلًا حتى الوصول إلى خطوة الإرسال.
الإصلاح: احلّ في الوقت المناسب
اطلب الحل فقط عندما تكون جاهزًا للإرسال الفوري:
import requests
import time
def solve_invisible_recaptcha(api_key, sitekey, page_url):
# Submit task
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1
})
if not resp.text.startswith("OK|"):
raise Exception(f"Submit failed: {resp.text}")
task_id = resp.text.split("|")[1]
# Poll for result
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.startswith("OK|"):
return result.text.split("|")[1]
if result.text != "CAPCHA_NOT_READY":
raise Exception(f"Solve failed: {result.text}")
raise Exception("Solve timed out after 5 minutes")
# Usage: solve JUST before you need to submit
# 1. Navigate to page and prepare form data first
# 2. THEN solve the captcha
# 3. Inject token and submit immediately
token = solve_invisible_recaptcha("YOUR_API_KEY", sitekey, page_url)
# Submit within 120 seconds of receiving the token
الخطأ 6: رفض الرمز — ERROR_BAD_TOKEN_OR_PAGEURL
تحقّق الموقع المستهدف من الرمز لدى Google فحصل على فشل. الأسباب الشائعة وطريقة تمييزها:
| السبب | كيف تتعرّف عليه | الإصلاح |
|---|---|---|
pageurl خاطئ |
العنوان لا يطابق النطاق المسجَّل لمفتاح الموقع | استخدم العنوان الدقيق الذي تُحمَّل عنده الأداة |
| استُخدم الرمز على نطاق مختلف | إعادة استخدام الرمز عبر النطاقات | احلّ باستخدام pageurl الخاص بالنطاق الصحيح |
| الرمز مُستخدَم مسبقًا | إرسال الرمز نفسه مرتين | اطلب حلًا جديدًا لكل عملية إرسال |
| عدم تطابق عنوان IP | عنوان IP لديك يختلف عن عنوان جلسة الحل | أضف معامل proxy لمطابقة عنوان IP للجلسة |
غياب علم invisible |
حُلّ كـ v2 قياسي واستُخدم على صفحة غير مرئية | أضف invisible=1 إلى طلب الحل |
قائمة تحقق للتشخيص
شغّل عملية حل تشخيصية مع تسجيل مفصّل لعزل السبب:
def debug_invisible_solve(api_key, sitekey, page_url, proxy=None):
"""Run a diagnostic solve with detailed logging."""
print(f"Sitekey: {sitekey}")
print(f"Page URL: {page_url}")
print(f"Proxy: {proxy or 'none'}")
params = {
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1
}
if proxy:
params["proxy"] = proxy
params["proxytype"] = "HTTP"
# Submit
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
print(f"Submit response: {resp.text}")
if not resp.text.startswith("OK|"):
return None
task_id = resp.text.split("|")[1]
print(f"Task ID: {task_id}")
# Poll with timing
start = time.time()
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
})
elapsed = time.time() - start
print(f" [{elapsed:.0f}s] {result.text[:50]}")
if result.text.startswith("OK|"):
token = result.text.split("|")[1]
print(f"Token received after {elapsed:.0f}s")
print(f"Token length: {len(token)} characters")
print(f"Token starts with: {token[:30]}...")
return token
if result.text != "CAPCHA_NOT_READY":
print(f"FAILED: {result.text}")
return None
print("TIMEOUT after 5 minutes")
return None
الخطأ 7: أدوات reCAPTCHA متعددة في الصفحة نفسها
بعض الصفحات تجمع بين مربع اختيار v2 ظاهر وreCAPTCHA غير مرئي في آنٍ واحد.
نصيحة: إذا حللت الأداة الخطأ، فسيكون الرمز صالحًا لكنه لا يطابق الأداة التي تحمي الإجراء الذي تحتاجه، فيُرفَض عند الإرسال.
الإصلاح: استهدف الأداة الصحيحة
عدّد جميع أدوات reCAPTCHA على الصفحة أولًا، ثم اختر الأداة ذات size="invisible" تحديدًا:
from bs4 import BeautifulSoup
def find_all_recaptcha_widgets(html):
soup = BeautifulSoup(html, "html.parser")
widgets = []
for el in soup.find_all(class_="g-recaptcha"):
widgets.append({
"sitekey": el.get("data-sitekey"),
"size": el.get("data-size", "normal"),
"callback": el.get("data-callback"),
"tag": el.name,
"id": el.get("id")
})
return widgets
# Example output:
# [
# {"sitekey": "6LdA...", "size": "normal", "callback": None, "tag": "div", "id": "recaptcha-login"},
# {"sitekey": "6LdB...", "size": "invisible", "callback": "onRegister", "tag": "div", "id": "recaptcha-register"}
# ]
# Use the widget with size="invisible" for the invisible solve
حلّال reCAPTCHA غير المرئي كامل مع معالجة الأخطاء
نصيحة: يجمع هذا الغلاف الجاهز للإنتاج كل الإصلاحات السابقة في مكان واحد — تمييز الأخطاء الدائمة عن العابرة، وإعادة المحاولة الآمنة، والاستطلاع الدوري للنتيجة.
import requests
import time
import logging
logger = logging.getLogger(__name__)
class InvisibleRecaptchaSolver:
def __init__(self, api_key, max_retries=3):
self.api_key = api_key
self.max_retries = max_retries
self.base_url = "https://ocr.captchaai.com"
def solve(self, sitekey, page_url, proxy=None):
"""Solve invisible reCAPTCHA with automatic retry on transient errors."""
for attempt in range(1, self.max_retries + 1):
try:
token = self._attempt_solve(sitekey, page_url, proxy)
if token:
return token
except Exception as e:
logger.warning(f"Attempt {attempt} failed: {e}")
if attempt < self.max_retries:
time.sleep(2 ** attempt)
raise Exception(f"Failed to solve after {self.max_retries} attempts")
def _attempt_solve(self, sitekey, page_url, proxy):
params = {
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1
}
if proxy:
params["proxy"] = proxy
params["proxytype"] = "HTTP"
# Submit task
resp = requests.get(f"{self.base_url}/in.php", params=params)
if "ERROR" in resp.text:
error = resp.text.strip()
if error in ("ERROR_WRONG_GOOGLEKEY", "ERROR_KEY_DOES_NOT_EXIST"):
raise Exception(f"Configuration error (do not retry): {error}")
if error == "ERROR_ZERO_BALANCE":
raise Exception("Account balance is zero — add funds")
raise Exception(f"Submit error: {error}")
if not resp.text.startswith("OK|"):
raise Exception(f"Unexpected submit response: {resp.text}")
task_id = resp.text.split("|")[1]
# Poll for result
for _ in range(60):
time.sleep(5)
result = requests.get(f"{self.base_url}/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id
})
if result.text.startswith("OK|"):
return result.text.split("|")[1]
if result.text == "CAPCHA_NOT_READY":
continue
if result.text == "ERROR_CAPTCHA_UNSOLVABLE":
logger.warning("Captcha unsolvable — will retry with new task")
return None
raise Exception(f"Poll error: {result.text}")
raise Exception("Solve timed out after 5 minutes")
# Usage
solver = InvisibleRecaptchaSolver("YOUR_API_KEY")
token = solver.solve(
sitekey="6LdKlZEU...",
page_url="https://example.com/login"
)
print(f"Token: {token[:50]}...")
والنسخة نفسها بلغة Node.js:
const axios = require("axios");
class InvisibleRecaptchaSolver {
constructor(apiKey, maxRetries = 3) {
this.apiKey = apiKey;
this.maxRetries = maxRetries;
this.baseUrl = "https://ocr.captchaai.com";
}
async solve(sitekey, pageUrl, proxy) {
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
try {
const token = await this._attemptSolve(sitekey, pageUrl, proxy);
if (token) return token;
} catch (err) {
console.warn(`Attempt ${attempt} failed: ${err.message}`);
if (attempt < this.maxRetries) {
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
}
}
}
throw new Error(`Failed to solve after ${this.maxRetries} attempts`);
}
async _attemptSolve(sitekey, pageUrl, proxy) {
const params = {
key: this.apiKey,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageUrl,
invisible: 1,
};
if (proxy) {
params.proxy = proxy;
params.proxytype = "HTTP";
}
// Submit task
const submitResp = await axios.get(`${this.baseUrl}/in.php`, { params });
if (submitResp.data.includes("ERROR")) {
const error = submitResp.data.trim();
if (["ERROR_WRONG_GOOGLEKEY", "ERROR_KEY_DOES_NOT_EXIST"].includes(error)) {
throw new Error(`Configuration error (do not retry): ${error}`);
}
throw new Error(`Submit error: ${error}`);
}
const taskId = submitResp.data.split("|")[1];
// Poll for result
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get(`${this.baseUrl}/res.php`, {
params: { key: this.apiKey, action: "get", id: taskId },
});
if (result.data.startsWith("OK|")) {
return result.data.split("|")[1];
}
if (result.data === "CAPCHA_NOT_READY") continue;
if (result.data === "ERROR_CAPTCHA_UNSOLVABLE") return null;
throw new Error(`Poll error: ${result.data}`);
}
throw new Error("Solve timed out after 5 minutes");
}
}
// Usage
const solver = new InvisibleRecaptchaSolver("YOUR_API_KEY");
solver.solve("6LdKlZEU...", "https://example.com/login").then((token) => {
console.log(`Token: ${token.substring(0, 50)}...`);
});
قائمة التحقق النهائية عند فشل الحل
مرّ على هذه الخطوات بالترتيب عند تعطّل حل reCAPTCHA غير المرئي؛ كل خطوة تعزل سببًا محتملًا:
| الخطوة | التحقق | الأمر أو الإجراء |
|---|---|---|
| 1 | تأكد أنه غير مرئي وليس v2 قياسيًا | ابحث عن data-size="invisible" أو size: 'invisible' في استدعاء العرض |
| 2 | تحقق من صحة مفتاح الموقع | قارنه بقيمة data-sitekey على الأداة غير المرئية تحديدًا |
| 3 | أكّد وجود invisible=1 في طلب الـ API |
راجع معاملات in.php |
| 4 | تحقق من تطابق pageurl تمامًا |
استخدم عنوان أدوات مطوّري المتصفح، لا عنوان إعادة التوجيه |
| 5 | جد اسم دالة رد النداء | ابحث عن سمة data-callback أو callback داخل grecaptcha.render() |
| 6 | تحقق من حقن الرمز واستدعاء رد النداء معًا | الخطوتان مطلوبتان؛ الرمز وحده لا يكفي |
| 7 | تحقق من حداثة الرمز | يجب استخدام الرمز خلال 120 ثانية |
| 8 | اختبر بوكيل إذا كان عنوان IP مهمًا | أضف معاملي proxy وproxytype |
الأسئلة الشائعة
كيف أميّز reCAPTCHA غير المرئي عن v3 على الصفحة؟
- غير المرئي: يعرض شارة reCAPTCHA في زاوية الصفحة، ويعتمد على
data-size="invisible"أو علىgrecaptcha.execute()المربوط بزر. - v3: يعمل في الخلفية على كل صفحة ويعيد درجة (score) دون أي تفاعل، وغالبًا بلا شارة ظاهرة.
- للتمييز بينهما: افحص HTML بحثًا عن
data-sizeأو عن استدعاء render صريح.
لماذا يتكرر ERROR_CAPTCHA_UNSOLVABLE رغم صحة المفتاح؟
غالبًا لأن الطلب أُرسل دون invisible=1، فيُعامَل التحدي كـ v2 قياسي ويتعذّر حله. تحقق أيضًا من سمعة عنوان IP وملفات تعريف الارتباط، وأعد المحاولة بوكيل نظيف. وإذا استمر الخطأ رغم ذلك، فقد يكون الموقع قد انتقل إلى v3.
هل يمكنني إعادة استخدام الرمز نفسه لأكثر من عملية إرسال؟
لا. كل رمز صالح لعملية إرسال واحدة، وتنتهي صلاحيته خلال 120 ثانية. إعادة استخدام الرمز نفسه تؤدي إلى timeout-or-duplicate أو ERROR_BAD_TOKEN_OR_PAGEURL. اطلب حلًا جديدًا لكل محاولة إرسال.
متى أحتاج إلى بروكسي لحل النسخة غير المرئية؟
ليس دائمًا. لكن إذا كان الموقع يقارن عنوان IP الذي حُلّ عبره الرمز بعنوان جلستك، فأضف معاملي proxy وproxytype لمطابقة عنوان IP للجلسة. هذا يفسّر غالبًا نجاح الرمز في بيئة الاختبار وفشله في الإنتاج.
هل يلزم متصفح فعلي لحل reCAPTCHA غير المرئي؟
ليس بالضرورة. بما أن الحل يجري من جانب الخادم عبر الـ API، فأنت تحتاج فقط إلى مفتاح الموقع وعنوان الصفحة للحصول على الرمز. المتصفح يلزم فقط إذا كان عليك تنفيذ دالة رد النداء على الصفحة الفعلية لإتمام الإرسال.
الخطوات التالية
- ابدأ سريعًا مع CaptchaAI: أول كابتشا محلولة في 5 دقائق
- طريقة حل Cloudflare Turnstile عبر الـ API
- طريقة حل GeeTest v3 عبر الـ API