بازگشت به وبلاگ

چگونه محدودیت نرخ API را هنگام پارس کردن از طریق پروکسی دور بزنیم: تنظیم چرخش و انتخاب IP

دلایل مسدود شدن API هنگام استفاده از پروکسی را بررسی کرده و روش‌های خاصی برای دور زدن محدودیت نرخ را نشان می‌دهیم: از تنظیم چرخش IP تا انتخاب نوع مناسب پروکسی.

📅۳۰ بهمن ۱۴۰۴
```html

شما پارسر را تنظیم کرده‌اید، پروکسی را متصل کرده‌اید، اما API هنوز هم خطاهای 429 "بیش از حد درخواست" را برمی‌گرداند یا دسترسی را مسدود می‌کند؟ مشکل در خود پروکسی‌ها نیست، بلکه در استراتژی نادرست استفاده از آن‌هاست. محدودیت نرخ — یک مکانیزم حفاظتی API است که تعداد درخواست‌ها را از یک آدرس IP در یک دوره معین محدود می‌کند. در این مقاله بررسی می‌کنیم که چرا مسدودیت‌ها هنگام کار از طریق پروکسی ایجاد می‌شود و چگونه سیستم را به درستی برای دور زدن محدودیت‌ها تنظیم کنیم.

محدودیت نرخ API چیست و چگونه کار می‌کند

محدودیت نرخ (Rate limiting) — یک مکانیزم حفاظتی برای API است که از بارگذاری بیش از حد و سوء استفاده جلوگیری می‌کند. سرویس یک محدودیت برای تعداد درخواست‌هایی که می‌توان از یک منبع در یک بازه زمانی معین انجام داد، تعیین می‌کند. به عنوان مثال، API‌های محبوب از چنین محدودیت‌هایی استفاده می‌کنند:

  • 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 و fingerprint: برخی API‌ها هدرهای مرورگر را تجزیه و تحلیل کرده و یک اثر انگشت دیجیتال برای مشتری ایجاد می‌کنند.

نشست (کوکی‌ها): محدودیت ممکن است به نشست کاربر از طریق کوکی‌ها وابسته باشد.

وقتی محدودیت تجاوز می‌شود، 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 دقیقه) استفاده می‌شود، سپس به یک آدرس جدید تغییر می‌کند. این استراتژی برای API‌هایی که نیاز به حفظ نشست دارند، یا زمانی که باید چندین درخواست مرتبط از یک "کاربر" انجام شود، مناسب است.

محاسبه زمان بهینه چرخش: اگر محدودیت API 100 درخواست در ساعت باشد و شما قصد دارید 50 درخواست از یک IP انجام دهید، از نشست چسبنده به مدت 30 دقیقه استفاده کنید. در این مدت شما 25 درخواست انجام می‌دهید (با بار یکنواخت)، که دو برابر کمتر از محدودیت است.

چرخش بر اساس استخر با نظارت بر محدودیت‌ها

استراتژی پیشرفته: اسکریپت شما تعداد درخواست‌ها را از هر IP پیگیری می‌کند و به طور خودکار به IP جدیدی جابجا می‌شود، زمانی که به محدودیت نزدیک می‌شود. به عنوان مثال، شما یک استخر از 20 پروکسی دارید، محدودیت API 100 درخواست در ساعت است. اسکریپت شمارنده را برای هر IP پیگیری می‌کند و به IP بعدی جابجا می‌شود زمانی که به 90 درخواست برسد.

این استراتژی نیاز به برنامه‌نویسی منطق دارد، اما حداکثر کارایی را فراهم می‌کند: شما از هر پروکسی به طور کامل استفاده می‌کنید، بدون اینکه از محدودیت‌ها تجاوز کنید.

چرخش جغرافیایی

برخی API‌ها محدودیت‌های متفاوتی را بسته به منطقه اعمال می‌کنند. به عنوان مثال، سرویس ممکن است درخواست‌ها را از ایالات متحده سخت‌تر از اروپا محدود کند. در چنین مواردی از پروکسی‌های کشورهای مختلف استفاده کنید و بار را بین آن‌ها توزیع کنید.

استراتژی چرخش کی استفاده کنیم نوع پروکسی
پس از هر درخواست محدودیت‌های سخت (1-10 درخواست/IP)، پارسینگ شبکه‌های اجتماعی پروکسی‌های مقیم با چرخش خودکار
بر اساس زمان (5-30 دقیقه) نیاز به نشست، محدودیت‌های متوسط (50-200 درخواست/ساعت) پروکسی‌های مقیم چسبنده یا موبایل
بر اساس استخر با نظارت بر محدودیت‌ها حجم بالای پارسینگ، محدودیت‌های شناخته شده API هر نوع با استخر 10+ IP
جغرافیایی محدودیت‌های منطقه‌ای، پارسینگ محتوای محلی پروکسی‌های مقیم از کشورهای مختلف

تنظیم تأخیرها بین درخواست‌ها

حتی با چرخش ایده‌آل IP، مهم است که تأخیرها بین درخواست‌ها به درستی تنظیم شوند. درخواست‌های بسیار سریع به عنوان حمله به نظر می‌رسند، حتی اگر از IP‌های مختلف باشند.

محاسبه حداقل تأخیر

فرمول: تأخیر = (پنجره زمانی به ثانیه / محدودیت درخواست‌ها) × ضریب ایمنی

مثال: 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:

  • اعتماد بالا: API به ندرت IP‌های خانگی را مسدود می‌کند
  • استخرهای بزرگ: میلیون‌ها IP برای چرخش
  • تنوع جغرافیایی: IP از شهرها و کشورهای مختلف
  • مناسب برای شبکه‌های اجتماعی و API‌های سخت (Instagram، Facebook، TikTok)

معایب:

  • هزینه بالا: پرداخت معمولاً بر اساس ترافیک (از 5-15 دلار برای 1 گیگابایت)
  • سرعت متغیر: بستگی به اینترنت کاربر نهایی دارد
  • عدم ثبات: IP ممکن است در هر لحظه قطع شود

کی استفاده کنیم: پارسینگ Instagram، Facebook، TikTok، کار با API‌های بازار (Wildberries، Ozon)، هر وظیفه‌ای که در آن شهرت IP حیاتی است.

پروکسی‌های موبایل

پروکسی‌های موبایل از IP‌های اپراتورهای موبایل (4G/5G) استفاده می‌کنند. یک IP اغلب به طور همزمان توسط هزاران کاربر واقعی استفاده می‌شود، بنابراین API به ندرت آن‌ها را مسدود می‌کند.

مزایا برای API:

  • اعتماد حداکثری: API نمی‌توانند IP‌های اپراتورهای موبایل را مسدود کنند
  • ایده‌آل برای برنامه‌های موبایل و API‌ها (Instagram، TikTok، Snapchat)
  • تغییر خودکار IP در هنگام دوباره‌اتصال (حالت هواپیما)
  • یک IP می‌تواند درخواست‌های بیشتری بدون مسدود شدن انجام دهد

معایب:

  • هزینه بسیار بالا: از 50-150 دلار برای هر IP در ماه
  • استخرهای کوچک: دشوار است که صدها IP موبایل به دست آورید
  • سرعت متغیر: بستگی به کیفیت سیگنال موبایل دارد

کی استفاده کنیم: کار با API‌های موبایل، پارسینگ Instagram/TikTok در حجم بالا، زمانی که نیاز به حداکثر حفاظت در برابر مسدود شدن دارید.

پروکسی‌های دیتاسنتر

پروکسی‌های دیتاسنتر — آدرس‌های IP سرورهایی هستند که در دیتاسنترها قرار دارند. آن‌ها با کاربران واقعی ارتباطی ندارند.

مزایا برای API:

  • هزینه پایین: از 1-5 دلار برای هر IP در ماه
  • سرعت بالا: کانال‌های 1-10 گیگابیت در ثانیه
  • ثبات: IP‌ها به طور تصادفی قطع نمی‌شوند
  • استخرهای بزرگ: به راحتی می‌توان صدها IP به دست آورد

معایب:

  • اعتماد پایین: بسیاری از API‌ها دیتاسنترها را مسدود می‌کنند
  • IP‌ها به دلیل سایر کاربران اغلب در لیست سیاه قرار دارند
  • برای شبکه‌های اجتماعی و خدمات سخت مناسب نیستند

کی استفاده کنیم: پارسینگ API‌های عمومی بدون حفاظت سخت (هواشناسی، نرخ ارز، اخبار)، کار با API‌های خود، تست و توسعه.

معیار مقیم موبایل دیتاسنتر
اعتماد API بالا حداکثری پایین
اندازه استخر میلیون‌ها IP صدها IP هزاران IP
سرعت متوسط (10-50 مگابیت در ثانیه) متوسط (5-100 مگابیت در ثانیه) بالا (بیش از 100 مگابیت در ثانیه)
هزینه 5-15 دلار/گیگابایت 50-150 دلار/IP/ماه 1-5 دلار/IP/ماه
برای شبکه‌های اجتماعی ✅ عالی ✅ ایده‌آل ❌ مناسب نیستند
برای API‌های عمومی ✅ خوب ✅ خوب (گران) ✅ عالی

پیاده‌سازی عملی: مثال‌های کد در Python

بیایید مثال‌های خاصی از پیاده‌سازی دور زدن محدودیت نرخ با استفاده از پروکسی را بررسی کنیم. همه مثال‌ها در Python با کتابخانه 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())

استفاده از پروکسی‌های مقیم با چرخش خودکار

بسیاری از ارائه‌دهندگان پروکسی‌های مقیم یک endpoint واحد ارائه می‌دهند که به طور خودکار 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 درخواست از طریق IP‌های مختلف
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 نیاز به نظارت مداوم بر محدودیت‌ها و پردازش صحیح خطاها دارد. در اینجا نکات کلیدی وجود دارد:

تحلیل هدرهای پاسخ

بسیاری از API‌ها اطلاعاتی درباره محدودیت‌ها را در هدرهای پاسخ بازمی‌گردانند. هدرهای استاندارد:

  • X-RateLimit-Limit — حداکثر تعداد درخواست‌ها در پنجره
  • X-RateLimit-Remaining — چند درخواست باقی مانده است
  • X-RateLimit-Reset — زمان بازنشانی محدودیت (timestamp یونیکس)
  • 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} بازنشانی می‌شود")

لاگ‌گیری و آمار

آمار دقیقی از درخواست‌ها برای هر پروکسی نگه‌داری کنید. این به شناسایی IP‌های مشکل‌دار و بهینه‌سازی چرخش کمک می‌کند:

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}s")

# استفاده
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}s")

پردازش کپچا و سایر مسدودیت‌ها

برخی API‌ها در صورت تجاوز از محدودیت‌ها، به جای مسدودیت مستقیم، کپچا را نمایش می‌دهند. نشانه‌ها:

  • کد وضعیت 403 با بدنه پاسخ که شامل "captcha" یا "recaptcha" است
  • ریدایرکت به صفحه کپچا (کد وضعیت 302)
  • هدرهای خاصی مانند X-Captcha-Required: true

در چنین مواردی باید:

  1. بلافاصله استفاده از این IP را متوقف کنید
  2. به پروکسی دیگری از استخر جابجا شوید
  3. تأخیرها بین درخواست‌ها را افزایش دهید
  4. تنوع بیشتری به User-Agent و سایر هدرها اضافه کنید

مهم: اگر به طور منظم با کپچا هنگام استفاده از پروکسی‌های مقیم مواجه می‌شوید، مشکل احتمالاً در الگوهای رفتاری (هدرهای یکسان، درخواست‌های بسیار سریع) است، نه در آدرس‌های IP.

نتیجه‌گیری

دور زدن محدودیت نرخ API هنگام استفاده از پروکسی، تنها یک تنظیم فنی نیست، بلکه یک استراتژی جامع است که شامل انتخاب صحیح نوع پروکسی، تنظیم چرخش IP، مدیریت تأخیرها و نظارت بر محدودیت‌ها می‌شود. نکات کلیدی از مقاله:

  • پروکسی‌ها به تنهایی مشکل محدودیت نرخ را حل نمی‌کنند — نیاز به استراتژی چرخش صحیح است
  • برای شبکه‌های اجتماعی و API‌های سخت از پروکسی‌های مقیم یا موبایل استفاده کنید، برای API‌های عمومی دیتاسنترها مناسب هستند
  • اندازه استخر پروکسی را بر اساس محدودیت‌های API و سرعت مورد نظر پارسینگ محاسبه کنید
  • همیشه به دنبال بهینه‌سازی رفتار درخواست‌های خود باشید تا از مسدودیت‌ها جلوگیری کنید.
```