حدود معدل الاستخراج: شرح مفصل

How rate limits work, how sites detect scrapers, and practical strategies to stay under limits. (ب) تشمل رمز التقلبات التكييفية وأنماط الحد من المعدل الموزع.

حدود معدل الاستخراج: شرح مفصل

ما هو الحدائق؟

والحدود النسبية هي الجدران الخفية التي تبنى المواقع الشبكية للسيطرة على مدى سرعة أي عميل واحد في تقديم الطلبات. عندما تخرّب موقعاً بشكل عدواني جداً، تضرب هذه الجدران - والعواقب تتراوح بين التباطؤ المؤقت والحظر الدائم للشركة. فهم كيفية الحد من معدل العمل، وكيف يكتشفونك، وكيفية البقاء تحتها أمر أساسي لبناء الخردة التي تقدم البيانات بشكل موثوق.

هذا الدليل يشرح الميكانيكيين وراء الحد من المعدل، وأجهزة الكشف تستخدم المواقع الشبكية، والاستراتيجيات العملية للضرب التكيّفي الذي يبقي الخردة تعمل بسلاسة.

من أجل لمحة عامة أوسع عن الخردة مع العملاء دليل كامل للدعاوى الإلكترونية- تجنبا للقطع بوجه عام، يقرأ كيف لـ (سكرابي ويب) دون أن يغلق.

How Rate Limiting Works

وتنفذ المواقع الشبكية حدوداً للمعدلات في طبقات متعددة، ولكل منها نطاقات مختلفة للكشف:

1 - الحد الأقصى المحدد بمقياس IP-Based

النهج الأكثر شيوعا. ويقوم الخادم بتتبع الطلبات لكل عنوان من عنوان IP في غضون نافذة زمنية. Exceed the threshold and you receive HTTP 429 (Too Many requests) or 503 responses.

# Typical rate limit behavior
Request 1-50:    HTTP 200 (normal)
Request 51:      HTTP 429 (rate limited)
Wait 60 seconds...
Request 52:      HTTP 200 (reset)

Layer 2: Session/Cex-Based Limits

التتبع يطلب تردد كل دورة أو كعكة بروزر حتى لو تناوبت شركاء التنفيذ نفس الجلسة التي تضرب الخادم بسرعة سوف تحفز الحدود

Layer 3: Account-Based Limits

أما بالنسبة للمواقع التي تحتاج إلى قطع غيار، فإن الحدود ترتبط بحساب المستخدم بصرف النظر عن IP. Common on APIs and SaaS platforms.

Layer 4: Behavioral Analysis

(ج) النظم المتقدمة مثل كلودفلير وبيريميتركس وأكامي تحلل الأنماط السلوكية: طلب التوقيت، تدفق الملاحة، تحركات الفأر (في سياقات بروزر). هذه الطبقة هي الاصعب على التفاف لأنها لا تعتمد على مضادات بسيطة

الإشارات المشتركة لتحديد الحدود

وتستخدم المواقع الشبكية إشارات متعددة في آن واحد للكشف عن الخردة الآلية:

الإشارات المشتركة لتحديد الحدود
الإشارةما هو تشخيصصعوبة إيفا
كل دقيقةالسرعة القصوىعلى مهلك
كل ساعة/يومالحجم المستداممتوسطة (معدلات ضغط الدم)
نظام التوقيتفترات تشبه الآلاتمتوسطة (مبتدئة)
المفقودون/المرؤوسونعملاء غير مكتظينعلى مهلك
Sequential URL patternsزحف منتظممتوسطة (ترتيب محلي)
بصمتالمكتبة ضد بروزرصلب (استخدام مهرّب حقيقي)
حكم الإعداممهر بلا رأسصلب (ثقب مائل)
تظاهرات على متن السفنسلوك البوتصعب جدا

تعلم المزيد عن آليات الكشف في دليلنا How Anti-Bot Systems Detect Proxies.

:: مدونات الاستجابة الخاصة بمكافحة الاتجار بالبشر

معرفة أيّ رموز (ه تي بي) تشير إلى أنّ الحدّ من السعر يساعدك على بناء منطق التراجع السليم

