Proxy Rotation Is Essential for Large-Scale Haping
Yüzlerce ila milyonlarca istekten ölçeklendiğinde, tek bir proxy IP bir sorumluluk haline gelir. Web siteleri IP başına talep modelleri takip eder ve normal tarama davranışını aşıyor veya yasak adreslerini yasaklayacaktır. Proxy rotasyon İsteklerinizi birçok IP üzerinden dağıtın, böylece tek bir adres algılamayı tetikleyecek kadar aktivite biriktirir.
Bir naif rotasyon yaklaşımı ve iyi tasarlanmış bir strateji arasındaki fark,% 95 başarı oranı ile %40 arasında fark anlamına gelebilir. Bu kılavuz, her birini kullanmak için dört ana rotasyon stratejisini kapsar ve bunları çalışma kodu örnekleri ile nasıl uygulayın.
Bu makalemizin bir parçasıdır Web'e komple rehber Proxies küme. Temel proxy konseptlerine ihtiyacınız varsa oraya başlayın.
Strateji 1: Per-Request Rotation
En basit yaklaşım: Her istek yeni bir IP alırBu, her isteğin bağımsız olduğu devletsiz veri toplaması için idealdir - fiyat aramaları, SERP sorguları, ürün sayfası getiriyor.
Ne zaman Kullanılır
- Her URL'nin bağımsız olduğu büyük katalogları avlayın
- SERP birçok anahtar kelime boyunca izleme
- Çerez veya oturum devleti gerektirmez herhangi bir görev
Python Uygulaması
import requests
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def fetch_with_rotation(urls: list[str]) -> list[str]:
"""Each request automatically gets a fresh IP via the rotating gateway."""
results = []
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
for url in urls:
try:
resp = session.get(url, timeout=30)
resp.raise_for_status()
results.append(resp.text)
except requests.RequestException as e:
print(f"Failed {url}: {e}")
results.append(None)
return results
# Each request through gate.proxyhat.com uses a different IP
pages = fetch_with_rotation([
"https://example.com/product/1",
"https://example.com/product/2",
"https://example.com/product/3",
])Node.js Uygulama
const HttpsProxyAgent = require('https-proxy-agent');
const fetch = require('node-fetch');
const agent = new HttpsProxyAgent('http://USERNAME:PASSWORD@gate.proxyhat.com:8080');
async function fetchWithRotation(urls) {
const results = [];
for (const url of urls) {
try {
const res = await fetch(url, { agent, timeout: 30000 });
results.push(await res.text());
} catch (err) {
console.error(`Failed ${url}: ${err.message}`);
results.push(null);
}
}
return results;
}Go Uygulama
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"time"
)
func fetchWithRotation(urls []string) []string {
proxyURL, _ := url.Parse("http://USERNAME:PASSWORD@gate.proxyhat.com:8080")
client := &http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
Timeout: 30 * time.Second,
}
results := make([]string, len(urls))
for i, u := range urls {
resp, err := client.Get(u)
if err != nil {
fmt.Printf("Failed %s: %v\n", u, err)
continue
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
results[i] = string(body)
}
return results
}Strateji 2: Zamanlı Rotasyon (Sticky Sessions)
Bazı kazı görevleri, bir dizi ilgili istek için aynı IP gerektirir - bir paginated listeleme, çok adımlı bir checkout ya da bir giriş seansını sürdürmek. Zamanlı rotasyon (veya yapışkan seanslar) tanımlanmış bir süre için aynı IP tutar, genellikle 1-30 dakika.
Ne zaman Kullanılır
- Paginated hatching (sayfa 1, 2, 3 ... sonuçlar)
- Çerezler veya seans gerektiren görevler kalıcıdır
- Gerçek tarama kalıpları
Uygulama
ProxyHat ile, yapışkan seanslar kimliklerinizde oturum parametresi ile kontrol edilir. Her benzersiz oturum ID, yapılandırılmış süre için aynı IP'yi korur:
import requests
import uuid
def create_sticky_session(duration_label: str = "10m"):
"""Create a session that maintains the same IP."""
session_id = uuid.uuid4().hex[:8]
proxy = f"http://USERNAME-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
session = requests.Session()
session.proxies = {"http": proxy, "https": proxy}
return session
# All requests through this session use the same IP
session = create_sticky_session()
page1 = session.get("https://example.com/listings?page=1")
page2 = session.get("https://example.com/listings?page=2")
page3 = session.get("https://example.com/listings?page=3")Node.js Sticky Session
const HttpsProxyAgent = require('https-proxy-agent');
const fetch = require('node-fetch');
const crypto = require('crypto');
function createStickyAgent() {
const sessionId = crypto.randomBytes(4).toString('hex');
return new HttpsProxyAgent(
`http://USERNAME-session-${sessionId}:PASSWORD@gate.proxyhat.com:8080`
);
}
async function crawlPaginated(baseUrl, pages) {
const agent = createStickyAgent(); // Same IP for all pages
const results = [];
for (let page = 1; page <= pages; page++) {
const res = await fetch(`${baseUrl}?page=${page}`, { agent });
results.push(await res.text());
}
return results;
}Strateji 3: Başarısızlıklı Rotasyon
Her istekte veya bir zamanlayıcıda geri dönmek yerine, Başarısızlık temelli rotasyon bloke olana kadar bir IP kullanmaya devam edin, sonra anahtarlar. Bu, çalışır olduğu sürece her IP değerini en üstlenir.
Ne zaman Kullanılır
- Hedefler, tahmin edilemez eşleri engellemeyle
- IP başına en fazla talep istediğiniz yerde bütçe bilinçli kazılar
- Bazı IP'lerin geçen saatler ve diğer dakikalar nerede olduğunu uzun süren taramalar
Otomatik Başarısızlık ile Uygulama
import requests
import uuid
from time import sleep
class FailureBasedRotator:
"""Rotates proxy only when the current IP fails."""
BLOCK_SIGNALS = [403, 429, 503]
MAX_RETRIES = 3
def __init__(self):
self.session_id = None
self.requests_on_current_ip = 0
self._new_session()
def _new_session(self):
self.session_id = uuid.uuid4().hex[:8]
self.requests_on_current_ip = 0
proxy = f"http://USERNAME-session-{self.session_id}:PASSWORD@gate.proxyhat.com:8080"
self.session = requests.Session()
self.session.proxies = {"http": proxy, "https": proxy}
def fetch(self, url: str) -> str | None:
for attempt in range(self.MAX_RETRIES):
try:
resp = self.session.get(url, timeout=30)
if resp.status_code in self.BLOCK_SIGNALS:
print(f"Blocked (HTTP {resp.status_code}) after "
f"{self.requests_on_current_ip} requests. Rotating...")
self._new_session()
sleep(1)
continue
resp.raise_for_status()
self.requests_on_current_ip += 1
return resp.text
except requests.RequestException:
self._new_session()
sleep(1)
return None
# Usage
rotator = FailureBasedRotator()
for url in urls:
html = rotator.fetch(url)Başarısızlık ile Uygulama
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"net/http"
"net/url"
"time"
)
type FailureRotator struct {
client *http.Client
sessionID string
reqCount int
}
func NewFailureRotator() *FailureRotator {
r := &FailureRotator{}
r.rotate()
return r
}
func (r *FailureRotator) rotate() {
b := make([]byte, 4)
rand.Read(b)
r.sessionID = hex.EncodeToString(b)
r.reqCount = 0
proxyStr := fmt.Sprintf("http://USERNAME-session-%s:PASSWORD@gate.proxyhat.com:8080", r.sessionID)
proxyURL, _ := url.Parse(proxyStr)
r.client = &http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
Timeout: 30 * time.Second,
}
}
func (r *FailureRotator) Fetch(target string) (string, error) {
for attempt := 0; attempt < 3; attempt++ {
resp, err := r.client.Get(target)
if err != nil {
r.rotate()
time.Sleep(time.Second)
continue
}
defer resp.Body.Close()
if resp.StatusCode == 403 || resp.StatusCode == 429 || resp.StatusCode == 503 {
fmt.Printf("Blocked after %d requests. Rotating...\n", r.reqCount)
r.rotate()
time.Sleep(time.Second)
continue
}
body, _ := io.ReadAll(resp.Body)
r.reqCount++
return string(body), nil
}
return "", fmt.Errorf("all retries exhausted for %s", target)
}Strateji 4: Geo-Distributed Rotation
Yerelleştirilmiş içeriği kazılarken - arama sonuçları, fiyatlandırma, kullanılabilirlik - belirli coğrafi konumlardan IP'lere ihtiyacınız var. Geo- dağıtımlı rotasyon Hedef ülkelerden veya şehirlerden doğru yerel verileri elde etmek için IP'leri tayin eder.
Ne zaman Kullanılır
- SERP scraping yerel arama sıralamaları için
- Bölge genelinde fiyat izleme
- Content available checks (geo-restricted content)
- Belirli pazarlarda doğrulama
Ülke Hedefing ile Uygulama
import requests
from concurrent.futures import ThreadPoolExecutor
COUNTRIES = ["us", "gb", "de", "fr", "jp"]
def fetch_localized(url: str, country: str) -> dict:
"""Fetch URL through a proxy in the specified country."""
proxy = f"http://USERNAME-country-{country}:PASSWORD@gate.proxyhat.com:8080"
try:
resp = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)
return {"country": country, "status": resp.status_code, "body": resp.text}
except requests.RequestException as e:
return {"country": country, "status": 0, "error": str(e)}
def scrape_all_regions(url: str) -> list[dict]:
"""Fetch the same URL from multiple countries in parallel."""
with ThreadPoolExecutor(max_workers=len(COUNTRIES)) as executor:
futures = [executor.submit(fetch_localized, url, c) for c in COUNTRIES]
return [f.result() for f in futures]
# Get localized pricing from 5 countries simultaneously
results = scrape_all_regions("https://example.com/product/pricing")
for r in results:
print(f"{r['country'].upper()}: HTTP {r['status']}")Mevcut hedefleme seçeneklerine bakın ProxyHat Locations Sayfa.
Strategies: Hibrit Yaklaşım
Uygulamada, büyük ölçekli kazı projeleri birçok stratejiyi birleştirir. İşte keşif için per-request rotasyonunu kullanan bir model, derin tarama için yapışkan seanslar ve başarısızlık temelli düşüş:
import requests
import uuid
from enum import Enum
class RotationMode(Enum):
PER_REQUEST = "per_request"
STICKY = "sticky"
FAILURE_BASED = "failure_based"
class HybridRotator:
def __init__(self, mode: RotationMode = RotationMode.PER_REQUEST):
self.mode = mode
self.session_id = None
self.failure_count = 0
self._init_session()
def _init_session(self):
if self.mode == RotationMode.PER_REQUEST:
proxy = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
else:
self.session_id = self.session_id or uuid.uuid4().hex[:8]
proxy = f"http://USERNAME-session-{self.session_id}:PASSWORD@gate.proxyhat.com:8080"
self.session = requests.Session()
self.session.proxies = {"http": proxy, "https": proxy}
def force_rotate(self):
"""Force a new IP regardless of mode."""
self.session_id = uuid.uuid4().hex[:8]
self.failure_count = 0
self._init_session()
def fetch(self, url: str) -> str | None:
try:
resp = self.session.get(url, timeout=30)
if resp.status_code in [403, 429, 503]:
self.failure_count += 1
if self.failure_count >= 2:
self.force_rotate()
return None
self.failure_count = 0
return resp.text
except requests.RequestException:
self.failure_count += 1
if self.failure_count >= 2:
self.force_rotate()
return None
# Discovery phase: rotate every request
discovery = HybridRotator(RotationMode.PER_REQUEST)
sitemap_urls = [discovery.fetch(url) for url in seed_urls]
# Deep crawl phase: sticky sessions per site section
crawler = HybridRotator(RotationMode.STICKY)
for section_url in section_urls:
pages = [crawler.fetch(f"{section_url}?page={i}") for i in range(1, 11)]
crawler.force_rotate() # New IP for next sectionRotation Strategy Karşılaştırma
| Strateji Stratejisi | En iyisi için | Başarı Puanı | IP Verimliliği | Karmaşıklık |
|---|---|---|---|---|
| Per-Request | Devletsiz toplu koleksiyon | Yüksek Yüksek Yüksek Yüksek Yüksek | Low Low Low Low | Low Low Low Low |
| Timed/Sticky | Oturum bağımsız görevleri | Medium-High-High | Medium Medium Medium Medium Medium | Low Low Low Low |
| Başarısızlık - | Değişken-difficulty hedefleri | Medium Medium Medium Medium Medium | Yüksek Yüksek Yüksek Yüksek Yüksek | Medium Medium Medium Medium Medium |
| Geo-Distributed | Localized data collection | Yüksek Yüksek Yüksek Yüksek Yüksek | Medium Medium Medium Medium Medium | Medium Medium Medium Medium Medium |
| Hybrid Hybrid Hybrid Hybrid | Kompleks multi-faz projeleri | En yüksek | Yüksek Yüksek Yüksek Yüksek Yüksek | Yüksek Yüksek Yüksek Yüksek Yüksek |
Scale için en iyi uygulamalar
- Saygı robotlar.txt. Rotation sizi iyi bir vatandaş olmaktan muaf değildir. Kurallara göz atın ve tarama yönergelerine saygı gösterin.
- Gerçek gecikmeler ekleyin. rotasyonla bile, ikinci başına yüzlerce istek robotik görünüyor. İstekler arasında 0,5-2 ikinci rastgele gecikme ekleyin.
- Başarı oranlarını izleyin. Hedef site başına HTTP statüsü kodları izleyin. 90'ın altındaki bir düşüş, rotasyonunuzun ayarlanması anlamına gelir.
- Başlık rotasyonu ile birleştirin. Yalnızca IP'leri taşımak yeterli değildir. Rotate Kullanıcı-Agent dizeleri ve diğer başlıkları önlemek için Parmak tabanlı algılama.
- Başarısızlıklara geri dönün. Bir IP bloke edildiğinde, yeniden denemeden önce bekleyin. Exponential backoff (1s, 2s, 4s, 8s) geçici olarak düşmanca hedefler üzerinde talepleri engellemektedir.
rotasyon stratejinizi desteklemek için kaç IP'ye ihtiyacınız olduğunu anlamak için, bakın Kaç Proxies Kaçmak İçin İhtiyacınız Var?. Kapsamlı bir kazı mimari genel bakış için, ziyaret edin Web'e komple rehber Proxies.
Bu stratejileri uygulamaya hazır mısınız? Check out the the Python SDK, Node SDKYa da Go SDK Üretim hazır proxy entegrasyonu için veya keşfedin ProxyHat fiyatlandırma planları Başlamak için.
Sık Sorulan Sorular
Web scraping için en iyi proxy rotasyon stratejisi nedir?
Per-request rotasyonu çoğu hurda görevleri için en güvenli varsayılandır. Her istek farklı bir IP kullanır, desen algılamasını çok daha zor hale getirir. Oturumu gerektiren görevler için (pagination, login flows), bunun yerine yapışkan seanslar kullanın.
Ne kadar hızlı dönmeliyim?
per-request rotasyonu için, her istek otomatik olarak yeni bir IP alır. Barınma seansları için, 5-10 dakika iyi bir varsayılan. En iyi süre hedefe bağlıdır - agresif siteler daha kısa seanslar (1-2 dakika) gerektirebilir, ancak lenient olanlar 30 + dakikaya tahammül edebilir.
Farklı rotasyon stratejileri birleştirebilir miyim?
Evet, ve karmaşık projeler için yapmalısınız. Keşif ve URL koleksiyonu için per-request rotasyonunu kullanın, derin tarama için yapışkan seanslar ve IP'lerin bloke edildiği bir geri dönüş olarak başarısızlık bazlı bir rotasyon. Bu kılavuzdaki hibrit yaklaşım nasıl olduğunu gösteriyor.
ProxyHat rotasyonu otomatik olarak ele alıyor mu?
Evet. ProxyHat Gateway (gate.proxyhat.com:808080) aracılığıyla her istek, konut havuzundan farklı bir IP alır. Sıkı seanslar için, kimliklerinize bir seans parametre ekleyin. Hiçbir manuel IP listesi yönetimi gerekli değildir.






