عندما يصطدم سكربت Playwright باختبار CAPTCHA، يتوقّف التدفّق بالكامل: لا تسجيل دخول، ولا إرسال نموذج، ولا خطوة تالية. الحل المباشر هو فصل المهمتين — يتكفّل CaptchaAI بحلّ الاختبار على الخادم، بينما يبقى دور Playwright محصوراً في استخراج مفتاح الموقع وحقن الرمز الناتج ومتابعة السيناريو. يشرح هذا الدليل النمط نفسه في Python وNode.js، مع reCAPTCHA وCloudflare Turnstile، وبأمثلة جاهزة للنسخ.
كيف يتكامل Playwright مع CaptchaAI في أربع خطوات
يقوم النمط بأكمله على أربع خطوات متسلسلة تتكرّر مع كل نوع من أنواع CAPTCHA:
- يرصد Playwright وجود عنصر الاختبار في الصفحة (مثل
.g-recaptchaأو.cf-turnstile) ويقرأ سمةdata-sitekey. - يرسل السكربت مفتاح الموقع وعنوان الصفحة إلى CaptchaAI عبر نقطة النهاية
in.php، فتعيد الخدمة معرّف مهمة. - يستطلع السكربت نقطة
res.phpدورياً حتى يجهز الرمز — عادة خلال ثوانٍ. - يحقن السكربت الرمز الناتج في حقل الاستجابة المخفي داخل الصفحة، ثم يُكمل الإرسال.
الميزة الأساسية أن منطق الحل لا يعيش داخل المتصفح؛ يتولّاه CaptchaAI بالكامل، ويبقى Playwright أداة تحكّم في المتصفح فحسب. هذا الفصل يجعل السكربت أبسط وأكثر استقراراً عبر Chromium وFirefox وWebKit.
ما تحتاجه قبل البدء
تحتاج إلى بيئة Python أو Node.js، ومكتبة Playwright مثبّتة مع متصفحاتها، ومفتاح CaptchaAI API واحد يخدم كل الأمثلة أدناه:
| المتطلب | التفاصيل |
|---|---|
| Python | pip install playwright requests ثم playwright install |
| Node.js | npm install playwright axios |
| مفتاح CaptchaAI API | من captchaai.com |
بعد التثبيت، شغّل playwright install مرة واحدة لتنزيل المتصفحات. مفتاح الـ API نفسه يعمل مع reCAPTCHA وTurnstile دون أي إعداد إضافي لكل نوع.
Playwright مع CaptchaAI في Python
إعداد دالة الحل
الدالة التالية تختصر الدورة كاملة: ترسل مفتاح الموقع إلى CaptchaAI، ثم تستطلع النتيجة كل خمس ثوانٍ حتى يجهز الرمز أو تنتهي المهلة. استعملها كوحدة مستقلة تستدعيها من أي سيناريو Playwright:
from playwright.sync_api import sync_playwright
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_recaptcha(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url
})
if not resp.text.startswith("OK|"):
raise Exception(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": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY": continue
if result.text.startswith("OK|"): return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError()
لاحظ أن الحلقة تعيد المحاولة حتى 60 مرة بفاصل خمس ثوانٍ؛ هذا هامش كافٍ لأبطأ الحالات دون تعليق السكربت إلى ما لا نهاية.
مثال كامل: تسجيل دخول محمي بـ reCAPTCHA
يجمع المثال التالي كل شيء: يفتح صفحة تسجيل الدخول، يملأ بيانات الاعتماد، يكتشف reCAPTCHA إن وُجد، يحلّه عبر الدالة السابقة، يحقن الرمز، ثم يرسل النموذج وينتظر اكتمال التنقل:
def login_with_captcha(url, username, password):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
)
page = context.new_page()
page.goto(url)
# Fill login form
page.fill("#username", username)
page.fill("#password", password)
# Check for reCAPTCHA
recaptcha = page.query_selector(".g-recaptcha")
if recaptcha:
site_key = recaptcha.get_attribute("data-sitekey")
print(f"Solving reCAPTCHA: {site_key}")
token = solve_recaptcha(site_key, page.url)
# Inject token
page.evaluate(f"""
document.getElementById('g-recaptcha-response').innerHTML = '{token}';
document.getElementById('g-recaptcha-response').style.display = '';
""")
# Submit
page.click('button[type="submit"]')
page.wait_for_load_state("networkidle")
print(f"Current URL: {page.url}")
content = page.content()
browser.close()
return content
result = login_with_captcha(
"https://example.com/login",
"user@example.com",
"password123"
)
ضبط user_agent واقعي يقلّل احتمال ظهور تحديات إضافية، ويترك المجال لـ CaptchaAI للتعامل مع الاختبار المعروض فعلاً.
النسخة غير المتزامنة (async)
إذا كنت تدير عدة صفحات بالتوازي، فالنسخة غير المتزامنة أكفأ. تستبدل requests بـ aiohttp وتستخدم async_playwright، مع الحفاظ على منطق الاستطلاع نفسه:
from playwright.async_api import async_playwright
import aiohttp
import asyncio
async def solve_recaptcha_async(site_key, page_url):
async with aiohttp.ClientSession() as session:
params = {
"key": API_KEY, "method": "userrecaptcha",
"googlekey": site_key, "pageurl": page_url
}
async with session.get("https://ocr.captchaai.com/in.php", params=params) as resp:
text = await resp.text()
task_id = text.split("|")[1]
for _ in range(60):
await asyncio.sleep(5)
params = {"key": API_KEY, "action": "get", "id": task_id}
async with session.get("https://ocr.captchaai.com/res.php", params=params) as resp:
text = await resp.text()
if text == "CAPCHA_NOT_READY": continue
if text.startswith("OK|"): return text.split("|")[1]
raise Exception(text)
raise TimeoutError()
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://example.com/form")
site_key = await page.get_attribute(".g-recaptcha", "data-sitekey")
token = await solve_recaptcha_async(site_key, page.url)
await page.evaluate(f"document.getElementById('g-recaptcha-response').innerHTML = '{token}'")
await page.click('button[type="submit"]')
await browser.close()
asyncio.run(main())
هذا النمط مفيد عند تشغيل دفعات من الاختبارات المتوازية، حيث لا يحجب انتظار الحل بقية المهام.
Playwright مع CaptchaAI في Node.js
ينتقل المنطق ذاته إلى Node.js دون تغيير جوهري: axios بدل requests، ودالة solveRecaptcha تعيد المحاولة في حلقة while حتى يجهز الرمز. الواجهة البرمجية لـ CaptchaAI موحّدة، فلا حاجة لتعلّم تدفّق جديد:
const { chromium } = require("playwright");
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
async function solveRecaptcha(siteKey, pageUrl) {
const submit = await axios.get("https://ocr.captchaai.com/in.php", {
params: {
key: API_KEY,
method: "userrecaptcha",
googlekey: siteKey,
pageurl: pageUrl,
},
});
const taskId = submit.data.split("|")[1];
while (true) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId },
});
if (result.data === "CAPCHA_NOT_READY") continue;
if (result.data.startsWith("OK|")) return result.data.split("|")[1];
throw new Error(result.data);
}
}
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto("https://example.com/login");
// Fill form
await page.fill("#username", "user@example.com");
await page.fill("#password", "password123");
// Solve CAPTCHA
const siteKey = await page.getAttribute(".g-recaptcha", "data-sitekey");
if (siteKey) {
const token = await solveRecaptcha(siteKey, page.url());
await page.evaluate(
(t) => (document.getElementById("g-recaptcha-response").innerHTML = t),
token
);
}
// Submit
await page.click('button[type="submit"]');
await page.waitForLoadState("networkidle");
console.log("Logged in:", page.url());
await browser.close();
})();
حل Cloudflare Turnstile في Playwright
يتبع Cloudflare Turnstile النمط ذاته مع اختلافين فقط: المحدّد .cf-turnstile بدل .g-recaptcha، والمعامل method يصبح turnstile. أما حقل الاستجابة الذي تحقن فيه الرمز فهو cf-turnstile-response:
# Detect Turnstile
turnstile = page.query_selector(".cf-turnstile")
if turnstile:
site_key = turnstile.get_attribute("data-sitekey")
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY, "method": "turnstile",
"sitekey": site_key, "pageurl": page.url
})
task_id = resp.text.split("|")[1]
# Poll and inject...
بعد استلام الرمز، احقنه في الحقل المخفي كما في مثال reCAPTCHA ثم أرسل النموذج. يحلّ CaptchaAI اختبارات Turnstile من جانب الخادم ضمن الأنواع المدعومة رسمياً.
سيناريو عملي: اختبار ليلي لبوابة تسجيل الدخول
تخيّل فريق ضمان جودة في متجر إلكتروني إقليمي يشغّل مجموعة اختبارات انحدار (regression) كل ليلة على بيئة التجهيز (staging). بوابة تسجيل الدخول محمية بـ Cloudflare Turnstile، ما يجعل الاختبار الآلي متعذّراً دون حل الاختبار. بدمج CaptchaAI في سكربت Playwright، يعمل المسار كاملاً بلا تدخل بشري: يفتح السكربت الصفحة، يحلّ Turnstile، يسجّل الدخول، ثم يتحقق من ظهور لوحة التحكم.
بالنسبة لحجم كهذا — بضع جلسات متوازية ليلاً — تكفي خطة BASIC ($15 شهرياً، 5 threads)، لأن الفوترة تعتمد على عدد الـ threads المتزامنة لا على عدد عمليات الحل. وإذا توسّعت المجموعة إلى عشرات المتصفحات المتوازية ضمن خط تكامل مستمر، تنقل خطة ADVANCE ($90 شهرياً، 50 threads) السقف أعلى دون رسوم لكل عملية حل. جميع الأسعار بالدولار الأمريكي.
Playwright مقابل Selenium مقابل Puppeteer
إن كنت تختار أداة الأتمتة، فهذه مقارنة سريعة من زاوية التعامل مع CAPTCHA:
| ميزة | Playwright | Selenium | Puppeteer |
|---|---|---|---|
| اللغات | Python وNode.js وC# وJava | Python وJava وC# وRuby وJS | Node.js |
| المتصفحات | Chromium وFirefox وWebKit | Chrome وFirefox وEdge وSafari | Chromium |
| الانتظار التلقائي | ✅ مدمج | ⏳ انتظار يدوي | ⚠️ جزئي |
| اعتراض الشبكة | ✅ | ⚠️ محدود | ✅ |
| التكامل مع CaptchaAI | ✅ نفس الـ API | ✅ نفس الـ API | ✅ نفس الـ API |
يعمل CaptchaAI بالطريقة ذاتها مع الأدوات الثلاث: استخرج مفتاح الموقع، احلّه عبر الـ API، ثم احقن الرمز. الاختلاف بينها في تجربة الأتمتة نفسها، لا في طريقة التكامل مع الخدمة.
حل المشكلات الشائعة
| المشكلة | الحل |
|---|---|
page.query_selector تُعيد قيمة فارغة |
عنصر CAPTCHA يُحمّل ديناميكياً؛ انتظره عبر page.wait_for_selector() قبل قراءة data-sitekey |
| حقن الرمز لا يُحدث أثراً | تأكّد أن حقل الاستجابة يحمل المعرّف المتوقّع؛ قد يختلف اسمه بين المواقع |
| تعطّل Playwright داخل Docker | ثبّت تبعيات المتصفح عبر playwright install-deps |
| يظهر الاختبار مجدداً بعد الحل | قد يستدعي الموقع دالة رد نداء بعد الحل؛ نفّذها يدوياً عبر page.evaluate() |
الأسئلة الشائعة
هل يجب تشغيل Playwright بوضع headless أم مرئي عند استخدام CaptchaAI؟
لا فرق من ناحية CaptchaAI؛ فالحل يجري على الخادم بمعزل عن المتصفح. الوضع headless أسرع وأنسب لخوادم CI، بينما الوضع المرئي مفيد أثناء تنقيح السكربت ومتابعة الحقن بصرياً.
كم يستغرق حل reCAPTCHA أو Turnstile داخل السكربت؟
يختلف الزمن بحسب النوع والحِمل. اجعل حلقة الاستطلاع تعيد المحاولة كل خمس ثوانٍ مع مهلة كافية (60 محاولة في الأمثلة) لتغطية أبطأ الحالات دون أن يتعلّق السكربت. تجنّب تقليل الفاصل الزمني كثيراً حتى لا ترهق نقطة res.php بطلبات زائدة.
هل يحلّ CaptchaAI كل أنواع CAPTCHA التي قد يعرضها الموقع؟
يغطّي CaptchaAI اختبارات reCAPTCHA v2 وv3، وCloudflare Turnstile وChallenge، وGeeTest v3، واختبارات الصور وOCR والشبكة. أما hCaptcha وFunCaptcha فغير مدعومين حالياً، وGeeTest v4 لا يزال قيد التطوير. تحقّق من نوع الاختبار الذي يعرضه موقعك المستهدف قبل الاعتماد على المسار في الإنتاج.
هل أحتاج إلى بروكسي مع Playwright وCaptchaAI؟
ليس شرطاً. يحلّ CaptchaAI الاختبار ويعيد رمزاً صالحاً بصرف النظر عن الخادم الوسيط. لكن إذا كان الموقع المستهدف يقيّد الوصول جغرافياً أو يعتمد على سمعة عنوان IP، فقد يحسّن الوكيل السكني ثبات الجلسة العامة لسكربت Playwright.