:: مدونات الاستجابة الخاصة بمكافحة الاتجار بالبشر
المدونةمعنىالإجراء
200 (مع CAPTCHA)اللبنة الخفيفة - صفحة التحديIP, slow down
403 محظورIP or session blockedتناوب IP على الفور
429 طلبات كثيرةالحد الأقصى للمعدلات المتوقعةالانتظار والعودة مع التخلف
503 خدمات غير متاحةحمولة زائدة أو كتلةتراجعوا، تحققوا إذا تم إيقافهم
302/307 إلى CAPTCHA URLإعادة توجيه التحديمعدل IP، خفض السرعة

الاستراتيجية 1: الالتزام

النهج الأبسط - إبقاء معدل طلبك أقل بكثير مما يسمح به الهدف. وهذا يعني انخفاض حالات الفشل، وقلة هدر عرض النطاق الترددي، وزيادة استدامة الخردة.

import requests
import time
import random
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def respectful_scrape(urls: list[str], rpm_limit: int = 10) -> list[str]:
    """Scrape URLs while respecting a requests-per-minute limit."""
    delay = 60.0 / rpm_limit
    results = []
    for url in urls:
        try:
            resp = requests.get(
                url,
                proxies={"http": PROXY, "https": PROXY},
                timeout=30
            )
            results.append(resp.text if resp.status_code == 200 else None)
        except requests.RequestException:
            results.append(None)
        # Add delay with random jitter (±30%) to look less robotic
        jitter = delay * random.uniform(0.7, 1.3)
        time.sleep(jitter)
    return results

الاستراتيجية 2: التأثير الإيجابي

بدلاً من سعر ثابت عدل سرعتك بشكل دينامي بناء على الردود التي تتلقاها تسرع عندما يعمل كل شيء تبطئ عندما ترى علامات تحذير

Python Implementation

import requests
import time
import random
from dataclasses import dataclass, field
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
@dataclass
class AdaptiveThrottle:
    """Automatically adjusts request rate based on server responses."""
    base_delay: float = 2.0      # seconds between requests
    min_delay: float = 0.5
    max_delay: float = 30.0
    current_delay: float = 2.0
    success_streak: int = 0
    warning_codes: set = field(default_factory=lambda: {429, 403, 503})
    def on_success(self):
        self.success_streak += 1
        # Speed up after 10 consecutive successes
        if self.success_streak >= 10:
            self.current_delay = max(self.current_delay * 0.85, self.min_delay)
            self.success_streak = 0
    def on_rate_limit(self):
        self.success_streak = 0
        # Double the delay on rate limit
        self.current_delay = min(self.current_delay * 2.0, self.max_delay)
    def on_block(self):
        self.success_streak = 0
        # Aggressive backoff on block
        self.current_delay = min(self.current_delay * 3.0, self.max_delay)
    def wait(self):
        jitter = self.current_delay * random.uniform(0.7, 1.3)
        time.sleep(jitter)
def scrape_adaptive(urls: list[str]) -> list[dict]:
    throttle = AdaptiveThrottle()
    results = []
    for url in urls:
        try:
            resp = requests.get(
                url,
                proxies={"http": PROXY, "https": PROXY},
                timeout=30
            )
            if resp.status_code == 200:
                throttle.on_success()
                results.append({"url": url, "status": 200, "body": resp.text})
            elif resp.status_code == 429:
                throttle.on_rate_limit()
                # Check Retry-After header
                retry_after = int(resp.headers.get("Retry-After", 0))
                if retry_after:
                    time.sleep(retry_after)
                results.append({"url": url, "status": 429, "body": None})
            elif resp.status_code == 403:
                throttle.on_block()
                results.append({"url": url, "status": 403, "body": None})
            else:
                results.append({"url": url, "status": resp.status_code, "body": resp.text})
        except requests.RequestException as e:
            throttle.on_block()
            results.append({"url": url, "status": 0, "error": str(e)})
        throttle.wait()
        print(f"Current delay: {throttle.current_delay:.1f}s")
    return results

Node.js Implementation

