Web scraping süreçlerinde karşılaşılan HTTP 403 Forbidden yanıtı, hedef sunucunun isteğinizi anladığını ancak kaynağa erişimi kasten engellediğini belirtir. Klasik 401 Unauthorized hatasından farklı olarak 403, eksik bir oturum bilgisinden ziyade doğrudan bir bot koruma katmanına (WAF), hatalı istek başlıklarına veya güvenilmez bir IP adresine takıldığınızı gösterir.

Hızlı Çözüm / Özet Adımlar (TL;DR)

403 hatasını hızlıca bertaraf etmek için sırasıyla şu adımları kontrol edin:

  1. User-Agent Bilgisini Güncelleyin: python-requests/2.x veya boş User-Agent değerlerini güncel bir masaüstü tarayıcı dizesiyle değiştirin.
  2. Kritik Başlıkları Ekleyin: Yalnızca User-Agent yetmez; Accept-Language, Accept-Encoding, Sec-Ch-Ua ve gerekiyorsa Referer başlıklarını eksiksiz tanımlayın.
  3. TLS Parmak İzinizi (JA3/JA4) Gizleyin: Standart requests kütüphanesi yerine tarayıcı TLS el sıkışmasını taklit eden curl_cffi veya tls-client kütüphanelerine geçin.
  4. IP Adresinizi ve Hızınızı Değiştirin: Veri merkezi (datacenter) IP'leri yerine kaliteli konut tipi (residential) proxy havuzları kullanın ve istek aralıklarına rastgele gecikmeler (jitter) ekleyin.
  5. Headless Browser ile Dinamik Koruma Aşımı: Cloudflare Turnstile veya DataDome gibi gelişmiş JavaScript meydan okumalarında Playwright ya da Puppeteer altyapısını stealth eklentileriyle birlikte devreye alın.

403 Forbidden Hatasının Arkasındaki Tespit Vektörleri

Modern web siteleri scraping araçlarını tek bir kritere göre engellemez. Güvenlik duvarları gelen her HTTP paketini çok katmanlı bir filtreleme sürecinden geçirir. 403 hatası alıyorsanız, aşağıdaki vektörlerden en az birine takılıyorsunuz demektir.

İstemci İsteği
   ├── 1. IP & İtibar Analizi (Datacenter IP, Rate Limit) ────> 403 Forbidden
   ├── 2. TLS El Sıkışması (JA3 / JA4 Fingerprint) ───────────> 403 Forbidden
   ├── 3. HTTP Başlık Kontrolü (User-Agent, Sec-Ch-Ua) ────────> 403 Forbidden
   └── 4. JS Çalıştırma / Davranışsal Analiz (WAF) ───────────> 403 Forbidden

1. Eksik veya Şüpheli HTTP İstek Başlıkları

Sunucu tarafındaki ilk filtre başlık analizidir. Birçok popüler HTTP kütüphanesi (Python urllib, requests, Node.js axios), istemci kimliğini açıkça belli eden varsayılan User-Agent değerleri gönderir. Sunucu, User-Agent değerinde kütüphane adı gördüğü anda isteği 403 ile düşürür.

Bunun yanı sıra modern tarayıcılar (Chrome, Firefox, Safari) her istekte Sec-Fetch-* ve Sec-Ch-Ua gibi "Client Hints" başlıkları taşır. Bir istekte hem Windows 11 Chrome User-Agent'ı bulunup hem de bu başlıklar yer almadığında, WAF sistemleri aradaki tutarsızlığı anında tespit eder.

2. TLS / SSL Parmak İzi (JA3 ve JA4)

En yaygın yanılgılardan biri, doğru başlıklar eklendiğinde botun tarayıcı gibi görüneceğini düşünmektir. Ancak TLS el sıkışması (handshake), HTTP başlıkları sunucuya iletilmeden önce gerçekleşir.

Sunucular, istemcinin desteklediği şifreleme paketleri (cipher suites), TLS uzantıları ve el sıkışma sırasını analiz ederek istemcinin bir OpenSSL implementasyonu mu yoksa gerçek bir Chromium motoru mu olduğunu tespit eder. Python requests kütüphanesi doğrudan OpenSSL tabanlı urllib3 kullandığı için oluşturduğu JA3 parmak izi standart tarayıcılardan tamamen farklıdır. Cloudflare veya Akamai arkasındaki siteler, başlıklarınıza bakmaksızın sırf bu TLS uyuşmazlığı nedeniyle 403 döndürür.

