المقارنات

الاختلافات بين حلول Standard وEnterprise reCAPTCHA v2

تعود استجابة CaptchaAI بالحالة OK، ويصل الرمز سليماً إلى السكربت، ثم يرفضه الموقع المستهدف دون رسالة خطأ واضحة. في أغلب هذه الحالات لا علاقة للأمر بجودة الحل: الصفحة تعمل بإصدار reCAPTCHA v2 Enterprise بينما أُرسل الطلب مضبوطاً على الإصدار القياسي — أو العكس تماماً.

الإصداران يعرضان الواجهة نفسها للمستخدم: مربع "أنا لست روبوتًا" وشبكات الصور 3×3 أو 4×4. الاختلاف كله في الواجهة الخلفية لدى Google — رموز الأسباب والقواعد المخصصة والإدارة عبر Google Cloud — أما في طرف التكامل فينحصر في معامل واحد: enterprise=1.

وترتيب العمل الصحيح واضح: اقرأ الصفحة، حدّد الإصدار، ثم أرسل الطلب المناسب — وعلى هذا الترتيب يسير ما تبقّى من الدليل.


الإجابة المختصرة: ما الذي يتغيّر في تكاملك

  • شكل التحدي: لا شيء. مربع الاختيار وشبكات الصور متطابقة، ووقت الحل المعتاد 10–30 ثانية في الحالتين.
  • ملف JavaScript: الإصدار القياسي يحمّل api.js، وEnterprise يحمّل enterprise.js — وهذه هي العلامة الفاصلة الموثوقة.
  • طلب CaptchaAI: المعاملات نفسها والطريقة userrecaptcha نفسها، مع إضافة enterprise=1 في حالة Enterprise فقط.
  • الاستطلاع الدوري وحقن الرمز: متطابقان، ويستخدمان الحقل g-recaptcha-response نفسه.
  • رموز الأسباب والقواعد المخصصة: تخصّ الواجهة الخلفية للموقع، ولا تصل إلى مزوّد الحل أصلاً.

الخطوة الأولى: حدّد إصدار reCAPTCHA v2 قبل إرسال أي طلب

العلامة الفاصلة موجودة في وسم <script> الذي تحمّله الصفحة، لا في شكل الودجت المعروض.

افحص وسم script يدوياً

<!-- Standard v2 -->
<script src="https://www.google.com/recaptcha/api.js"></script>

<!-- Enterprise v2 -->
<script src="https://www.google.com/recaptcha/enterprise.js"></script>

إن ظهر enterprise.js فالصفحة تعمل بـ reCAPTCHA v2 Enterprise. ولا تكتفِ بمصدر الصفحة في المواقع التي تبني واجهتها في المتصفح؛ راجع تبويب Network.

كشف تلقائي في Python

import requests
from bs4 import BeautifulSoup

def detect_recaptcha_version(url):
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")

    enterprise_script = soup.find("script", src=lambda s: s and "enterprise.js" in s)
    standard_script = soup.find("script", src=lambda s: s and "recaptcha/api.js" in s)

    widget = soup.find(class_="g-recaptcha")
    sitekey = widget["data-sitekey"] if widget else None

    if enterprise_script:
        return {"version": "enterprise_v2", "sitekey": sitekey}
    elif standard_script:
        return {"version": "standard_v2", "sitekey": sitekey}
    return None

info = detect_recaptcha_version("https://example.com/login")
print(info)

الدالة تعيد الإصدار ومفتاح الموقع معاً، وهما ما ستحتاجه في الطلب التالي. وقد يوجد data-sitekey على عنصر مختلف عن .g-recaptcha في التطبيقات أحادية الصفحة.

كشف تلقائي في Node.js

const axios = require("axios");
const cheerio = require("cheerio");

async function detectRecaptchaVersion(url) {
  const { data } = await axios.get(url);
  const $ = cheerio.load(data);

  const hasEnterprise = $('script[src*="enterprise.js"]').length > 0;
  const hasStandard = $('script[src*="recaptcha/api.js"]').length > 0;
  const sitekey = $(".g-recaptcha").attr("data-sitekey");

  if (hasEnterprise) return { version: "enterprise_v2", sitekey };
  if (hasStandard) return { version: "standard_v2", sitekey };
  return null;
}

المنطق نفسه بمكتبتي Axios وcheerio لمن يبني خط الأتمتة على Node.js، بمخرجات موحّدة بين النسختين.

فحص سريع من وحدة تحكم المتصفح

// Quick check in DevTools
if (document.querySelector('script[src*="enterprise.js"]')) {
  console.log("Enterprise v2");
} else if (document.querySelector('script[src*="recaptcha/api.js"]')) {
  console.log("Standard v2");
}

مفيد أثناء التطوير: الصق السطر في وحدة التحكم واعرف الإصدار خلال ثانية.


إرسال الطلب إلى CaptchaAI: الفرق معامل واحد

