Scraping Hız Limitleri Açıklaması

Hız limitleri nasıl çalışır, siteler hurdaları nasıl algılar ve sınırları altında kalmak için pratik stratejiler. Adaptif bir throttling kodu ekleyin ve limitli kalıpları dağıtın.

Scraping Hız Limitleri Açıklaması

Fiyat Sınırları Ne Atıyor?

Puan sınırları, web sitelerinin herhangi bir müşterinin istekleri ne kadar hızlı kontrol etmek için inşa ettiği görünmez duvarlardır. Bir siteyi çok agresif bir şekilde kazıdığınızda, bu duvarları vurdunız - ve sonuçları geçici yavaşlamalardan kalıcı IP yasaklarına kadar. Hız sınırlarının nasıl çalıştığını anlamak, sizi nasıl algıladıkları ve onların altında kalmak, verileri güvenilir bir şekilde teslim eden hurdaları inşa etmek için temeldir.

Bu kılavuz, ölçüm sinyalleri web sitelerinin kısıtlanmasının ardındaki mekanikleri ve satın almalarını sağlayan adaptif bir throttling için pratik stratejileri açıklıyor.

Daha geniş bir tanıtım için, referanslarla kazıma, bizi gör Web'e komple rehber ProxiesGenel olarak bloklardan kaçınmak için, okuyun Blokedilmeden Web Siteleri Nasıl Çıkarılır.

How Rate Limiting Works

Web siteleri birden çok katmanda, her biri farklı algılama granularity:

Katman 1: IP-Based Rate Limits

En yaygın yaklaşım. Sunucu, IP adresi bir süre içinde talep eder. Eşliği genişletin ve HTTP 429 (Too Many Requests) veya 503 yanıt alırsınız.

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

Katman 2: Oturum/Cookie-Based Limits

Tracks istek frekansı seans veya tarayıcı kurabiye için. IP'leri döndürseniz bile, aynı seans sunucuyu hızlı vurmak limitleri tetikleyecek.

Katman 3: Hesap Tabanlı Limitler

Giriş gerektiren siteler için, sınırlar IP'ye bakılmaksızın kullanıcı hesabına bağlıdır. API'ler ve SaaS platformları üzerinde ortak.

Katman 4: Davranış Analizi

Cloudflare, PerimeterX ve Akamai gibi gelişmiş sistemler: istek zamanlaması, navigasyon akışı, fare hareketleri ( tarayıcı bağlamları). Bu katman atlamak en zor çünkü basit karşılara güvenmiyor.

Common Rate Limit Tespit Signals

Web siteleri otomatik kazı tespit etmek için aynı anda birden fazla sinyal kullanır:

Common Rate Limit Tespit Signals
Signal SignalHangileri tespit ederEvade
Dakikada IP'ye İsteklerRaw hızKolay (görüler)
IP'ye saatte / günlük isteklerSustained volumeMedium (rotate IPs)
Sıklık isteğiMachine-like intervalsMedium (add jitter)
Eksik /wrong başlıklarıOlmayan müşterilerKolay (doğru başlıklar)
Senaryo kalıplarıSistematik taramaMedium (rando Feedback order)
TLS parmak iziKütüphane vs tarayıcıHard (gerçek tarayıcılar kullanın)
JavaScript execution JavaScript execution JavaScript executionHeadless browserHard (advanced configure)
Mouse /keyboard olaylarBot davranışıÇok zor

Rehberimizde algılama mekanizmaları hakkında daha fazla bilgi edinin Anti-Bot Systems Proxies nasıl tespit edilir.

HTTP Response Kodlarını Limiting

Hangi HTTP kodlarının uygun yeniden deneme mantığı oluşturmanıza yardımcı olduğunu bilmek:

HTTP Response Kodlarını Limiting
Kod KoduAnlamEylem
200 (CAPTCHA ile)Yumuşak blok - meydan okuma sayfası servisRotate IP, yavaş aşağı
403 YasakIP veya oturum bloke edildiRotate IP hemen
429 Çok Fazla İstekExplicit oranı limit hitWait and retry with backoff
503 Hizmet Un availableServer aşırı yükleme veya blokBackoff, bloke edilirse kontrol edin
302/307 - CAPTCHA URLChallenge yönlendirmeRotate IP, hız azalt

Strateji 1: Saygılı Throttling

En basit yaklaşım - Hedefin izin verdiğinin altında talep oranını iyi tut. Bu daha az başarısızlık, daha az boşanmış bant genişliği ve daha sürdürülebilir kazı anlamına gelir.

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

