تنبيه قانوني: هذا الدليل مخصص لاستخراج البيانات العامة فقط. احترم ملف robots.txt وشروط الخدمة وحدود المعدل لكل موقع. قد تخضع عمليات الاستخراج لقوانين مثل قانون الاحتيال وإساءة استخدام الكمبيوتر (CFAA) في الولايات المتحدة واللائحة العامة لحماية البيانات (GDPR) في الاتحاد الأوروبي عند معالجة بيانات شخصية. استخدم واجهات برمجة التطبيقات الرسمية متى توفرت.
إذا كنت تبني زاحفًا للويب في بايثون باستخدام Crawlee، فمن المرجح أنك واجهت الحجب المفاجئ، رموز CAPTCHA، أو استجابات 403 بعد عدة طلبات ناجحة فقط. المشكلة ليست في منطق الزاحف — بل في إدارة عناوين IP. تدوير البروكسي في كرولي للبايثون هو المفتاح لتحويل زاحف هش يتوقف بعد 100 طلب إلى خط أنابيب إنتاجي يتعامل مع آلاف الطلبات يوميًا بمعدل نجاح يتجاوز 95%.
في هذا الدليل، سنغوص في معمارية Crawlee، وكيفية ربط ProxyConfiguration بـ SessionPool، ولماذا تتفوق البروكسي السكنية على بروكسي مراكز البيانات أمام أنظمة مكافحة الروبوت مثل Cloudflare وDataDome، مع أمثلة كود قابلة للتشغيل مرتبطة بـ ProxyHat.
ما هو تدوير البروكسي في كرولي للبايثون ولماذا يهمك؟
تدوير البروكسي في كرولي للبايثون يعني توزيع طلبات HTTP/S عبر عناوين IP متعددة تلقائيًا، بحيث لا يصدر كل الزحف من نفس IP. يوفر Crawlee فئة ProxyConfiguration التي تدير هذه العملية عبر SessionPool، حيث يُربط كل جلسة (session) بعنوان IP محدد، أو يُدوّر الطلبات بشكل round-robin حسب الحاجة.
الأهمية عملية بحتة: المواقع الحديثة تستخدم أنظمة مكافحة الروبوت التي تراقب معدل الطلبات لكل IP. عندما يتجاوز معدلك عتبة معينة (غالبًا 50–200 طلب لكل IP في الدقيقة)، يُحظر IP فورًا. تدوير البروكسي يوزع الحمل عبر مئات أو آلاف عناوين IP، مما يبقي كل عنوان تحت الرادار.
معمارية كرولي: الطبقات والامتدادات
قبل الغوص في تفاصيل البروكسي، من المهم فهم معمارية Crawlee. وفقًا للتوثيق الرسمي لـ Crawlee، يتكون الإطار من عدة طبقات متراكبة:
المجمعات (Crawlers) وقائمة الطلبات الموحدة
يوفر Crawlee نوعين رئيسيين من المجمعات:
- BeautifulSoupCrawler: مجمع خفيف يعتمد على
httpxلجلب HTML وتحليله عبر BeautifulSoup. مثالي للمواقع الثابتة التي لا تتطلب تنفيذ JavaScript. - PlaywrightCrawler: مجمع كامل يعتمد على متصفح Chromium/Firefox headless لتنفيذ JavaScript والتعامل مع تطبيقات الصفحة الواحدة (SPA).
كلا المجمعين يعملان فوق قائمة طلبات موحدة (Unified Request Queue)، مما يعني أنك يمكن خلط الطلبات، إعادة جدولتها، وإدارة حالتها عبر جلسات متعددة. هذا مهم لأن البروكسي يُربط بالجلسة، والجلسة تتبع الطلب.
التوسع التلقائي (Autoscaling)
يحتوي Crawlee على AutoscaledPool داخلي يضبط عدد الطلبات المتزامنة بناءً على استخدام CPU والذاكرة وسرعة الاستجابة. هذا يعني أنك لا تحتاج إلى ضبط عدد العمليات يدويًا — الإطار يوسع أو يقلل التزامن تلقائيًا. عند استخدام البروكسي، يؤثر هذا مباشرة على عدد الجلسات النشطة: إذا كان AutoscaledPool يدير 50 طلبًا متزامنًا، فأنت تحتاج على الأقل 50 جلسة بروكسي نشطة.
SessionPool: ربط الكوكيز والبصمات بعناوين IP
SessionPool هو العنصر المحوري في إدارة البروكسي ضمن Crawlee. كل جلسة في Pool تحتوي على:
- عنوان IP مرتبط (عبر ProxyConfiguration)
- كوكيز (cookies) متراكمة عبر الطلبات
- بصمة متصفح (fingerprint) عند استخدام PlaywrightCrawler
- حالة (نشطة، متقاعدة، محظورة)
هذا الربط ضروري: إذا قمت بتدوير IP دون الحفاظ على الكوكيز، ستلاحظ أنظمة مكافحة الروبوت التناقض فورًا (IP جديد + كوكيز قديم = سلوك مشبوه). العكس صحيح أيضًا: IP ثابت مع كوكيز متغيرة باستمرار يثير الشكوك. SessionPool يحل هذا بربط الاثنين معًا في وحدة واحدة متماسكة.
إعداد ProxyConfiguration في كرولي للبايثون
الفئة ProxyConfiguration هي الواجهة الرسمية لإدارة البروكسي في Crawlee. يمكن تمريرها إلى أي مجمع (crawler) عبر المعامل proxy_configuration. توفر طريقتين أساسيتين:
التدوير الدائري (Round-Robin)
في هذا النمط، يُولّد Crawlee عنوان بروكسي جديد لكل طلب دون ربطه بجلسة محددة. مناسب للمواقع ذات الحماية الخفيفة:
from crawlee.proxy_configuration import ProxyConfiguration
# تدوير دائري — IP مختلف لكل طلب
proxy_config = ProxyConfiguration(
proxy_urls=[
'http://user-country-US:pass@gate.proxyhat.com:8080',
'http://user-country-DE:pass@gate.proxyhat.com:8080',
'http://user-country-GB:pass@gate.proxyhat.com:8080',
]
)
الجلسات الثابتة (Sticky Sessions)
هنا تُربط كل جلسة بـ IP محدد طوال عمر الجلسة. هذا النمط ضروري للمواقع التي تتطلب تسجيل دخول أو تحافظ على حالة عبر الطلبات:
from crawlee.proxy_configuration import ProxyConfiguration
async def new_proxy_url(session_id: str) -> str:
"""توليد عنوان بروكسي مرتبط بجلسة محددة."""
return f'http://user-country-US-session-{session_id}:pass@gate.proxyhat.com:8080'
proxy_config = ProxyConfiguration(
new_url_function=new_proxy_url
)
عندما يستدعي Crawlee proxy_configuration.new_url(session_id=...)، يمرر معرف الجلسة الحالي. الدالة تُرجع عنوان بروكسي فريد لكل جلسة، ويحتفظ SessionPool بهذا الربط طالما الجلسة نشطة.
لماذا تتفوق البروكسي السكنية على مراكز البيانات؟
عند استهداف مواقع محمية بـ Cloudflare Bot Management أو DataDome، يصبح نوع IP حاسمًا. أنظمة مكافحة الروبوت الحديثة لا تكتفي بفحص معدل الطلبات — تتحقق من سمات عنوان IP نفسه:
| السمة | بروكسي مراكز البيانات | بروكسي سكنية |
|---|---|---|
| تصنيف ASN | معروف كمزود استضافة (AWS, DigitalOcean) | مزود إنترنت منزلي حقيقي (Comcast, Vodafone) |
| معدل الحجب المتوقع | 60–90% على المواقع المحمية | 5–15% على نفس المواقع |
| السرعة (زمن الاستجابة) | 50–150ms | 200–800ms |
| التكلفة لكل GB | $0.5–$2 | $3–$15 |
| مناسبة لـ | استخراج واسع النطاق بدون حماية | مواقع محمية، تسجيل دخول، SERP |
الفرق الجوهري: عناوين مراكز البيانات تظهر في قواعد بيانات ASN كمصادر معروفة للاستضافة، بينما عناوين IP السكنية تُسجّل كمزودات إنترنت منزلية عادية. أنظمة Cloudflare وDataDome تفحص ASN لكل طلب وارد، وتطبق تحديقات أقوى على IPs المصنّفة كمركز بيانات.
البروكسي المتدرّجة (Tiered Fallback)
في الإنتاج، لا تستخدم نوعًا واحدًا من البروكسي. النمط الأمثل هو البروكسي المتدرّجة: ابدأ بالبروكسي السكنية للطلبات الحساسة، وعند الحجب، انتقل إلى بروكسي جوال (mobile) كطبقة ثانية، ثم بروكسي مركز بيانات كحل أخير للطلبات منخفضة المخاطر. يمكن تنفيذ هذا في Crawlee عبر دوال new_url_function ذكية تتبع معدل النجاح لكل نوع.
مثال عملي: BeautifulSoupCrawler مع ProxyConfiguration و ProxyHat
إليك مثالًا كاملًا قابلًا للتشغيل يوضح دمج ProxyConfiguration مع BeautifulSoupCrawler، مع توليد معرفات جلسات ديناميكية مرتبطة ببروكسي ProxyHat السكنية:
import asyncio
import hashlib
from crawlee import BeautifulSoupCrawler
from crawlee.proxy_configuration import ProxyConfiguration
from crawlee.sessions import SessionPool
PROXYHAT_GATEWAY = 'gate.proxyhat.com'
PROXYHAT_PORT = 8080
PROXYHAT_USER = 'your_username'
PROXYHAT_PASS = 'your_password'
def make_proxy_url(session_id: str, country: str = 'US') -> str:
"""توليد عنوان بروكسي ProxyHat مرتبط بجلسة ودولة محددة."""
return (
f'http://{PROXYHAT_USER}-country-{country}'
f'-session-{session_id}:{PROXYHAT_PASS}'
f'@{PROXYHAT_GATEWAY}:{PROXYHAT_PORT}'
)
async def new_url(session_id: str | None = None) -> str:
"""دالة تدوير البروكسي — جلسة ثابتة لكل session_id."""
if session_id is None:
session_id = hashlib.md5(str(asyncio.current_task()).encode()).hexdigest()[:8]
return make_proxy_url(session_id, country='US')
async def main():
proxy_config = ProxyConfiguration(new_url_function=new_url)
crawler = BeautifulSoupCrawler(
proxy_configuration=proxy_config,
request_handler_timeout=60,
max_request_retries=3,
max_session_retries=3,
use_session_pool=True,
)
@crawler.router.default_handler
async def handler(request, session, request_handler_data):
# session يحتوي على البروكسي المرتبط
response = await request_handler_data.http_client.get(
str(request.url),
proxy_url=session.proxy_url if session else None,
)
if response.status_code == 403:
# تقاعد الجلسة عند الحجب
if session:
session.retire()
raise RuntimeError(f'Blocked on {request.url}')
# معالجة HTML
soup = await request_handler_data.parse_html(response)
title = soup.find('title')
print(f'[{session.id if session else "no-session"}] {request.url} -> {title.text if title else "no title"}')
await crawler.run(['https://example.com/page-1', 'https://example.com/page-2'])
if __name__ == '__main__':
asyncio.run(main())
لاحظ النقاط الأساسية:
new_url_functionتستقبلsession_idمن Crawlee تلقائيًا وتُرجع عنوان بروكسي فريد لكل جلسة.use_session_pool=TrueيفعّلSessionPoolالذي يربط الكوكيز والبصمات بكل IP.session.retire()يُقصي الجلسة المحظورة من Pool ويولّد جلسة جديدة بـ IP جديد عند الطلب التالي.- علم
-country-US-session-abc123في اسم المستخدم يوجه ProxyHat لتخصيص IP سكني ثابت في الولايات المتحدة مرتبط بالجلسةabc123.
استخدام SOCKS5 مع PlaywrightCrawler
عند الحاجة لبروكسي SOCKS5 (مفيد لتجاوز جدران حماية معينة)، استخدم المنفذ 1080:
from crawlee import PlaywrightCrawler
from crawlee.proxy_configuration import ProxyConfiguration
async def socks5_url(session_id: str | None = None) -> str:
sid = session_id or 'default'
return (
f'socks5://{PROXYHAT_USER}-country-DE'
f'-session-{sid}:{PROXYHAT_PASS}'
f'@{PROXYHAT_GATEWAY}:1080'
)
proxy_config = ProxyConfiguration(new_url_function=socks5_url)
crawler = PlaywrightCrawler(
proxy_configuration=proxy_config,
headless=True,
browser_type='chromium',
max_request_retries=4,
)
أنماط الإنتاج: التعامل مع الحجب والأخطاء والتزامن
1. تقاعد الجلسات عند الحجب (session.retire)
عند تلقي استجابة 403 أو 429 أو صفحة CAPTCHA، يجب تقاعد الجلسة فورًا. session.retire() يزيل الجلسة من Pool دون التأثير على الطلبات الجارية — الجلسات الجديدة ستحصل على IPs جديدة تلقائيًا:
@crawler.router.default_handler
async def handler(request, session, request_handler_data):
response = await request_handler_data.http_client.get(str(request.url))
if response.status_code in (403, 429):
if session:
session.retire()
# إعادة جدولة الطلب مع جلسة جديدة
request.retry_count += 1
raise RuntimeError(f'HTTP {response.status_code} on {request.url}')
if 'cf-chl-bypass' in response.headers.get('server', ''):
# Cloudflare challenge — تقاعد الجلسة
if session:
session.retire()
raise RuntimeError('Cloudflare challenge detected')
2. ضبط max_request_retries
max_request_retries يحدد عدد مرات إعادة محاولة الطلب قبل التخلي عنه. القيمة الافتراضية 3 مناسبة لمعظم الحالات، لكن للمواقع شديدة الحماية، قد ترفعها إلى 5 أو 6. كل إعادة محاولة تستهلك جلسة جديدة (وبالتالي IP جديد)، لذا كل زيادة تعني استهلاك بروكسي إضافي.
3. التزامن عبر AutoscaledPool
يدير Crawlee التزامن تلقائيًا عبر AutoscaledPool. يمكنك ضبط الحدود عبر:
max_concurrency: الحد الأقصى للطلبات المتزامنة (افتراضي: 50).min_concurrency: الحد الأدنى (افتراضي: 1).max_cpu_usage: عتبة استخدام CPU للتوسع (افتراضي: 95%).
عند استخدام 50 طلبًا متزامنًا مع جلسات ثابتة، أنت تحتاج إلى 50 جلسة بروكسي نشطة كحد أدنى. مع ProxyHat، هذا يعني 50 معرف جلسة فريد، كل واحد مرتبط بـ IP سكني مختلف.
4. معالجة الأخطاء في request_handler
أخطاء الشبكة (مهلات، انقطاع الاتصال) تختلف عن الحجب. يجب التمييز بينهما:
import httpx
@crawler.router.default_handler
async def handler(request, session, request_handler_data):
try:
response = await request_handler_data.http_client.get(
str(request.url),
timeout=httpx.Timeout(30.0),
)
except httpx.TimeoutException:
# مهلة — لا تقاعد الجلسة، فقط أعد المحاولة
raise RuntimeError(f'Timeout on {request.url}')
except httpx.ProxyError:
# خطأ في البروكسي نفسه — تقاعد الجلسة
if session:
session.retire()
raise RuntimeError(f'Proxy error on {request.url}')
if response.status_code == 200:
# نجاح — معالجة البيانات
pass
elif response.status_code in (403, 429, 503):
if session:
session.retire()
raise RuntimeError(f'Blocked: HTTP {response.status_code}')
متى لا تستخدم زحف المتصفح؟ وأخلاقيات استخراج البيانات
متى يكفي BeautifulSoupCrawler؟
زحف المتصفح (PlaywrightCrawler) أبطأ بـ 10 إلى 20 مرة من الطلبات HTTP المباشرة (BeautifulSoupCrawler)، ويستهلك ذاكرة أكبر بكثير (200–500MB لكل مثيل Chromium مقابل 5–15MB لكل طلب httpx). استخدمه فقط عندما:
- الموقع يتطلب تنفيذ JavaScript لعرض المحتوى (React, Vue, Angular SPA).
- الموقع يستخدم تحديات JavaScript معقدة لا يمكن تجاوزها بالطلبات البسيطة.
- تحتاج إلى التفاعل مع الصفحة (نقر أزرار، ملء نماذج، تمرير).
في جميع الحالات الأخرى — بما في ذلك معظم صفحات المنتجات، مقالات الأخبار، ونتائج SERP الثابتة — يكفي BeautifulSoupCrawler وهو أسرع وأرخص بكثير.
الاعتبارات الأخلاقية والقانونية
قبل بناء أي زاحف، ضع القواعد التالية:
- تحقق من robots.txt: احترم توجيهات
DisallowوCrawl-delay. يمكن لـ Crawlee قراءة robots.txt تلقائيًا عبر إعدادات الجدولة. - احترم حدود المعدل: حتى مع 1000 IP بروكسي، لا ترسل أكثر من 1–2 طلب لكل ثانية لكل نطاق. الزحف العدواني يضر بالبنية التحتية للموقع.
- افضّل واجهات برمجة التطبيقات الرسمية: إذا كان الموقع يوفر API (حتى مدفوع)، استخدمه بدلاً من الزحف. أكثر موثوقية، أسرع، وقانوني بوضوح.
- لا تستخرج بيانات شخصية: أسماء، بريد إلكتروني، أرقام هواتف، أو أي معلومات تُعرّف أفرادًا دون موافقة. هذا قد ينتهك GDPR في الاتحاد الأوروبي.
- لا تتجاوز مصادقة الدخول: استخراج الصفحات العامة مسموح عمومًا، لكن تجاوز جدران تسجيل الدخول قد يُعتبر وصولًا غير مصرّح به بموجب CFAA.
للاطلاع على تفاصيل ProxyHat والبروكسي السكنية، راجع التوثيق الرسمي لـ ProxyHat وصفحة الأسعار. يمكنك أيضًا الاطلاع على المواقع المتاحة لمعرفة الدول المدعومة.
النقاط الرئيسية
خلاصة الدليل:
ProxyConfigurationمعnew_url_functionهو الطريقة الرسمية لإدارة البروكسي في Crawlee — استخدمsession_idللجلسات الثابتة.SessionPoolيربط الكوكيز والبصمات بـ IP — لا تفصل بينهما أبدًا.- البروكسي السكنية تتفوق على مراكز البيانات بمعدل نجاح 85–95% مقابل 10–40% على المواقع المحمية.
session.retire()عند الحجب، وليس عند أخطاء الشبكة — ميّز بين النوعين.- ابدأ بـ BeautifulSoupCrawler؛ انتقل إلى PlaywrightCrawler فقط عند الحاجة الفعلية لتنفيذ JavaScript.
- احترم
robots.txtوحدود المعدل، وافضّل واجهات برمجة التطبيقات الرسمية متى توفرت.
لمزيد من القراءة حول حالات استخدام استخراج الويب، راجع دليل استخراج الويب وتتبع نتائج محركات البحث.