نقطة النهاية واحدة في الحالتين — إرسال إلى in.php ثم استطلاع دوري على res.php حتى تعود الاستجابة بالبادئة OK|. راجع دليل حل reCAPTCHA v2 عبر الـ API خطوة بخطوة إن كنت تبني هذا المسار لأول مرة.

مسار reCAPTCHA v2 القياسي

import requests
import time

# Submit task
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

# Poll for token
for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

المعرّف العائد من in.php هو ما تستفسر به لاحقاً؛ اجعل مهلة الانتظار معقولة وسجّل كل استجابة غير متوقعة.

مسار reCAPTCHA v2 Enterprise

import requests
import time

# Submit task — only difference is enterprise=1
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url,
    "enterprise": 1  # Required for Enterprise
})
task_id = resp.text.split("|")[1]

# Polling is identical
for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

لا تغيير في نقطة النهاية ولا في الطريقة ولا في دورة الاستطلاع؛ الإضافة الوحيدة هي enterprise: 1.

فئة واحدة تكتشف وتحل

import requests
import time
from bs4 import BeautifulSoup

class RecaptchaV2Solver:
    def __init__(self, api_key):
        self.api_key = api_key

    def detect_and_solve(self, page_url, page_html=None):
        if not page_html:
            page_html = requests.get(page_url).text

        soup = BeautifulSoup(page_html, "html.parser")
        is_enterprise = bool(soup.find("script", src=lambda s: s and "enterprise.js" in s))
        widget = soup.find(class_="g-recaptcha")
        sitekey = widget["data-sitekey"] if widget else None

        if not sitekey:
            raise Exception("No reCAPTCHA sitekey found on page")

        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url
        }
        if is_enterprise:
            params["enterprise"] = 1

        resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit failed: {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": self.api_key, "action": "get", "id": task_id
            })
            if result.text.startswith("OK|"):
                return {
                    "token": result.text.split("|")[1],
                    "is_enterprise": is_enterprise,
                    "sitekey": sitekey
                }
            if result.text != "CAPCHA_NOT_READY":
                raise Exception(f"Solve failed: {result.text}")

        raise Exception("Solve timed out")


solver = RecaptchaV2Solver("YOUR_API_KEY")
result = solver.detect_and_solve("https://example.com/login")
print(f"Enterprise: {result['is_enterprise']}, Token: {result['token'][:40]}...")

دمج الخطوتين يلغي الحاجة إلى فرع منفصل لكل إصدار، ويحمي الكود من التعطل حين يرقّي الموقع حمايته دون إشعار. ولاحظ أن CAPCHA_NOT_READY حالة انتظار طبيعية لا فشلاً.


حقن الرمز في الصفحة — إجراء واحد للإصدارين

بعد الحصول على الرمز، الخطوات متطابقة: املأ الحقل g-recaptcha-response، ثم استدعِ دالة data-callback إن كانت الصفحة تعتمد عليها.

# Selenium injection — works for both standard and enterprise
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# If the page uses a callback function
callback = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
if callback:
    driver.execute_script(f'{callback}("{token}");')

وفي Puppeteer المنطق نفسه، مع تمرير الرمز إلى سياق الصفحة:

// Puppeteer injection — works for both
await page.evaluate((token) => {
  document.getElementById("g-recaptcha-response").value = token;
  // Find and call callback if present
  const widget = document.querySelector(".g-recaptcha");
  const cb = widget?.getAttribute("data-callback");
  if (cb && typeof window[cb] === "function") {
    window[cb](token);
  }
}, token);

إهمال استدعاء data-callback من أكثر أسباب بقاء زر الإرسال معطلاً رغم أن الرمز في مكانه الصحيح.


جدول الفروق التفصيلي بين إصداري reCAPTCHA v2

العنصر reCAPTCHA v2 القياسي reCAPTCHA v2 Enterprise
ودجت مربع الاختيار نعم — مظهر متطابق نعم — مظهر متطابق
تحديات الصور شبكات 3×3 أو 4×4 شبكات 3×3 أو 4×4
ملف JavaScript api.js enterprise.js
دالة التنفيذ grecaptcha.execute() grecaptcha.enterprise.execute()
واجهة التحقق لدى Google siteverify — مجانية recaptchaenterprise.googleapis.com — مدفوعة
رموز الأسباب غير متاحة متاحة — AUTOMATION وTOO_MUCH_TRAFFIC وغيرها
القواعد المخصصة غير متاحة متاحة — حدود لكل إجراء
الإدارة عبر Google Cloud Console غير متاحة متاحة — إدارة قائمة على المشاريع
كشف تسريب كلمات المرور غير متاح متاح
بنية الرمز المُعاد البنية نفسها البنية نفسها
معامل CaptchaAI enterprise=1
وقت الحل المعتاد 10–30 ثانية 10–30 ثانية