const HttpsProxyAgent = require('https-proxy-agent');
const fetch = require('node-fetch');
class AdaptiveThrottle {
  constructor() {
    this.currentDelay = 2000; // ms
    this.minDelay = 500;
    this.maxDelay = 30000;
    this.successStreak = 0;
  }
  onSuccess() {
    this.successStreak++;
    if (this.successStreak >= 10) {
      this.currentDelay = Math.max(this.currentDelay * 0.85, this.minDelay);
      this.successStreak = 0;
    }
  }
  onRateLimit() {
    this.successStreak = 0;
    this.currentDelay = Math.min(this.currentDelay * 2, this.maxDelay);
  }
  onBlock() {
    this.successStreak = 0;
    this.currentDelay = Math.min(this.currentDelay * 3, this.maxDelay);
  }
  async wait() {
    const jitter = this.currentDelay * (0.7 + Math.random() * 0.6);
    return new Promise(resolve => setTimeout(resolve, jitter));
  }
}
async function scrapeAdaptive(urls) {
  const throttle = new AdaptiveThrottle();
  const agent = new HttpsProxyAgent('http://USERNAME:PASSWORD@gate.proxyhat.com:8080');
  const results = [];
  for (const url of urls) {
    try {
      const res = await fetch(url, { agent, timeout: 30000 });
      if (res.ok) {
        throttle.onSuccess();
        results.push({ url, status: res.status, body: await res.text() });
      } else if (res.status === 429) {
        throttle.onRateLimit();
        const retryAfter = parseInt(res.headers.get('retry-after') || '0');
        if (retryAfter) await new Promise(r => setTimeout(r, retryAfter * 1000));
        results.push({ url, status: 429, body: null });
      } else if (res.status === 403) {
        throttle.onBlock();
        results.push({ url, status: 403, body: null });
      }
    } catch (err) {
      throttle.onBlock();
      results.push({ url, status: 0, error: err.message });
    }
    await throttle.wait();
    console.log(`Current delay: ${throttle.currentDelay.toFixed(0)}ms`);
  }
  return results;
}

الاستراتيجية 3: الحد من المعدل الموزع

وعند إدارة حالات الخردة المتعددة بالتوازي، تنسيق الحد الأقصى للمعدلات في جميع العمال. فبدون التنسيق، يحترم كل عامل حدوده الخاصة، ولكن حركة المرور المشتركة لا تزال تفوق الهدف.

import requests
import time
import threading
class DistributedRateLimiter:
    """Thread-safe rate limiter for multiple scraper workers."""
    def __init__(self, max_rpm: int):
        self.min_interval = 60.0 / max_rpm
        self.lock = threading.Lock()
        self.last_request_time = 0.0
    def acquire(self):
        """Block until it is safe to make the next request."""
        with self.lock:
            now = time.time()
            elapsed = now - self.last_request_time
            if elapsed < self.min_interval:
                time.sleep(self.min_interval - elapsed)
            self.last_request_time = time.time()
# Shared limiter across all threads
limiter = DistributedRateLimiter(max_rpm=30)
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def worker(urls: list[str], results: list):
    for url in urls:
        limiter.acquire()
        try:
            resp = requests.get(
                url,
                proxies={"http": PROXY, "https": PROXY},
                timeout=30
            )
            results.append({"url": url, "status": resp.status_code})
        except Exception as e:
            results.append({"url": url, "error": str(e)})

الاستراتيجية 4: طلب الحصول على الأولوية

وفيما يتعلق بمشاريع الخردة المعقدة، ينبغي استخدام استفسار ذي أولوية يدير حدود المعدلات لكل مجال مستهدف:

import requests
import time
import heapq
import threading
from collections import defaultdict
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
class DomainRateLimiter:
    """Per-domain rate limiting with priority queue."""
    def __init__(self, default_rpm: int = 10):
        self.default_rpm = default_rpm
        self.domain_limits = {}          # domain -> max RPM
        self.domain_last = defaultdict(float)  # domain -> last request time
        self.lock = threading.Lock()
    def set_limit(self, domain: str, rpm: int):
        self.domain_limits[domain] = rpm
    def wait_for_domain(self, domain: str):
        rpm = self.domain_limits.get(domain, self.default_rpm)
        min_interval = 60.0 / rpm
        with self.lock:
            now = time.time()
            elapsed = now - self.domain_last[domain]
            if elapsed < min_interval:
                time.sleep(min_interval - elapsed)
            self.domain_last[domain] = time.time()
# Configure per-domain limits
limiter = DomainRateLimiter(default_rpm=10)
limiter.set_limit("amazon.com", 3)        # Very conservative for Amazon
limiter.set_limit("example.com", 30)      # Lenient for simple sites
limiter.set_limit("google.com", 5)        # Moderate for Google

قراءة الروبوتات

العديد من المواقع تنشر أفضليات الزحف في الروبوتات The Crawl-delay التوجيه يخبرك بالثواني الدنيا بين الطلبات