Strateji 2: Adaptasyon Throttling

Sabit bir oran yerine, dinamik olarak aldığınız cevaplara dayanarak hızınızı ayarlayın. Her şeyin çalıştığı zaman hızlanır, uyarı işaretleri gördüğünüzde yavaşlayın.

Python Uygulaması

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 Uygulama

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;
}

Strateji 3: Dağıtılmış Oran Limiting

Paralel olarak birden çok hurda örneği çalışırken, tüm işçiler arasındaki oranı sınırlayın. Koordinasyon olmadan, her işçi kendi sınırına saygı duyar, ancak birleşik trafik hala hedefin üzerindedir.

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

Strateji 4: Öncekilik ile Queue

Karmaşık kazı projeleri için, hedef alan başına oranı limitlerini yöneten öncelikli bir kuyruk kullanın:

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

Robotlar.txt for Rate Hints

Birçok site, robotlarda tarama tercihlerini yayınlar.txt. The The The The The The The The Crawl-delay yönerge size istekler arasında en az saniye söyler:

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

Common Rate Limit Hatalar

  • 429 cevabı görmezden gelin. Birçok scrapers aynı yanıtların tamamını tedavi eder. A 429 size tam olarak ne olduğunu söyler - Retry- Afterhead ve back off.
  • jitter olmadan sabit gecikmeler. Her 2.000 saniyede bir istek robotik görünüyor. Belirsizlerinize rastgele varyasyon (jitter) ekleyin.
  • Paralel işçileri koordine etme. Her biri 10 RPM toplam 50 RPM eşittir. Paylaşılan bir fiyat limiti kullanın.
  • Yavaşlamadan IP'leri Rotating IPs without slowing. IP rotasyonu sizi zaman alır, ancak her yeni IP hemen siteyi çekiçse, gelişmiş algılama sizi yakalar. Doğru throttling ile rotasyonu birleştirin.
  • Top saatleri boyunca avlamak. Siteler yüksek-traffic dönemler sırasında sınırlanan oranla daha agresiftir. Hedefin zaman bölgesi için kapalı saatler boyunca ağır taramalar.

Oran sınırlı kazınızı desteklemek için kaç temsilciye ihtiyacınız olduğunu hesaplamak için, bakınız Kaç Proxies Kaçmak İçin İhtiyacınız Var?.For proxy rotasyon stratejileri that complete rate limit, read Proxy Rotation Strategies for Large-Scale Haping.

Doğru oran sınırlı kazılarla başlayın ProxyHat Python SDK veya keşfedin Fiyatlandırma planları Projeniz için.

Sık Sorulan Sorular

Bir oranı sınırı aşıyorsam ne olur?

Cevap siteye bağlıdır. Çoğu geri dönüş HTTP 429, bir Retry- Afterhead ile. Bazıları CAPTCHAs'a hizmet eder. Aggressive siteleri IP'yi 403 yanıtla hemen engeller. En kötü durumda, tekrarlanan ihlaller kalıcı IP yasağına yol açıyor.

Bir sitenin oranı sınırı nasıl bulurum?

Yavaş başlayın ve yanıt kodlarını takip ederken yavaşlayın. Crawl-delay yönergeleri için robotlar.txt. X-RateLimit-Limit ve X-RateLimit-Remaining alanları için kafaları takip edin. Bazı API'ler, belgelerinde sınırlarını yayınlar.

Yönleri kullanmak oran sınırları aşıyor mu?

Proxies, birden fazla IP üzerinden istekleri dağıtır, bu yüzden her IP per-IP sınırı altında kalır. Bununla birlikte, sofistike siteler de seansları, parmak izlerini ve davranışsal kalıpları takip eder. Proxies gereklidir ancak yeterli değildir - onları doğru throttling ve gerçekçi istek kalıpları ile birleştirir.

Yıkım için en güvenli istek oranı nedir?

Evrensel bir cevap yoktur. Google veya Amazon gibi agresif hedefler için, IP başına dakika başına 1-5 talep güvenlidir. Işıklı korumalı siteler için, IP başına 20-60 RPM çalışabilir. Her zaman gözlemlenen başarı oranlarına dayanan muhafazakar ve artış başlar.

Başlamaya hazır mısınız?

148+ ülkede 50M+ konut IP'sine AI destekli filtreleme ile erişin.

Fiyatlandırmayı GörüntüleKonut Proxy'leri
← Bloga Dön