Scarnox · Blog

Engellenmeden web scraping yapmak: kod örnekleriyle pratik rehber

Scraping sırasında engellenmek genellikle üç şeyden birini anlatır: çok fazla isteği çok hızlı gönderdiniz, istemciniz bir tarayıcıya ya da bilinen bir bota hiç benzemedi ya da IP adresiniz sitenin daha az güvendiği bir listede. Üçünü de birkaç alışkanlıkla azaltabilirsiniz: bloğu erken fark edin, site geri ittiğinde yavaşlayın, tutarlı ve dürüst bir kimlik tutun ve proxy'leri yalnızca uygun olduğu yerlerde kullanın. Bu rehber her birini çalışan kodla anlatır. Yalnızca taramanıza izin verilen siteler için kullanın.

Bir bloğu tanıyın

Bir blok her zaman bir hata sayfası gibi görünmez. Şunlara dikkat edin:

Her başarısızlık için durum kodunu ve gövdenin kısa bir örneğini loglayın. Loglarınızda göremediğiniz bir blok, düzeltemeyeceğiniz bir bloktur.

Yeniden denemelerle geri çekilin

Site "yavaşla" dediğinde, kodunuz bir nebze değil, belirgin şekilde yavaşlamalıdır. Deneme sayısında bir sınır olan üssel geri çekilme (exponential backoff) standart yaklaşımdır. Site gönderdiğinde Retry-After değerine de uyar:

import time
import requests

session = requests.Session()
session.headers.update({
    "User-Agent": "ExampleBot/1.0 (+https://example.com/bot)",
    "Accept-Language": "en-US,en;q=0.9",
})

def polite_get(url: str, max_attempts: int = 4) -> requests.Response:
    delay = 2.0
    resp = None
    for _ in range(max_attempts):
        resp = session.get(url, timeout=30)
        if resp.status_code not in (429, 503):
            return resp
        retry_after = resp.headers.get("Retry-After", "")
        wait = float(retry_after) if retry_after.isdigit() else delay
        time.sleep(wait)
        delay *= 2
    return resp  # hâlâ engelli: son yanıtı çağıran taraf ele alsın

resp = polite_get("https://example.com/products?page=1")
print(resp.status_code, len(resp.text))

Fonksiyonun yapmadıklarına dikkat edin. 403'ü yeniden denemez ve bir engeli aşmak için kimlikler arasında dönmez. 403, çözülecek bir bulmaca değil, durma kararıdır.

Bir bloğu adım adım teşhis edin

Bir çalıştırma başarısız olmaya başladığında, başka bir şeyi değiştirmeden önce şu kontrolleri yapın:

  1. İlk başarısız URL'ye ve durum koduna bakın. Bir blok genellikle rastgele değil, belirli bir noktada başlar.
  2. İlk başarısızlıktan önceki dakikalardaki istek hızını karşılaştırın. Bir patlama en yaygın nedendir.
  3. Hatanın tek bir yola, tek bir bölüme ya da günün tek bir saatine bağlı olup olmadığını kontrol edin.
  4. Aynı URL'yi normal bir tarayıcıda elle bir kez açın. Tarayıcı yüklüyorsa fark istek örüntünüzdedir. Tarayıcı da engelleniyorsa, site şimdilik size sayfayı sunmayı bırakmıştır.
  5. Ancak bundan sonra kodu değiştirin. Önce yavaşlayın, ikinci olarak geri çekilmeyi ekleyin, en son kimliğinizi gözden geçirin.

Birçok şeyi aynı anda değiştirmek, hangisinin yardımcı olduğunu bilmeyi imkânsız kılar.

Tutarlı ve dürüst bir kimlik koruyun

Scraper'lar, kimlikleri istekler arasında değiştiğinde ya da trafiğin geri kalanıyla eşleşmediğinde engellenir. Tek bir oturum ve net bir User-Agent en basit kararlı kimliktir. Botunuza bir ad verin, bir iletişim bağlantısı ekleyin ve yalnızca normal bir istemcinin göndereceği başlıkları gönderin. Pek çok farklı ziyaretçiye benzemek için User-Agent'ları değiştirmek bir kaçınma biçimidir ve bloğu azaltmak yerine artırma eğilimindedir.

Bir site tarayıcılara ve düz HTTP istemcilerine farklı içerik sunuyorsa, o sayfalar için gerçek bir tarayıcı kullanın ve aynı hız sınırını koruyun. Bu meşru bir yoldur ve istek örüntüsünü makul tutar.

Proxy'leri dikkatle kullanın

Proxy, bir isteğin geldiği adresi değiştirir. Meşru ihtiyaçlar için bir araçtır; örneğin test etmeye izniniz olan bir sitede belirli bir bölgeden test yapmak ya da yükü kendi altyapınız arasında dağıtmak. Sitenin size koyduğu bir limiti aşmanın yolu değildir. Proxy formatı, proxy görev tiplerinin kullandığı formattır:

proxies = {
    "http": "http://user:pass@proxy.example.net:8000",
    "https": "http://user:pass@proxy.example.net:8000",
}
resp = session.get("https://example.com/products", proxies=proxies, timeout=30)

Proxy tipini seçmek ayrı bir sorudur ve residential ve datacenter proxy karşılaştırmasında ve scraping için rotating proxy rehberinde ele alınır.

Blok bir captcha'ya dönüştüğünde

Bazı siteler bir hız sorununa sert bir engelleme yerine bir captcha ile yanıt verir. Mantıklı sıra şudur: dur, yavaşla, kuralları yeniden kontrol et ve ancak bundan sonra bir çözümü değerlendir. PopularCaptcha widget'ları için Scarnox'un canlı API'si, form alanında göndermeniz gereken h-captcha-response token'ını döndürür. Diğer captcha tipleri için canlı listeyi kontrol edin; reCAPTCHA, Cloudflare Turnstile, GeeTest, AWS WAF ve Arkose desteği yakında geliyor. Ayrıntılı rehber web scraping captcha'ları sayfasındadır.

Bir sitede bloklar görmeye başladıysanız, sebep neredeyse her zaman istek örüntüsüdür. Scraping'de captcha'lardan kaçınmak bunları önleyen alışkanlıkları anlatır.

Sorumlu scraping

Sonraki adımlar