import requests
from urllib.parse import urlparse
from urllib.robotparser import RobotFileParser
def get_crawl_delay(base_url: str, user_agent: str = "*") -> float | None:
    """Extract Crawl-delay from robots.txt."""
    parsed = urlparse(base_url)
    robots_url = f"{parsed.scheme}://{parsed.netloc}/robots.txt"
    try:
        resp = requests.get(robots_url, timeout=10)
        if resp.status_code != 200:
            return None
        rp = RobotFileParser()
        rp.parse(resp.text.splitlines())
        delay = rp.crawl_delay(user_agent)
        return delay
    except Exception:
        return None
# Check before scraping
delay = get_crawl_delay("https://example.com")
if delay:
    print(f"Site requests {delay}s between requests")
else:
    print("No crawl-delay specified")

المعدل العام لمدى سوء التصرف

  • تجاهل 429 ردا. ويعالج العديد من الخردة جميع الردود غير الـ 200 على نفس المنوال. A 429 tells you exactly what happened - use the Retry-After header and back off.
  • تأخيرات ثابتة بدون جليس طلب بالضبط كل 2000 ثانية يبدو روبوتياً أضف تغيراً عشوائياً إلى تأخيراتك
  • ليس تنسيق العمال الموازيين ويعادل كل من خمسة من العمال الذين يعملون في 10 من هذه الآليات ما مجموعه 50 من الألغام المضادة للأفراد. استخدموا الحد الأقصى للمعدلات المشتركة
  • تناوب شركاء التنفيذ دون إبطاء تناوب شرطة "آي بي" يشتري لك الوقت، لكن إذا كان كلّ مُستجدّة يدقّ الموقع على الفور، فإنّ الاكتشاف المُقدّم سيظلّ يقبض عليك. تناوب في التكوين مع الخنق المناسب.
  • تهتز خلال ساعات الذروة والمواقع أكثر عدوانية مع الحد من المعدل خلال الفترات المرتفعة الارتفاع. زحف ثقيلة مبرمجة خلال ساعات غير دقيقة لزمن الهدف

لحساب كم عدد المحترفين الذين تحتاجهم لدعم الخردة المحدودة كم عدد المحترفين الذين تحتاجون للتشويش؟- بالنسبة لاستراتيجيات التناوب البديلة التي تكمل الحد من المعدل، يستعاض عن عبارة: Proxy Rotation Strategies for Large-Scale Scraping.

ابدأ بتخريد مقيّد السعر بشكل صحيح باستخدام ProxyHat Python SDK أو استكشاف خطط التسعير لمشروعك

الأسئلة المتكررة

ماذا يحدث عندما أتجاوز الحد الأقصى؟

الرد يعتمد على الموقع معظمهم يعودون إلى الشرطة 429 مع رئيس فريق ريتري وبعضها يخدم مراكز تنسيق المساعدة الإنسانية. المواقع العدوانية على الفور تحجب IP مع 403 رد. In the worst case, repeated violations lead to permanent IP bans.

كيف أجد الحد الأقصى للموقع؟

ابدأ بالبطء والازدياد تدريجيا مع رصد رموز الاستجابة. تحققي من الروبوتات، التوكسيت من أجل توجيهات القتل Observe response headers for X-RateLimit-Limit and X-RateLimit-Remaining fields. Some APIs publish their limits in documentation.

هل تستخدم حدود معدل التجاوزات؟

العملاء يوزعون الطلبات عبر شركاء التنفيذ المتعددين لذا يبقى كل منهم تحت الحد الأقصى للشراكات الدولية غير أن المواقع المتطورة تتبع أيضاً الجلسات وبصمات الأصابع والأنماط السلوكية. والدعاوى ضرورية ولكنها غير كافية - تجمع بينها وبين أنماط الطلب السليمة والواقعية.

ما هو أفضل معدل لطلب الخردة؟

لا يوجد إجابة عالمية بالنسبة لأهداف عدوانية مثل غوغل أو الأمازون، 1-5 طلبات في الدقيقة لكل آي بي آمنة. For lightly protected sites, 20-60 RPM per IP may work. وتبدأ دائما بالتحفظ والزيادة على أساس معدلات النجاح الملحوظة.

¿Listo para empezar?

Accede a más de 50M de IPs residenciales en más de 148 países con filtrado impulsado por IA.

Ver preciosProxies residenciales
← Volver al Blog