من الواقع: لوحة تاجر واحدة بإصدارين مختلفين

في شركة مدفوعات بالقاهرة، يشغّل فريق التكامل اختبارات مجدولة على تسجيل الدخول إلى لوحة التاجر الخاصة بالشركة. فعّل فريق الأمن هناك reCAPTCHA v2 Enterprise على بيئة الإنتاج ضمن مشروع Google Cloud الخاص بها، وبقيت بيئة التهيئة على الإصدار القياسي. النتيجة أن السكربت الواحد يمرّ في التهيئة ويتعثّر في الإنتاج: الرمز يصل سليماً، ثم ترفضه الواجهة الخلفية عند التحقق.

المعالجة لم تكن في تبديل مزوّد الحل، بل في حذف الافتراض الثابت من الكود وتشغيل الكشف الموضّح أعلاه مع كل جلسة، فصارت قاعدة كود واحدة تخدم البيئتين وتحتمل أي ترقية لاحقة. وعلى مستوى التكلفة، تُحسب خطط CaptchaAI بعدد الـ threads المتزامنة لا بعدد عمليات الحل، مع عمليات حل غير محدودة خلال الشهر ودون رسوم إضافية بحسب نوع الـ CAPTCHA: مسار واحد تحت الاختبار يكفيه BASIC بسعر $15 شهرياً مع 5 threads، أما تشغيل عدة بوابات بالتوازي فيناسبه ADVANCE بسعر $90 شهرياً مع 50 thread. الأسعار بالدولار الأمريكي، وتبقى صفحة التسعير الرسمية المرجع قبل أي اعتماد.


الأخطاء الأكثر تكراراً في فرق الأتمتة

الخطأ ما الذي يحدث التصحيح
إضافة enterprise=1 إلى صفحة قياسية قد يعود رمز لا يقبله الموقع تحقق من enterprise.js قبل إضافة المعامل
إغفال enterprise=1 في صفحة Enterprise الواجهة الخلفية ترفض الرمز عند التحقق أضف المعامل كلما ظهر enterprise.js
استخدام مفتاح موقع خاطئ استجابة ERROR_WRONG_GOOGLEKEY استخرج data-sitekey من عنصر .g-recaptcha
الخلط بين v2 Enterprise وv3 Enterprise معاملات لا تناسب الصفحة v2 بمربع اختيار مرئي، وv3 يعمل في الخلفية بدرجة تقييم

الأسئلة الشائعة

هل ينجح الكشف عندما يُحمَّل ملف reCAPTCHA ديناميكياً؟

ليس دائماً. الكشف المعتمد على مصدر HTML الأولي يفشل حين تحقن الصفحة وسم <script> بعد تفاعل المستخدم. افتح الصفحة عندئذ عبر متصفح مؤتمت مثل Selenium أو Playwright، ومرّر ناتج HTML بعد اكتمال التحميل إلى دالة الكشف.

ما الفرق بين reCAPTCHA v2 Enterprise وv3 Enterprise؟

الإصدار v2 يعرض مربع اختيار أو تحدي صور يراه المستخدم، أما v3 فيعمل في الخلفية ويُرجع درجة تقييم دون تفاعل. الخلط بينهما يعني إرسال معاملات لا تناسب الصفحة، فتعود نتيجة لا يقبلها الموقع. تأكد من وجود عنصر .g-recaptcha مرئي قبل أن تقرر أنك أمام v2.

هل تختلف تكلفة حل Enterprise v2 عن الإصدار القياسي؟

ليس ضمن خطط CaptchaAI: الفوترة قائمة على عدد الـ threads المتزامنة، وكل خطة تشمل عمليات حل غير محدودة خلال الشهر دون رسوم إضافية بحسب نوع الـ CAPTCHA. ما يختلف فعلاً هو تكلفة التحقق لدى Google على مالك الموقع، لأن واجهة Enterprise مدفوعة.

كم عدد الـ threads الذي أحتاجه لعشرات الصفحات؟

الـ thread الواحد يعني عملية حل واحدة قيد التنفيذ، وبمجرد انتهائها يلتقط المهمة التالية. لذلك يحدد العدد سرعة الإنجاز لا سقفه الشهري. اختبار يومي على بضع صفحات يعمل بأريحية على BASIC بسعر $15 شهرياً مع 5 threads، أما التشغيل المتوازي الكثيف فيستفيد من ADVANCE بسعر $90 شهرياً مع 50 thread.

هل يتغيّر اسم حقل الرمز في صفحات Enterprise؟

لا. الرمز يُحقن في الحقل g-recaptcha-response نفسه، وبنيته لا تختلف بين الإصدارين. وإن اعتمد الموقع على data-callback فاستدعها بعد الحقن في الحالتين، وإلا بقي النموذج بلا إشعار باكتمال التحدي.


أدلة ذات صلة

التعليقات غير مفعّلة لهذا المقال.