تنبيه قانوني: هذا الدليل موجّه لجمع البيانات العامة المصرّح بها فقط. قد يخضع الكشط غير المصرّح به لقوانين مثل CFAA في الولايات المتحدة وGDPR في الاتحاد الأوروبي. راجع شروط استخدام الموقع المستهدف واستشر مختصاً قانونياً عند الحاجة.
إذا كنت من مهندسي بايثون الذين اعتمدوا على undetected-chromedriver لسنوات، فربما لاحظت أنه يفقد فعاليته تدريجياً أمام أنظمة مثل Cloudflare Turnstile وImperva Incapsula. السبب الجوهري هو أن Selenium WebDriver يترك بصمات بروتوكول واضحة — رأس webdriver في navigator، اتصالات CDP مكشوفة، ومسارات عملية قابلة للكشف. هنا يأتي دور الكشط باستخدام nodriver: مكتبة بايثون غير المتزامنة بالكامل من نفس مطوّر undetected-chromedriver، تعمل مباشرة فوق Chrome DevTools Protocol عبر websockets دون أي طبقة WebDriver.
ما هو الكشط باستخدام nodriver ولماذا يهمك
nodriver هو خليفة undetected-chromedriver كما يوضّحه المستودع الرسمي. بدلاً من توريد Selenium وإجراء تعديلات سطحية على ملفات Chrome، يتصل nodriver مباشرة بـ CDP عبر websocket ثنائي الاتجاه. هذا يعني أن المتصفح الذي تتحكم به لا يملك كائن driver ولا يطابق بصمة WebDriver الكلاسيكية التي تبحث عنها معظم أنظمة مكافحة البوت.
لماذا يهم مستخدمي البروكسي؟ لأن الأنظمة المتقدمة لا تكتشف الـ IP فقط بل تربطه بسلوك المتصفح. إذا كان الـ IP سكنياً موثوقاً لكن المتصفح يكشف عن navigator.webdriver === true، فسيُحجب الطلب. العكس صحيح أيضاً: متصفح نظيف خلف IP مركز بيانات يفشل بنفس القدر. التكامل بين nodriver undetected وبروكسي سكني هو ما يحقق نسب نجاح تتجاوز 95% في صفحات محمية بشدة، مقارنة بـ 40–60% مع WebDriver التقليدي خلف نفس البروكسي.
معمارية nodriver: لماذا تتجاوز Selenium
لفهم قوة nodriver، يجب فهم ما يزيله:
- لا Selenium ولا WebDriver: لا توجد عملية chromedriver وسيطة، ولا طلبات HTTP JSON Wire Protocol. كل اتصال يمر عبر Chrome DevTools Protocol مباشرة.
- إزالة
navigator.webdriver:nodriverيحقن سكربتات قبل تحميل أي صفحة لتفريغ هذه الخاصية وتعديل بصمات أخرى مثلchrome.runtimeوpermissions.query. - إخفاء تسريبات CDP: المتصفحات التي تُدار عبر CDP تظهر علامات مثل
window.cdc_أو منافذ تصحيح مكشوفة.nodriverيعالج هذه التسريبات على مستوى الإطلاق. - أداء غير متزامن: لأن كل شيء مكتوب بـ
asyncio، يمكنك تشغيل عشرات التبويبات المتزامنة في عملية واحدة دون خيوط عائقية.
النتيجة: بصمة متصفح أقرب إلى مستخدم حقيقي، وزمن استجابة أقل لأنك تحذف طبقة وسيطة كاملة. في اختبارات عملية، يقلل nodriver زمن الإقلاع بنحو 300–500ms مقارنة بـ undetected-chromedriver لأنه لا ينتظر تهيئة chromedriver.
الواجهة البرمجية الأساسية لـ nodriver async
واجهة nodriver مختلفة جذرياً عن Selenium. لا توجد driver.get() أو WebDriverWait. بدلاً من ذلك، تعمل مع كائنات Browser وTab وتستخدم await في كل مكان.
import nodriver as uc
import asyncio
async def main():
browser = await uc.start(headless=False)
tab = await browser.get("https://example.com")
# انتظر ظهور عنصر بدلاً من WebDriverWait
element = await tab.select("h1", timeout=10)
print(await element.get_attribute("textContent"))
browser.stop()
if __name__ == "__main__":
asyncio.run(main())
النقاط الأساسية:
uc.start()تُرجع كائنBrowser— هذا هو نقطة الدخول الوحيدة.browser.get(url)تفتح تبويباً جديداً وتُرجع كائنTab.tab.select(selector, timeout=)تحل محلWebDriverWait + expected_conditions— تنتظر حتى يظهر العنصر أو تنتهي المهلة.tab.find()تبحث دون انتظار، مفيدة للعناصر الموجودة مسبقاً.- خطافات الأحداث: بدلاً من الاستطلاع الدوري، يمكنك تسجيل معالجات لأحداث CDP مثل
Network.responseReceived.
async def on_response(event):
if event.response.mimeType == "application/json":
body = await event.response.body
print(f"JSON caught: {body[:200]}")
tab.add_handler(ur.event.Network.ResponseReceived, on_response)
await tab.get("https://api.example.com/data")
هذا النمط غير المتزامن هو جوهر nodriver async: لا حظر، لا استطلاع، استجابة فورية للأحداث.
إعداد بروكسي nodriver مع ProxyHat
nodriver لا يملك نظام تدوير بروكسي مدمج — وهذا متعمد. المكتبة تركز على التحكم بالمتصفح، أما توزيع الطلبات فيقع على عاتق البنية التحتية الخارجية. الطريقة الموصى بها هي تمرير --proxy-server= عبر browser_args عند الإقلاع.
لأن Chrome لا يدعم مصادقة البروكسي عبر سطر الأوامر، نستخدم إضافة صغيرة أو — وهو الأنظف — نعتمد على بروكسي بوابة تتعامل مع المصادقة في طبقة URL. مع ProxyHat، تُمرّر بيانات الاعتماد داخل اسم المستخدم نفسه.
import nodriver as uc
import urllib.parse
PROXY_HOST = "gate.proxyhat.com"
PROXY_PORT = 8080
PROXY_USER = "user-country-US-session-abc123"
PROXY_PASS = "pass"
# nodriver يقبل --proxy-server فقط (بدون مصادقة في CLI)
# لذا نبني بروكسي محلي بسيط أو نستخدم إضافة مصادقة
proxy_arg = f"--proxy-server=http://{PROXY_HOST}:{PROXY_PORT}"
browser = await uc.start(
headless=False,
browser_args=[proxy_arg],
)
لحل مشكلة المصادقة بشكل أنيق، استخدم بروكسي محلي وسيط (local proxy bridge) يضيف رأس Proxy-Authorization تلقائياً، أو اعتمد على إضافة Chrome مصغّرة. البوابة في gate.proxyhat.com:8080 تدعم HTTP، ومنفذ 1080 يدعم SOCKS5 عندما تحتاج طبقة نقل أعمق.
لماذا البروكسي السكني ضروري للوضع الخفي (stealth)؟ لأن Cloudflare يصنّف نطاقات IP حسب ASN. عناوين مراكز البيانات (مثل AWS أو OVH) تحصل على درجة مخاطرة عالية فوراً، حتى لو كان المتصفح نظيفاً تماماً. البروكسي السكني يربط طلبك بـ ASN مزود إنترنت حقيقي، مما يخفض احتمالية تحدي CAPTCHA بشكل كبير. اطلّع على مواقع ProxyHat لاختيار الدول والمدن المناسبة.
مثال عملي قابل للتشغيل: الكشط من صفحة محمية
سنطلق nodriver عبر نقطة نهاية سكنية أمريكية بجلسة ثابتة، نتنقّل لصفحة محمية، ونلتقط استجابة JSON من الشبكة.
import nodriver as uc
import nodriver.cdp.network as network
import asyncio
import json
PROXY_HOST = "gate.proxyhat.com"
PROXY_PORT = 8080
# علم الجلسة الثابتة في اسم المستخدم
PROXY_USER = "user-country-US-session-abc123"
PROXY_PASS = "pass"
async def scrape_protected():
proxy_arg = f"--proxy-server=http://{PROXY_HOST}:{PROXY_PORT}"
browser = await uc.start(
headless=False,
browser_args=[
proxy_arg,
"--disable-blink-features=AutomationControlled",
],
)
tab = await browser.get("https://protected-target.example")
captured = []
async def on_response(event):
try:
if event.response.url.endswith("/api/products"):
body = await tab.send(
network.GetResponseBody(event.request_id)
)
captured.append(json.loads(body))
except Exception:
pass
tab.add_handler(
uc.cdp.network.ResponseReceived,
on_response,
)
# تفاعل لتفعيل طلب XHR
button = await tab.select("#load-more", timeout=15)
await button.click()
await tab.wait_for("#results-loaded", timeout=20)
print(f"Captured {len(captured)} JSON payloads")
browser.stop()
if __name__ == "__main__":
asyncio.run(scrape_protected())
النقطة المهمة هنا: session-abc123 تضمن بقاء نفس الـ IP طوال الجلسة. هذا حيوي لأن تبديل الـ IP في منتصف التفاعل (مثلاً بعد تسجيل الدخول) يُعتبر سلوكاً مشبوهاً ويؤدي إلى حظر فوري. عند الحاجة إلى IP جديد، غيّر قيمة الجلسة وأعد الإقلاع.
لمزيد من أنماط الكشط المتقدمة، راجع دليل استخدامات الكشط وتتبّع نتائج البحث.
التوسع: أسطول متزامن في Docker
عندما تحتاج إلى مئات الطلبات المتوازية، يصبح تشغيل متصفح واحد غير كافٍ. نمط التوسع الموصى به مع nodriver هو: حاوية لكل عامل، كل عامل يدير عدة تبويبات، وكل تبويب يملك جلسة بروكسي مستقلة.
التزامن داخل عملية واحدة
import nodriver as uc
import asyncio
SESSIONS = [
"user-country-US-session-s1",
"user-country-DE-session-s2",
"user-country-GB-session-s3",
]
PROXY_PASS = "pass"
async def worker(session_user):
proxy_arg = f"--proxy-server=http://gate.proxyhat.com:8080"
browser = await uc.start(
headless=True,
browser_args=[proxy_arg, "--no-sandbox"],
)
tab = await browser.get("https://target.example")
title = await tab.evaluate("document.title")
print(f"{session_user}: {title}")
browser.stop()
async def main():
await asyncio.gather(*[worker(s) for s in SESSIONS])
asyncio.run(main())
حاويات Docker
للتوسع الأفقي، شغّل حاويات متعددة من صورة Chrome headless. كل حاوية تدير عملية بايثون مستقلة بتبويباتها الخاصة. استخدم مدير حاويات مثل Docker Compose أو Kubernetes لتوزيع الحمل.
FROM python:3.12-slim
RUN apt-get update && apt-get install -y chromium
RUN pip install nodriver
COPY scraper.py /app/scraper.py
WORKDIR /app
CMD ["python", "scraper.py"]
أفضل الممارسات:
- حدّ التزامن لكل حاوية: 3–5 تبويبات كحد أقصى لتجنّب استهلاك الذاكرة. كل تبويب يستهلك نحو 150–250MB.
- إيقاف سلس: استخدم
browser.stop()دائماً داخلfinallyلمنع تسرب عمليات Chrome. - تخصيص بروكسي لكل سياق: مرّر
--proxy-serverمختلف لكل عامل لتوزيع الجغرافيا. - مراقبة: تتبّع معدل النجاح وزمن الاستجابة لكل جلسة وبدّل الجلسات الراكدة.
راجع وثائق ProxyHat لتفاصيل حدود التزامن وعدد الجلسات لكل خطة، وصفحة الأسعار لاختيار الخطة المناسبة لحجم أسطولك.
متى لا تستخدم متصفحاً كاملاً
رغم قوة nodriver، ليس كل مهمة كشط تستحق متصفحاً كاملاً. المتصفح الخفي يستهلك ذاكرة ووحدة معالجة كبيرة، ويبطئ الإنتاجية مقارنة بالطلبات HTTP المباشرة.
| المعيار | nodriver + بروكسي سكني | curl_cffi + بروكسي سكني |
|---|---|---|
| استهلاك الذاكرة لكل مهمة | 150–250MB | ~20MB |
| الطلبات في الثانية (عقدة واحدة) | 5–15 | 200–500 |
| تجاوز Cloudflare JS Challenge | نعم (تنفيذ JS كامل) | جزئي (TLS fingerprint فقط) |
| تكلفة البنية التحتية | مرتفعة (حاويات Chrome) | منخفضة جداً |
| مناسب لـ | صفحات SPA محمية بشدة | APIs وصفحات HTML ثابتة |
القاعدة العملية: ابدأ بـ curl_cffi أو httpx مع بروكسي سكني. إذا واجهت تحدي JS لا يمكن حله بـ TLS fingerprint، انتقل إلى nodriver. لا تستخدم متصفحاً كاملاً لجلب HTML ثابت من موقع غير محمي — هذا إهدار للموارد.
أخطاء شائعة وحالات حدّية
- نسيان
browser.stop(): يؤدي إلى تراكم عمليات Chrome zombie. استخدم دائماًtry/finallyأو مدير سياق. - تغيير الـ IP في منتصف الجلسة: بعد تسجيل الدخول، أي تبديل IP يُسجّل كجلسة مشبوهة. ثبّت
session-*طوال التفاعل. - استخدام headless بدون تعديلات: وضع headless النقي يكشف عن بصمات.
nodriverيخفّي بعضها، لكن أضف--disable-blink-features=AutomationControlledدائماً. - تجاهل
robots.txt: حتى مع متصفح غير مكشوف، احترامrobots.txtوحدود المعدل مسألة أخلاقية وقانونية. - عدم التعامل مع CAPTCHA: حتى مع
nodriver+ بروكسي سكني، قد تظهر تحديات CAPTCHA. خطّط لخدمة حلّ CAPTCHA أو إعادة المحاولة بجلسة جديدة.
نقاط رئيسية
الخلاصة:
nodriverيلغي WebDriver ويتصل بـ CDP مباشرة، فيزيلnavigator.webdriverوتسريبات CDP.- الواجهة غير متزامنة بالكامل:
uc.start()،tab.select()، وخطافات الأحداث بدلاً منWebDriverWait.- البروكسي يُمرّر عبر
--proxy-server=gate.proxyhat.com:8080مع جلسات ثابتة في اسم المستخدم.- البروكسي السكني ضروري لأن أنظمة مكافحة البوت تصنّف ASN قبل فحص المتصفح.
- للتوسع: حاوية لكل عامل، 3–5 تبويبات لكل حاوية، إيقاف سلس دائماً.
- لا تستخدم متصفحاً كاملاً عندما يكفي
curl_cffi— وفّر الموارد.
الجمع بين nodriver وبروكسي سكني من ProxyHat يمنحك أفضل ما في العالمين: بصمة متصفح نظيفة وIP موثوق. ابدأ بتجربة مجانية على صفحة الأسعار وادمج نقطة النهاية gate.proxyhat.com:8080 في سكربت nodriver التالي لديك.






