المقارنات

WebDriver مقابل بروتوكول Chrome DevTools لأتمتة CAPTCHA

اختيارك بين WebDriver وCDP لا يغيّر معدل حل CAPTCHA، فالحل يجري على خوادم CaptchaAI بعيداً عن المتصفح. ما يتغيّر شيئان: كم مرة يظهر التحدي أمام سكربتك، وكم سطراً تكتبه لاعتراض الطلبات وحقن الرمز.

  • WebDriver — معيار W3C يغطي Chrome وFirefox وSafari وEdge، لكنه يمرّ عبر ChromeDriver ويترك أثراً في الصفحة.
  • CDP — اتصال WebSocket مباشر مع Chrome، يمنحك اعتراض الشبكة وتعديل الاستجابة، ولا يعمل خارج Chromium.
  • CaptchaAI — مستقل عن الاثنين: نفس in.php وres.php ونفس وقت الحل.

بنية البروتوكولين

WebDriver (Selenium):
  Script ──HTTP──▶ ChromeDriver ──DevTools──▶ Chrome
  (JSON Wire)        (bridge)      (internal)

CDP (Puppeteer/Playwright):
  Script ──WebSocket──▶ Chrome
  (direct)               (no middle layer)

كل أمر في WebDriver يقطع رحلة HTTP إلى ChromeDriver ثم يُترجم إلى أوامر DevTools، بينما يتحدث CDP إلى Chrome عبر اتصال WebSocket واحد يبقى مفتوحاً طوال الجلسة.


الفروق العملية بين WebDriver وCDP

العنصر WebDriver CDP
البروتوكول HTTP + JSON WebSocket
سطح الكشف مرتفع — navigator.webdriver = true أقل وقابل للتعديل
اعتراض الشبكة يحتاج selenium-wire مدمج عبر Fetch وNetwork
تعديل الطلب والاستجابة غير مدعوم مدعوم
دعم المتصفحات Chrome وFirefox وSafari وEdge Chrome/Chromium فقط

ما تراه المواقع من كل بروتوكول

بصمة Selenium

المواقع تبحث عن متغيّرات محدّدة يتركها المتصفح المُدار:

// What sites check for Selenium
navigator.webdriver                    // true (set by ChromeDriver)
document.$cdc_asdjflasutopfhvcZLmcfl  // ChromeDriver internal variable
window.callSelenium                    // Older Selenium versions
window._selenium                      // Selenium internals
document.__webdriver_evaluate          // WebDriver namespace

وحتى بعد إخفاء العلامة، تبقى متغيّرات $cdc_ التي يحقنها ChromeDriver:

# Even with flag removal, ChromeDriver leaves traces
from selenium import webdriver

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(options=options)

# Still detectable via $cdc variables in document

بصمة Puppeteer عبر CDP

هنا تُضبط الخاصية قبل تحميل الصفحة، ولا وجود لمتغيّرات ChromeDriver أصلاً:

// Puppeteer sets webdriver flag too, but it's fully patchable
await page.evaluateOnNewDocument(() => {
  Object.defineProperty(navigator, 'webdriver', {
    get: () => undefined,
  });
  // No $cdc variables to worry about
  // No Selenium-specific traces
});

النتيجة سطح كشف أقل وتحديات أقل على الجلسة نفسها: بصمة أتمتة أنظف، لا وعد بتفادي الفحص.


حل reCAPTCHA v2 عبر CaptchaAI في Selenium

المسار واحد في أي مكتبة: استخرج sitekey، أرسل المهمة إلى in.php، استطلع res.php حتى تصل النتيجة، ثم احقن الرمز في g-recaptcha-response وأرسل النموذج.

# Selenium (WebDriver) + CaptchaAI
import requests
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

API_KEY = "YOUR_API_KEY"
API_URL = "https://ocr.captchaai.com"

options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(options=options)

driver.get("https://example.com/form")
time.sleep(2)

# Extract sitekey
sitekey = driver.execute_script(
    "return document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')"
)

# Solve via CaptchaAI
resp = requests.post(f"{API_URL}/in.php", data={
    "key": API_KEY, "method": "userrecaptcha",
    "googlekey": sitekey, "pageurl": driver.current_url, "json": 1,
})
task_id = resp.json()["request"]

for _ in range(60):
    time.sleep(5)
    resp = requests.get(f"{API_URL}/res.php", params={
        "key": API_KEY, "action": "get", "id": task_id, "json": 1,
    })
    data = resp.json()
    if data["request"] != "CAPCHA_NOT_READY":
        break

