لقد قمت بإعداد برنامج جمع البيانات، وتوصيل البروكسي، ولكن لا يزال API يعيد الأخطاء 429 "طلبات كثيرة جدًا" أو يحظر الوصول؟ المشكلة ليست في البروكسي بحد ذاته، ولكن في الاستراتيجية الخاطئة لاستخدامه. تحديد المعدل هو آلية حماية لـ API، تحدد عدد الطلبات من عنوان IP واحد خلال فترة زمنية معينة. في هذه المقالة، سنحلل لماذا تحدث الحظرات عند العمل عبر البروكسي وكيفية إعداد النظام بشكل صحيح لتجاوز الحدود.
ما هو تحديد معدل API وكيف يعمل
تحديد المعدل (تحديد معدل الطلبات) هو آلية لحماية API من التحميل الزائد وسوء الاستخدام. يقوم الخدمة بتحديد حد لعدد الطلبات التي يمكن تنفيذها من مصدر واحد خلال فترة زمنية معينة. على سبيل المثال، تستخدم APIs الشهيرة مثل هذه الحدود:
- Twitter API: 300 طلبًا خلال 15 دقيقة للوصول القياسي
- Instagram Graph API: 200 طلبًا في الساعة لكل تطبيق
- Google Maps API: يعتمد على التعرفة، عادةً 100-1000 طلب في اليوم
- Wildberries API: حدود غير رسمية حوالي 60 طلبًا في الدقيقة من IP واحد
- Avito API: 10 طلبات في الثانية لجمع الإعلانات
هناك عدة طرق لتحديد مصدر الطلبات التي يتم تطبيق تحديد المعدل عليها:
عنوان IP: الطريقة الأكثر شيوعًا. يعتبر API عدد الطلبات من IP معين خلال نافذة زمنية.
مفتاح API: إذا كنت تستخدم المصادقة عبر المفتاح، يتم ربط الحد به بغض النظر عن IP.
User-Agent وبصمة الإصبع: بعض APIs تحلل رؤوس المتصفح وتخلق بصمة رقمية للعميل.
الجلسة (الكوكيز): يمكن أن يرتبط الحد بجلسة المستخدم عبر الكوكيز.
عندما يتم تجاوز الحد، يعيد API حالة HTTP 429 "طلبات كثيرة جدًا" ورأس Retry-After، الذي يشير إلى الوقت حتى يتم إعادة تعيين الحد. تستخدم بعض الخدمات "نافذة متحركة" (rolling window)، حيث يتم تحديث الحد تدريجيًا، بينما تستخدم أخرى نافذة ثابتة يتم إعادة تعيينها في وقت معين.
لماذا لا تنقذ البروكسي من تحديد المعدل تلقائيًا
يعتقد العديد من المطورين خطأً أنه يكفي توصيل البروكسي - ويمكن إرسال عدد غير محدود من الطلبات. في الممارسة العملية، تظهر مشاكل مثل:
استخدام بروكسي واحد لجميع الطلبات
إذا كان سكربتك يستخدم نفس عنوان IP للبروكسي لجميع الطلبات، فإن API ترى ذلك كمستخدم عادي وتطبق الحدود القياسية. على سبيل المثال، لقد قمت بإعداد برنامج جمع بيانات الأسعار من Wildberries عبر بروكسي سكني واحد. يقوم البرنامج بإجراء 100 طلب في الدقيقة، لكن الحد هو 60 طلبًا. النتيجة: حظر IP لمدة 10-30 دقيقة.
تدوير IP ببطء
يستخدم البعض مجموعة من 5-10 بروكسي ويتنقل بينها بشكل متتابع. المشكلة هي أن كل IP لا يزال يصل إلى الحد بشكل أسرع مما يحدث تدوير كامل. لنفترض أن لديك 10 بروكسي وحدود 100 طلب في الساعة لكل IP. إذا كنت تقوم بإجراء 1000 طلب في الساعة، سيحصل كل بروكسي على 100 طلب - بالضبط عند حدود الحد. أي عدم توازن في التوزيع سيؤدي إلى حظر.
تجاهل عوامل التعريف الأخرى
حتى مع تدوير IP المثالي، يمكن حظرك إذا:
- تأتي جميع الطلبات بنفس User-Agent (على سبيل المثال،
python-requests/2.28.0) - يتم استخدام مفتاح API واحد لجميع الطلبات
- تأتي الطلبات بتواتر مثالي (كل 0.5 ثانية) - يبدو ذلك كروبوت
- تقع عناوين IP للبروكسي في نفس الشبكة الفرعية (على سبيل المثال، جميعها في النطاق 192.168.1.x)
سمعة عناوين IP
غالبًا ما يتم إدراج بروكسي مراكز البيانات في القوائم السوداء، لأن عناوين IP الخاصة بها تستخدمها مئات المستخدمين الآخرين لجمع البيانات. يمكن أن يطبق API حدودًا أكثر صرامة على هذه العناوين أو يحظرها على الفور. على سبيل المثال، تقوم Instagram وFacebook بحظر مراكز البيانات بشكل عدواني، حتى إذا لم تتجاوز الحدود الرسمية.
استراتيجيات تدوير IP لتجاوز الحدود
يعتبر تدوير البروكسي بشكل صحيح هو المفتاح لتجاوز تحديد المعدل. دعونا نناقش استراتيجيات فعالة حسب المهمة.
تدوير بعد كل طلب
الاستراتيجية الأكثر عدوانية: كل طلب يمر عبر IP جديد. تناسب المهام ذات الحدود الصارمة جدًا (1-5 طلبات من IP) أو عندما تحتاج إلى توزيع الحمل بشكل أقصى. لهذا، يتم استخدام بروكسي سكنية مع تدوير تلقائي - حيث توفر مجموعة من ملايين IP، وكل طلب يحصل تلقائيًا على عنوان جديد.
مثال على الاستخدام: جمع بيانات Instagram عبر API غير رسمي، حيث الحد هو 5 طلبات في الدقيقة من IP واحد. مع التدوير بعد كل طلب، يمكنك إجراء 300 طلب في الدقيقة عبر 300 IP مختلف.
المزايا: حماية قصوى من تحديد المعدل، يتم استخدام كل IP بأقل حد.
العيوب: تكلفة عالية (البروكسي السكنية أغلى)، قد تحدث تأخيرات عند تغيير IP، من الصعب الحفاظ على الجلسات.
تدوير حسب الوقت (جلسات لزجة)
يتم استخدام عنوان IP لفترة زمنية معينة (5-30 دقيقة)، ثم يتم تغييره إلى جديد. تناسب هذه الاستراتيجية APIs التي تتطلب الحفاظ على الجلسة، أو عندما تحتاج إلى إجراء عدة طلبات مرتبطة من "مستخدم" واحد.
حساب الوقت الأمثل للتدوير: إذا كان حد API هو 100 طلب في الساعة، وتخطط لإجراء 50 طلبًا عبر IP واحد، استخدم جلسة لزجة لمدة 30 دقيقة. خلال هذا الوقت، ستقوم بإجراء 25 طلبًا (مع حمل متساوي)، وهو أقل بمقدار الضعف من الحد.
تدوير حسب المجموعة مع تتبع الحدود
استراتيجية متقدمة: يقوم سكربتك بتتبع عدد الطلبات من كل IP ويتحول تلقائيًا إلى جديد عندما يقترب من الحد. على سبيل المثال، لديك مجموعة من 20 بروكسي، وحد API هو 100 طلب في الساعة. يتتبع السكربت العداد لكل IP ويتحول إلى التالي عند الوصول إلى 90 طلبًا.
تتطلب هذه الاستراتيجية برمجة منطقية، لكنها توفر أقصى كفاءة: تستخدم كل بروكسي بكامل طاقته، دون تجاوز الحدود.
التدوير الجغرافي
تستخدم بعض APIs حدودًا مختلفة حسب المنطقة. على سبيل المثال، قد تقوم الخدمة بتحديد الطلبات من الولايات المتحدة بشكل أكثر صرامة من تلك القادمة من أوروبا. في هذه الحالات، استخدم بروكسي من دول مختلفة ووزع الحمل بينها.
| استراتيجية التدوير | متى تستخدم | نوع البروكسي |
|---|---|---|
| بعد كل طلب | حدود صارمة (1-10 طلبات/IP)، جمع بيانات الشبكات الاجتماعية | بروكسي سكنية مع تدوير تلقائي |
| حسب الوقت (5-30 دقيقة) | تحتاج إلى جلسة، حدود متوسطة (50-200 طلب في الساعة) | بروكسي سكنية لزجة أو موبايلية |
| حسب المجموعة مع تتبع الحدود | حجم كبير من جمع البيانات، حدود API المعروفة | أي نوع مع مجموعة من 10+ IP |
| جغرافي | قيود إقليمية، جمع بيانات محلية | بروكسي سكنية من دول مختلفة |
إعداد التأخيرات بين الطلبات
حتى مع تدوير IP المثالي، من المهم إعداد التأخيرات بين الطلبات بشكل صحيح. الطلبات السريعة جدًا تبدو كأنها هجوم، حتى لو كانت تأتي من IPs مختلفة.
حساب الحد الأدنى للتأخير
الصيغة: التأخير = (نافذة زمنية بالثواني / حد الطلبات) × معامل الأمان
مثال: يسمح API بـ 100 طلب في الساعة (3600 ثانية). الحد الأدنى للتأخير = 3600 / 100 = 36 ثانية. نضيف معامل الأمان 1.2: 36 × 1.2 = 43 ثانية بين الطلبات من IP واحد.
إذا كنت تستخدم 10 بروكسي مع تدوير، يمكنك إجراء الطلبات كل 4.3 ثانية (43 / 10)، دون تجاوز الحد في أي IP.
تأخيرات عشوائية (jitter)
بدلاً من التأخير الثابت لمدة 5 ثوانٍ، استخدم فترات عشوائية، مثل من 3 إلى 7 ثوانٍ. يجعل ذلك حركة المرور الخاصة بك تبدو كأنها تصرفات مستخدم حقيقي. العديد من أنظمة الحماية من الروبوتات تحلل الأنماط: إذا كانت الطلبات تأتي بالضبط كل 5.0 ثوانٍ، فهذا مريب.
تأخير أسي عند الأخطاء
عندما تتلقى خطأ 429، لا تستمر في إرسال الطلبات على الفور. استخدم تأخيرًا أسيًا: المحاولة الأولى بعد 1 ثانية، الثانية بعد 2، الثالثة بعد 4، الرابعة بعد 8 وهكذا. هذه ممارسة قياسية يتوقعها API من العملاء.
نصيحة: تحقق من رأس Retry-After في استجابة API. يشير إلى الوقت المحدد الذي يمكنك فيه إعادة إرسال الطلب. استخدم هذه القيمة بدلاً من التأخيرات العشوائية.
أي نوع من البروكسي يجب اختياره للعمل مع API
يؤثر اختيار نوع البروكسي بشكل حاسم على نجاح تجاوز تحديد المعدل. دعونا نحلل مزايا وعيوب كل خيار للعمل مع API.
بروكسي سكنية
البروكسي السكنية تستخدم عناوين IP لمستخدمين حقيقيين، مخصصة من قبل مزودي خدمة الإنترنت. بالنسبة لـ API، يبدو ذلك كإنترنت منزلي عادي.
المزايا لـ API:
- ثقة عالية: نادرًا ما تقوم APIs بحظر IPs المنزلية
- مجموعات ضخمة: ملايين IPs للتدوير
- تنوع جغرافي: IPs من مدن ودول مختلفة
- تناسب الشبكات الاجتماعية وAPIs الصارمة (Instagram، Facebook، TikTok)
العيوب:
- تكلفة عالية: الدفع عادةً مقابل البيانات (من 5-15 دولار لكل 1 جيجابايت)
- سرعة متغيرة: تعتمد على الإنترنت الخاص بالمستخدم النهائي
- عدم الاستقرار: يمكن أن يتوقف IP في أي لحظة
متى تستخدم: جمع بيانات Instagram، Facebook، TikTok، العمل مع APIs للأسواق (Wildberries، Ozon)، أي مهام حيث تكون سمعة IP حرجة.
بروكسي موبايلية
البروكسي الموبايلية تستخدم عناوين IP لمشغلي الهواتف المحمولة (4G/5G). غالبًا ما يستخدم IP واحد من قبل آلاف المستخدمين الحقيقيين في نفس الوقت، لذلك نادرًا ما تقوم APIs بحظرها.
المزايا لـ API:
- ثقة قصوى: لا يمكن لـ APIs حظر IPs لمشغلي الهواتف المحمولة
- مثالية للتطبيقات الموبايلية وAPIs (Instagram، TikTok، Snapchat)
- تغيير تلقائي لـ IP عند إعادة الاتصال (وضع الطائرة)
- يمكن أن يقوم IP واحد بإجراء المزيد من الطلبات دون حظر
العيوب:
- تكلفة مرتفعة جدًا: من 50-150 دولار لكل IP في الشهر
- مجموعات صغيرة: من الصعب الحصول على مئات IPs موبايلية
- سرعة متغيرة: تعتمد على جودة الاتصال المحمول
متى تستخدم: العمل مع APIs موبايلية، جمع بيانات Instagram/TikTok بكميات كبيرة، عندما تحتاج إلى أقصى حماية من الحظر.
بروكسي مراكز البيانات
بروكسي مراكز البيانات هي عناوين IP للخوادم الموجودة في مراكز البيانات. لا ترتبط بمستخدمين حقيقيين.
المزايا لـ API:
- تكلفة منخفضة: من 1-5 دولارات لكل IP في الشهر
- سرعة عالية: قنوات 1-10 جيجابت/ثانية
- استقرار: لا تتوقف IPs بشكل عشوائي
- مجموعات كبيرة: من السهل الحصول على مئات IPs
العيوب:
- ثقة منخفضة: العديد من APIs تحظر مراكز البيانات
- غالبًا ما تكون IPs في القوائم السوداء بسبب مستخدمين آخرين
- لا تناسب الشبكات الاجتماعية والخدمات الصارمة
متى تستخدم: جمع بيانات APIs العامة بدون حماية صارمة (الطقس، أسعار العملات، الأخبار)، العمل مع APIs الخاصة بك، الاختبار والتطوير.
| المعيار | سكنية | موبايلية | مراكز البيانات |
|---|---|---|---|
| ثقة API | عالية | قصوى | منخفضة |
| حجم المجموعة | ملايين IPs | مئات IPs | آلاف IPs |
| سرعة | متوسطة (10-50 ميغابت/ثانية) | متوسطة (5-100 ميغابت/ثانية) | عالية (100+ ميغابت/ثانية) |
| التكلفة | 5-15 دولار/جيجابايت | 50-150 دولار/IP/شهر | 1-5 دولار/IP/شهر |
| للشبكات الاجتماعية | ✅ ممتاز | ✅ مثالي | ❌ غير مناسبة |
| لـ APIs العامة | ✅ جيد | ✅ جيد (باهظ) | ✅ ممتاز |
التنفيذ العملي: أمثلة على الشيفرة بلغة بايثون
دعونا نناقش أمثلة محددة لتنفيذ تجاوز تحديد المعدل باستخدام البروكسي. جميع الأمثلة بلغة بايثون مع مكتبة requests.
تدوير بسيط من مجموعة البروكسي
تنفيذ أساسي مع تدوير دوري لـ IP من القائمة:
import requests
import time
from itertools import cycle
# قائمة البروكسي (التنسيق: protocol://user:pass@host:port)
PROXY_LIST = [
'http://user1:pass1@proxy1.example.com:8080',
'http://user2:pass2@proxy2.example.com:8080',
'http://user3:pass3@proxy3.example.com:8080',
]
# إنشاء مكرر دوري
proxy_pool = cycle(PROXY_LIST)
def make_request(url):
proxy = next(proxy_pool) # أخذ البروكسي التالي من المجموعة
proxies = {
'http': proxy,
'https': proxy
}
try:
response = requests.get(url, proxies=proxies, timeout=10)
return response
except requests.exceptions.RequestException as e:
print(f"خطأ مع البروكسي {proxy}: {e}")
return None
# مثال على الاستخدام
for i in range(10):
response = make_request('https://api.example.com/data')
if response and response.status_code == 200:
print(f"الطلب {i+1}: نجاح")
time.sleep(2) # تأخير بين الطلبات
تدوير مع تتبع الحدود
نسخة أكثر تقدمًا، تحسب الطلبات لكل بروكسي وتتحول عند الاقتراب من الحد:
import requests
import time
from collections import defaultdict
class ProxyRotator:
def __init__(self, proxy_list, max_requests_per_ip=90, time_window=3600):
self.proxy_list = proxy_list
self.max_requests = max_requests_per_ip # حد الطلبات لكل IP
self.time_window = time_window # نافذة زمنية بالثواني
self.request_counts = defaultdict(list) # تاريخ الطلبات لكل IP
self.current_index = 0
def get_proxy(self):
"""ترجع البروكسي مع أقل عدد من الطلبات"""
current_time = time.time()
# تنظيف السجلات القديمة خارج نافذة الوقت
for proxy in self.request_counts:
self.request_counts[proxy] = [
t for t in self.request_counts[proxy]
if current_time - t < self.time_window
]
# البحث عن البروكسي مع أقل عدد من الطلبات
available_proxies = []
for proxy in self.proxy_list:
count = len(self.request_counts[proxy])
if count < self.max_requests:
available_proxies.append((proxy, count))
if not available_proxies:
# إذا كانت جميع البروكسي قد استنفدت الحد، انتظر
oldest_request = min(
min(times) for times in self.request_counts.values() if times
)
wait_time = self.time_window - (current_time - oldest_request) + 1
print(f"جميع البروكسي استنفدت الحد. انتظار {wait_time:.0f} ثوانٍ...")
time.sleep(wait_time)
return self.get_proxy()
# اختيار البروكسي مع أقل عدد من الطلبات
proxy = min(available_proxies, key=lambda x: x[1])[0]
self.request_counts[proxy].append(current_time)
return proxy
def make_request(self, url, **kwargs):
proxy = self.get_proxy()
proxies = {'http': proxy, 'https': proxy}
try:
response = requests.get(url, proxies=proxies, timeout=10, **kwargs)
return response
except requests.exceptions.RequestException as e:
print(f"خطأ مع البروكسي {proxy}: {e}")
return None
# مثال على الاستخدام
PROXY_LIST = [
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
]
rotator = ProxyRotator(PROXY_LIST, max_requests_per_ip=100, time_window=3600)
for i in range(500): # إجراء 500 طلب
response = rotator.make_request('https://api.example.com/data')
if response and response.status_code == 200:
print(f"الطلب {i+1}: نجاح")
time.sleep(1) # الحد الأدنى من التأخير
معالجة الأخطاء 429 مع تأخير أسي
معالجة صحيحة للاستجابة "طلبات كثيرة جدًا" مع الأخذ في الاعتبار رأس Retry-After:
import requests
import time
def make_request_with_retry(url, proxies, max_retries=5):
"""يجري الطلب مع تكرارات تلقائية عند خطأ 429"""
for attempt in range(max_retries):
try:
response = requests.get(url, proxies=proxies, timeout=10)
if response.status_code == 200:
return response
elif response.status_code == 429:
# تحقق من رأس Retry-After
retry_after = response.headers.get('Retry-After')
if retry_after:
wait_time = int(retry_after)
print(f"تحديد المعدل. انتظار {wait_time} ثوانٍ (من Retry-After)")
else:
# تأخير أسي: 2^attempt ثوانٍ
wait_time = 2 ** attempt
print(f"تحديد المعدل. محاولة {attempt+1}, انتظار {wait_time} ثوانٍ")
time.sleep(wait_time)
continue
else:
print(f"خطأ HTTP {response.status_code}")
return None
except requests.exceptions.RequestException as e:
print(f"خطأ في الاتصال: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
continue
return None
print(f"تجاوز عدد المحاولات ({max_retries})")
return None
# مثال على الاستخدام
proxies = {
'http': 'http://user:pass@proxy.example.com:8080',
'https': 'http://user:pass@proxy.example.com:8080'
}
response = make_request_with_retry('https://api.example.com/data', proxies)
if response:
print("تم الحصول على البيانات:", response.json())
استخدام البروكسي السكنية مع تدوير تلقائي
العديد من مزودي البروكسي السكنية يقدمون نقطة نهاية واحدة، تقوم تلقائيًا بتغيير IP مع كل طلب. مثال على الإعداد:
import requests
import random
import time
# بروكسي سكنية مع تدوير تلقائي
# التنسيق: protocol://username:password@gateway:port
ROTATING_PROXY = 'http://customer-USER:PASS@proxy.provider.com:12321'
def make_request_rotating(url):
"""طلب عبر بروكسي متغير (IP جديد في كل مرة)"""
proxies = {
'http': ROTATING_PROXY,
'https': ROTATING_PROXY
}
# إضافة User-Agent عشوائي لمزيد من الخصوصية
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
]
headers = {
'User-Agent': random.choice(user_agents)
}
try:
response = requests.get(url, proxies=proxies, headers=headers, timeout=15)
return response
except requests.exceptions.RequestException as e:
print(f"خطأ: {e}")
return None
# إجراء 100 طلب عبر IPs مختلفة
for i in range(100):
response = make_request_rotating('https://api.example.com/data')
if response and response.status_code == 200:
print(f"الطلب {i+1}: نجاح، تم تغيير IP")
# تأخير عشوائي من 1 إلى 3 ثوانٍ
time.sleep(random.uniform(1, 3))
مراقبة الحدود ومعالجة الأخطاء
تتطلب العمل الفعال مع API مراقبة مستمرة للحدود ومعالجة الأخطاء بشكل صحيح. إليك الممارسات الأساسية:
تحليل رؤوس الاستجابة
تعيد العديد من APIs معلومات حول الحدود في رؤوس الاستجابة. الرؤوس القياسية:
X-RateLimit-Limit— الحد الأقصى لعدد الطلبات في النافذةX-RateLimit-Remaining— عدد الطلبات المتبقيةX-RateLimit-Reset— وقت إعادة تعيين الحد (طابع زمني Unix)Retry-After— بعد كم من الثواني يمكن إعادة إرسال الطلب
مثال على قراءة هذه الرؤوس:
response = requests.get(url, proxies=proxies)
# تحقق من رؤوس الحدود
limit = response.headers.get('X-RateLimit-Limit')
remaining = response.headers.get('X-RateLimit-Remaining')
reset_time = response.headers.get('X-RateLimit-Reset')
if remaining:
remaining = int(remaining)
if remaining < 10:
print(f"تحذير! تبقى فقط {remaining} طلبات")
if reset_time:
import datetime
reset_dt = datetime.datetime.fromtimestamp(int(reset_time))
print(f"سيتم إعادة تعيين الحد في {reset_dt}")
تسجيل الأخطاء والإحصائيات
احتفظ بإحصائيات مفصلة عن الطلبات لكل بروكسي. سيساعد ذلك في تحديد IPs المشكلة وتحسين التدوير:
import json
from datetime import datetime
class RequestLogger:
def __init__(self):
self.stats = {}
def log_request(self, proxy, status_code, response_time):
if proxy not in self.stats:
self.stats[proxy] = {
'total': 0,
'success': 0,
'rate_limited': 0,
'errors': 0,
'avg_response_time': 0
}
self.stats[proxy]['total'] += 1
if status_code == 200:
self.stats[proxy]['success'] += 1
elif status_code == 429:
self.stats[proxy]['rate_limited'] += 1
else:
self.stats[proxy]['errors'] += 1
# تحديث متوسط وقت الاستجابة
current_avg = self.stats[proxy]['avg_response_time']
total = self.stats[proxy]['total']
self.stats[proxy]['avg_response_time'] = (
(current_avg * (total - 1) + response_time) / total
)
def print_stats(self):
print("\n=== إحصائيات البروكسي ===")
for proxy, data in self.stats.items():
success_rate = (data['success'] / data['total'] * 100) if data['total'] > 0 else 0
print(f"\nالبروكسي: {proxy}")
print(f" إجمالي الطلبات: {data['total']}")
print(f" الناجحة: {data['success']} ({success_rate:.1f}%)")
print(f" تحديد المعدل: {data['rate_limited']}")
print(f" الأخطاء: {data['errors']}")
print(f" متوسط وقت الاستجابة: {data['avg_response_time']:.2f} ثوانٍ")
# الاستخدام
logger = RequestLogger()
start_time = time.time()
response = requests.get(url, proxies=proxies)
response_time = time.time() - start_time
logger.log_request(proxy, response.status_code, response_time)
logger.print_stats()
تبديل الاستراتيجية تلقائيًا
إذا كنت تتلقى باستمرار أخطاء 429، قم بتقليل سرعة الطلبات تلقائيًا أو زيادة مجموعة البروكسي:
class AdaptiveRateLimiter:
def __init__(self, initial_delay=1.0):
self.delay = initial_delay
self.consecutive_429 = 0
def on_success(self):
"""طلب ناجح - يمكن تسريع العملية قليلاً"""
self.consecutive_429 = 0
self.delay = max(0.5, self.delay * 0.95) # تقليل التأخير بنسبة 5%
def on_rate_limit(self):
"""تلقينا 429 - يجب أن نتباطأ"""
self.consecutive_429 += 1
self.delay *= 1.5 # زيادة التأخير بمقدار 1.5
if self.consecutive_429 > 5:
print("تحذير: عدد كبير جدًا من الأخطاء 429. تحقق من الإعدادات!")
def wait(self):
"""انتظار قبل الطلب التالي"""
time.sleep(self.delay)
return self.delay
# الاستخدام
limiter = AdaptiveRateLimiter(initial_delay=2.0)
for i in range(1000):
response = make_request(url)
if response.status_code == 200:
limiter.on_success()
elif response.status_code == 429:
limiter.on_rate_limit()
delay = limiter.wait()
print(f"الطلب {i+1}, التأخير: {delay:.2f} ثوانٍ")
معالجة CAPTCHA وغيرها من الحظرات
بعض APIs عند تجاوز الحدود تظهر CAPTCHA بدلاً من الحظر المباشر. العلامات:
- رمز الحالة 403 مع جسم الاستجابة يحتوي على "captcha" أو "recaptcha"
- إعادة توجيه إلى صفحة CAPTCHA (رمز الحالة 302)
- رؤوس خاصة مثل
X-Captcha-Required: true
في هذه الحالات، يجب عليك:
- إيقاف استخدام هذا IP على الفور
- التحول إلى بروكسي آخر من المجموعة
- زيادة التأخيرات بين الطلبات
- إضافة المزيد من التنوع في User-Agent ورؤوس أخرى
مهم: إذا كنت تواجه CAPTCHA بشكل متكرر عند استخدام البروكسي السكنية، فالمشكلة على الأرجح في أنماط السلوك (رؤوس متشابهة، طلبات سريعة جدًا)، وليس في عناوين IP.
الخاتمة
تجاوز تحديد معدل API عند استخدام البروكسي ليس مجرد إعداد تقني، بل هو استراتيجية شاملة تشمل الاختيار الصحيح لنوع البروكسي، إعداد تدوير IP، إدارة التأخيرات ومراقبة الحدود. الاستنتاجات الرئيسية من المقالة:
- البروكسي بحد ذاتها لا تحل مشكلة تحديد المعدل - تحتاج إلى استراتيجية تدوير صحيحة
- لشبكات الاجتماعية وAPIs الصارمة، استخدم البروكسي السكنية أو الموبايلية، ولـ APIs العامة، تناسب مراكز البيانات
- احسب حجم مجموعة البروكسي بناءً على حدود API وسرعة جمع البيانات المرغوبة
- دائمًا تحقق من رؤوس الاستجابة واحتفظ بإحصائيات دقيقة لتحسين الأداء.