3. IP İtibarı ve ASN Blokajları

AWS, DigitalOcean, Hetzner veya Google Cloud gibi büyük veri merkezi sağlayıcılarına ait IP blokları, kurumsal WAF kurallarında varsayılan olarak düşük itibar puanına sahiptir. Bu IP'lerden gelen istekler, normal şartlarda hiçbir bot davranışı sergilemese dahi otomatik olarak CAPTCHA veya 403 ile karşılanır. Ayrıca aynı IP üzerinden saniyede onlarca istek gönderildiğinde devreye giren rate limiting kuralları doğrudan 403 Forbidden üretir.

4. Dinamik JavaScript Kontrolleri ve Bot Yönetimi

Hedef web sitesi ilk HTTP GET isteğinde doğrudan içerik döndürmek yerine bir "challenge" sayfası sunabilir. Bu sayfa istemcinin JavaScript motorunu, Canvas/WebGL parmak izini, ekran çözünürlüğünü ve fare hareketlerini kontrol eder. Düz bir HTTP istemcisi JavaScript çalıştıramadığı için bu challenge'ı çözemez ve sunucu oturumu onaylamayarak sonraki tüm istekleri 403 ile kilitler.


403 Forbidden Hatasını Çözmek İçin Uygulama Adımları

1. HTTP Başlık Setini Tarayıcı Seviyesine Getirin

İsteklerinize yalnızca sahte bir User-Agent eklemek yeterli değildir. İstek gövdesinde tam bir tarayıcı ortamının yaydığı başlık sinyallerini eksiksiz simüle etmeniz gerekir.

Özellikle şu başlıkların varlığı ve değerleri kritik önem taşır:

  • User-Agent: Güncel, yaygın bir masaüstü tarayıcı dizesi.
  • Accept: Tarayıcının kabul ettiği MIME türleri (text/html,application/xhtml+xml...).
  • Accept-Language: Doğal dil dizilimi (örn. tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7).
  • Sec-Ch-Ua: Tarayıcı motoru ve sürüm bilgisi.
  • Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site: İsteğin nereden ve nasıl başlatıldığını belirten tarayıcı güvenlik başlıkları.

2. TLS Taklit Eden İstemcilere Geçiş Yapın

Python ekosisteminde standart requests yerine tarayıcı düzeyinde TLS parmak izi üreten kütüphaneler kullanılmalıdır. Bu alanda en kararlı çözüm curl_cffi kütüphanesidir. curl_cffi, tarayıcıların TLS parmak izlerini bayt düzeyinde taklit edebilir.

from curl_cffi import requests

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
    "Accept-Language": "tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7",
    "Sec-Ch-Ua": '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"',
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": '"Windows"',
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
}

# impersonate="chrome124" parametresi TLS/JA3/JA4 imzasını Chrome ile birebir eşler
response = requests.get(
    "https://ornek-hedef-site.com/veri",
    headers=headers,
    impersonate="chrome124",
    timeout=10
)

print(response.status_code)

impersonate argümanı tanımlandığında, sunucuya giden TLS Client Hello paketi gerçek bir Chrome tarayıcısının paketinden ayırt edilemez. Bu yöntem, Cloudflare WAF kullanan birçok sitede 403 engelini doğrudan çözer.

3. Proxy Stratejisini Değiştirin: Residential Havuzlar

Veri merkezi IP'leri ile kazıma yapıyorsanız, başlıklarınız ne kadar kusursuz olursa olsun 403 engeline takılma ihtimaliniz yüksektir.

  • Statik Datacenter IP'leri: Güvenlik katmanı bulunmayan basit siteler için uygundur.
  • Residential (Konut Tipi) Proxy: Gerçek ev interneti bağlantılarından (Türk Telekom, Vodafone, Comcast vb.) sağlanan IP'lerdir. WAF sistemleri bu IP'leri doğrudan engelleyemez çünkü gerçek kullanıcıları engelleme riski doğar.
  • Döndürme (Rotation) Kuralı: İdeal senaryoda her istekte veya her birkaç istekte bir IP değiştiren "backconnect" proxy sistemleri tercih edilmelidir. Oturum (session) bazlı işlemler yapılıyorsa, aynı IP'nin belirli bir süre korunduğu "sticky session" yaklaşımı uygulanmalıdır.