token = data["request"]

# Inject token
driver.execute_script(f"""
    document.querySelector('#g-recaptcha-response').value = '{token}';
    document.querySelectorAll('[name="g-recaptcha-response"]')
        .forEach(el => {{ el.value = '{token}'; }});
""")

driver.find_element(By.CSS_SELECTOR, "form").submit()
driver.quit()

كل استدعاء لـ execute_script يمرّ عبر الجسر ويضيف تأخيراً، فاجمع الحقن في استدعاء واحد.


المسار نفسه في Puppeteer

// Puppeteer (CDP) + CaptchaAI
const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");
const https = require("https");

puppeteer.use(StealthPlugin());

const API_KEY = "YOUR_API_KEY";
const API_URL = "https://ocr.captchaai.com";

function solveCaptcha(siteUrl, sitekey) {
  // Submit + poll (simplified)
  return new Promise(async (resolve, reject) => {
    const submitResp = await httpPost(`${API_URL}/in.php`, {
      key: API_KEY, method: "userrecaptcha",
      googlekey: sitekey, pageurl: siteUrl, json: "1",
    });

    const taskId = submitResp.request;

    for (let i = 0; i < 60; i++) {
      await new Promise((r) => setTimeout(r, 5000));
      const result = await httpGet(
        `${API_URL}/res.php?key=${API_KEY}&action=get&id=${taskId}&json=1`
      );
      if (result.request !== "CAPCHA_NOT_READY") {
        return resolve(result.request);
      }
    }
    reject(new Error("Timeout"));
  });
}

(async () => {
  const browser = await puppeteer.launch({
    headless: "new",
    args: ["--no-sandbox", "--window-size=1920,1080"],
  });

  const page = await browser.newPage();

  // CDP: Enable network interception
  const cdp = await page.createCDPSession();
  await cdp.send("Network.enable");

  // Monitor CAPTCHA-related requests
  cdp.on("Network.requestWillBeSent", (params) => {
    if (params.request.url.includes("recaptcha")) {
      console.log(`CAPTCHA request: ${params.request.url}`);
    }
  });

  await page.goto("https://example.com/form", { waitUntil: "networkidle0" });

  const sitekey = await page.evaluate(() =>
    document.querySelector("[data-sitekey]")?.getAttribute("data-sitekey")
  );

  if (sitekey) {
    const token = await solveCaptcha(page.url(), sitekey);

    // CDP: Inject via Runtime.evaluate (lower-level than page.evaluate)
    await cdp.send("Runtime.evaluate", {
      expression: `
        document.querySelector('#g-recaptcha-response').value = '${token}';
        document.querySelector('form').submit();
      `,
    });
  }

  await browser.close();
})();

استدعاء CaptchaAI متطابق؛ الفارق أنك تفتح جلسة CDP، وتراقب طلبات التحقق، وتحقن الرمز عبر Runtime.evaluate.


اعتراض الطلبات وتعديل الاستجابة والكوكيز

لا يملك WebDriver اعتراضاً أصلياً، بل يحتاج selenium-wire الذي يمرّر الحركة عبر خادم وسيط محلي:

# WebDriver: Cannot intercept requests natively
# Requires selenium-wire (third-party)
from seleniumwire import webdriver

driver = webdriver.Chrome()
# selenium-wire proxies all traffic through a local proxy

أما في CDP فالاعتراض جزء من البروتوكول:

// CDP: Built-in request interception
await cdp.send("Fetch.enable", {
  patterns: [{ urlPattern: "*recaptcha*" }],
});

cdp.on("Fetch.requestPaused", async ({ requestId, request }) => {
  console.log(`Intercepted: ${request.url}`);
  await cdp.send("Fetch.continueRequest", { requestId });
});

ويمكنك إعادة استجابة معدّلة في بيئات الاختبار التي تملكها:

// CDP: Can modify responses (WebDriver cannot)
cdp.on("Fetch.requestPaused", async ({ requestId, request }) => {
  if (request.url.includes("captcha-config")) {
    // Return modified response
    await cdp.send("Fetch.fulfillRequest", {
      requestId,
      responseCode: 200,
      body: btoa(JSON.stringify({ enabled: false })),
    });
  } else {
    await cdp.send("Fetch.continueRequest", { requestId });
  }
});

وفي الكوكيز يقرأ CDP الكوكيز المعلّمة بـ httpOnly ويكتبها، بخلاف واجهة WebDriver القياسية التي لا تصل إليها:

