ما هو الحدائق؟
والحدود النسبية هي الجدران الخفية التي تبنى المواقع الشبكية للسيطرة على مدى سرعة أي عميل واحد في تقديم الطلبات. عندما تخرّب موقعاً بشكل عدواني جداً، تضرب هذه الجدران - والعواقب تتراوح بين التباطؤ المؤقت والحظر الدائم للشركة. فهم كيفية الحد من معدل العمل، وكيف يكتشفونك، وكيفية البقاء تحتها أمر أساسي لبناء الخردة التي تقدم البيانات بشكل موثوق.
هذا الدليل يشرح الميكانيكيين وراء الحد من المعدل، وأجهزة الكشف تستخدم المواقع الشبكية، والاستراتيجيات العملية للضرب التكيّفي الذي يبقي الخردة تعمل بسلاسة.
من أجل لمحة عامة أوسع عن الخردة مع العملاء دليل كامل للدعاوى الإلكترونية- تجنبا للقطع بوجه عام، يقرأ كيف لـ (سكرابي ويب) دون أن يغلق.
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 resultsNode.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. وتبدأ دائما بالتحفظ والزيادة على أساس معدلات النجاح الملحوظة.