4. Otomasyon Tespiti Yapılan Headless Tarayıcıları Gizleyin

Playwright veya Selenium kullanırken 403 hatası alıyorsanız, tarayıcınızın navigator.webdriver bayrağı aktif demektir. Bu bayrak hedef sitedeki güvenlik scriptleri tarafından ilk milisaniyede okunur.

Playwright için playwright-stealth, Puppeteer için puppeteer-extra-plugin-stealth kütüphanelerini kullanarak şu değişkenleri gizleyin:

  • navigator.webdriver değerinin false veya undefined yapılması,
  • Chrome DevTools Protocol (CDP) sızıntılarının kapatılması,
  • Masaüstü donanımına ait sahte Canvas/WebGL grafik çıktılarının verilmesi.

403 Hatalarını Ayıklama (Debugging) İş Akışı

Sorunun hangi katmanda olduğunu anlamadan rastgele değişiklikler yapmak zaman kaybettirir. Tespiti izole etmek için aşağıdaki adımları sırayla izleyin:

Test Aşaması Yapılacak İşlem Hatanın Anlamı
Tarayıcı Doğrulaması Normal bir Chrome sekmesinde URL'yi açın. Tarayıcıda da 403 geliyorsa IP adresiniz veya coğrafi konumunuz doğrudan engellenmiştir.
cURL Testi curl -I https://hedefsite.com komutunu çalıştırın. Tarayıcı açılıyor ama cURL 403 veriyorsa sorun başlıklar veya TLS düzeyindedir.
Gelişmiş Taklit curl_cffi ile Chrome taklidi yaparak istek atın. Başarılı olursa sorun kesinlikle TLS fingerprint (JA3/JA4) uyuşmazlığıdır.
Proxy Testi İsteği residential bir proxy üzerinden yönlendirin. Başarılı olursa önceki IP adresinizin itibar puanı düşüktür veya ASN blokajı vardır.

Sıkça Sorulan Sorular

Python requests kütüphanesinde 403 hatası neden bu kadar sık yaşanır?

Python requests, istekleri varsayılan olarak python-requests/x.x.x User-Agent değeriyle ve standart OpenSSL TLS parametreleriyle iletir. Modern güvenlik duvarları bu varsayılan başlığı ve OpenSSL tabanlı TLS el sıkışmasını bot olarak sınıflandırarak bağlantıyı anında 403 Forbidden koduyla keser.

User-Agent dizesini değiştirmek 403 hatasını çözmek için neden yetersiz kalır?

User-Agent yalnızca bir HTTP başlığıdır; oysa WAF sistemleri istek başlıklarına gelmeden önce TLS seviyesindeki şifre paketlerini (JA3/JA4 parmak izini) denetler. Ayrıca tarayıcıya özgü Sec-Ch-Ua gibi modern Client Hints başlıkları eksik olduğunda sunucu gelen isteğin sahte olduğunu kolayca anlar.

Headless tarayıcı kullanırken alınan 403 hatası nasıl aşılır?

Headless tarayıcılar varsayılan olarak navigator.webdriver = true parametresiyle çalışır ve özel CDP izleri bırakır. Bu tespiti aşmak için playwright-stealth veya puppeteer-extra-plugin-stealth kullanarak bu bayrakları gizlemeli ve tarayıcı profiline gerçekçi ekran çözünürlüğü, dil ve donanım parametreleri tanımlamalısınız.

Ücretsiz proxy listeleri web scraping sırasındaki 403 hatalarını engeller mi?

Hayır, ücretsiz açık proxy'ler siber güvenlik firmaları ve WAF sağlayıcıları tarafından anlık olarak izlenir ve kara listeye alınır. Bu tür IP'ler genellikle çok yüksek oranda 403, 429 ve CAPTCHA engeline yol açar; bu nedenle scraping projelerinde konut tipi (residential) veya temiz ISP proxy altyapıları kullanılmalıdır.