# WebDriver: Standard cookie API
driver.add_cookie({"name": "session", "value": "abc123"})
cookies = driver.get_cookies()
// CDP: Full cookie control including httpOnly
await cdp.send("Network.setCookie", {
  name: "session",
  value: "abc123",
  domain: "example.com",
  httpOnly: true,
  secure: true,
});

// Get all cookies including httpOnly (WebDriver can't access these)
const { cookies } = await cdp.send("Network.getAllCookies");

الجمع بين WebDriver وCDP في Selenium 4

لست مضطراً إلى الاختيار؛ يمرّر Selenium 4 أوامر CDP مباشرة:

from selenium import webdriver

driver = webdriver.Chrome()

# Use WebDriver for navigation
driver.get("https://example.com")

# Use CDP for stealth patches
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
        Object.defineProperty(navigator, 'webdriver', {
            get: () => undefined
        });
    """
})

# Use CDP for network events
driver.execute_cdp_cmd("Network.enable", {})

أرقام الأداء

المقياس WebDriver — Selenium CDP — Puppeteer CDP — Playwright
بدء الجلسة ~2.5 ثانية ~1.5 ثانية ~1.2 ثانية
زمن التنقل الإضافي — مللي ثانية ~500 ~100 ~80
تنفيذ سكربت — مللي ثانية ~200 ~50 ~40
الذاكرة لكل جلسة — ميجابايت ~350 ~280 ~260

وقت الحل واحد في البروتوكولين لأنه استدعاء API مستقل عن المتصفح: أقل من 60 ثانية لـ reCAPTCHA v2 وأقل من 10 ثوانٍ لـ Cloudflare Turnstile.


متى تختار كل بروتوكول

الحالة الأنسب السبب
اختبار عبر عدة متصفحات WebDriver تغطية Firefox وSafari وEdge
تقليل ظهور التحديات CDP بصمة أتمتة أنظف
فريق غير معتاد على CDP WebDriver واجهة أبسط وتوثيق أوسع
صفحات كثيفة التحقق CDP + CaptchaAI بصمة أنظف وحل مؤتمت
مسارات CI/CD قائمة WebDriver تكامل أنضج

سيناريو عملي: منصة حجوزات في الرياض

فريق يشغّل منصة حجوزات يحتاج إلى مسارين. اختبارات القبول تعمل على Chrome وSafari معاً لأن نصف الزوار يدخلون من iPhone، وهنا يبقى Selenium الخيار الوحيد. ومراقبة مسار إتمام الشراء تعمل على Chrome وحده كل خمس دقائق مع قراءة طلبات الشبكة، وهنا يتفوق CDP.

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


أعطال شائعة وعلاجها

العطل في WebDriver في CDP
الجلسة تُصنَّف كأتمتة excludeSwitches وضبط الخيارات إضافة stealth مع تعديل الخصائص
تعذّر اعتراض الطلبات استخدم selenium-wire فعّل Fetch.enable
بطء التنفيذ قلّل استدعاءات execute_script اجمع أوامر CDP في دفعة
فشل حقن الرمز تحقق من سياق الـ iframe Runtime.evaluate مع تحديد السياق

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

هل يغني CDP عن الخادم الوسيط؟

لا. البروتوكول لا يغيّر عنوان IP الذي يخرج منه الطلب، والجلسات المكثفة من عنوان واحد تزيد ظهور التحديات. وزّع الخروج وقلّل التزامن أولاً.

لماذا يفشل حقن الرمز رغم وصول الحل؟

السبب الأشهر هو سياق التنفيذ: الحقل داخل iframe والسكربت يعمل في الصفحة الأم. اضبط g-recaptcha-response في السياق الصحيح، ثم أطلق حدث التغيير قبل الإرسال.

كم thread أحتاج عند تشغيل متصفحات متوازية؟

العدد يقابل عمليات الحل الجارية في اللحظة نفسها لا عدد المتصفحات. عشر جلسات تصل إلى التحقق تباعاً قد تكتفي بـ 5 threads، ودفعة تنطلق معاً تحتاج thread لكل جلسة.

هل يدعم CaptchaAI أنواعاً أخرى في المسار نفسه؟

reCAPTCHA v2 وv3 وEnterprise وCloudflare Turnstile مدعومة. أما hCaptcha وFunCaptcha وGeeTest v4 فليست مدعومة، وCaptchaFox وFriendly Captcha وLemin في مرحلة beta فقط.


أدلة ذات صلة


اختر البروتوكول الذي يناسب فريقك ودع الحل خارج المتصفح — احصل على مفتاح CaptchaAI وشغّل المسار نفسه في المكتبتين.

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