Bir Orta Gövde Takılması, Common requests Timeout Handler’ını Aşıyor

Son güncelleme: August 17, 2026
Bir Orta Gövde Takılması, Common requests Timeout Handler’ını Aşıyor
AI Özeti
Mevcut requests kodunda hata mı arıyorsunuz? Yönlendirme varsayımlarını, yalnızca requests.exceptions.Timeout yakalayıp gövde ortasında takılmayı da kapsadığını sanan handler’ları ve charset olmadan gelen yanıtları .text ile tüketen kodları gözden geçirin. Mekanik olarak httpx’e mi geçiyorsunuz? İstisna namespace’lerini httpx.TimeoutException ya da daha dar aşama sınıflarına çevirin, follow_redirects’i açıp açmayacağınıza karar verin ve kod çözme varsayımlarını yeniden test edin. Mevcut requests handler’ı zaten gösterilen gövde ortası vakasını kaçırıyor; geçiş bu özel hatayı üretmez. Çok sayıda URL çekecek yeni bir şey mi yazıyorsunuz? AsyncClient ve ayrı connect, read, write, pool zaman aşımı gerektiğinde httpx iyi bir adaydır.

Herkesin yazdığı koruma kodunu yazın:

try:
    r = requests.get(url, timeout=0.5)
except requests.exceptions.Timeout:
    retry()

Bunu, durum satırını ve başlıkları hemen gönderip ardından gövde gelmeden beklemeye geçen bir sunucuya yönlendirin. Okuma zaman aşımına uğrar. Ama koruma devreye girmez. Ortaya çıkan istisna ConnectionError olur ve ConnectionError, Timeout sınıfının alt sınıfı değildir.

Aynı bekleme durumunda httpx ReadTimeout yükseltir; bu da bir TimeoutException’dır ve eşdeğer koruma bunu yakalar.

Scraper’ları bozan farklar açısından httpx’in requests’ten nasıl ayrıldığını incelemeye başladım; async hakkında yazacağımı düşünüyordum. Meğer async, listedeki en az ilginç konuymuş.

Ne test ettim ve nasıl

Yerel bir fixture sunucusuna karşı sekiz farklı deneme yaptım; çünkü bir istemcinin ne yaptığını söylemesi, gerçekten ne yaptığına dair kanıt değildir. Sunucu TCP bağlantılarını sayıyor — herhangi bir istek satırı ayrıştırılmadan önce, kabul edilen her soket için bir kez artıyor — ve gerçekte çekilen yolları izliyor. Bağlantı yeniden kullanımı ve yönlendirme takibi tamamen hattın üzerindeki davranışlardır; bunlar da hattın üzerinde doğrulanır.

httpx 0.28.1 (http2 eklentisiyle), requests 2.34.2, Python 3.14.2, macOS arm64. İkisi de aynı temiz virtualenv içinde kuruldu; böylece biri diğerinden hiçbir iz taşımaz. Ham çıktı: httpx-probes.json.

İlk çalıştırmadan önce harness’e altı tahmin girildi ve sonrasında da aynı kaldı. Üçü tuttu, ikisi yanlış çıktı, biri aklımdaki senaryoda doğruydu ama asıl önemli olanı kaçırdı. Hesap dökümü prediction-scorecard.json içinde.

Sizi hazırlıksız yakalayan varsayılanlar

Ölçülen sonuç grafiği: İstemciler arasında farklı olan varsayılanlar

Davranışrequests 2.34.2httpx 0.28.1
Varsayılan olarak yönlendirmeleri takip ederevethayır
Modül düzeyindeki çağrı bağlantı yeniden kullanırhayırhayır
Başlıklardan önce takılmaReadTimeoutReadTimeout
Gövde ortasında takılmaConnectionErrorReadTimeout
Charset belirtilmemişseISO-8859-1utf-8
HTTP/2yokisteğe bağlı, çalışır
Ayrı connect/read/write/pool zaman aşımıhayırevet

Yönlendirmeler, soket yeniden kullanımı, istisna sonuçları, kod çözme ve protokol pazarlığı prob’larda gözlemlendi. Zaman aşımı API yapısı ve requests’te HTTP/2 bayrağı olmaması ise API yetenekleri açısından gözlemdir. httpx-probes.json.

Bu satırlardan üçü, kodunuzu değiştirirken sessizce davranış değiştirecek.

Yönlendirmeler: varsayılan olarak kapalı ve sunucu bunu kanıtlıyor

/ok ile biten dört adımlı bir yönlendirme zinciri:

İstemciSunucunun gördüğüDönen durum
requests5 istek200
httpx1 istek302
httpx, follow_redirects=True5 istek200

Beş sayısı, dört ara adım artı varış noktasını ifade ediyor. Benim tahminim dört demişti; bu, kontrol etmeden yaptığım bir aritmetikti. Yön doğruydu, sayı burada sessizce metne gömülmek yerine düzeltilmiş durumda.

Bu, httpx’in belgelenmiş davranışıdır ve savunulabilir bir tasarımdır — çünkü yönlendirme, çağıranın bilmek isteyebileceği bir şeydir. Ancak bu aynı zamanda, bir geçişte hiçbir hata vermeden en kolay bozulan şeydir. Kodunuz 302 alır, response.text boştur, ayrıştırıcınız hiç satır bulamaz ve loglarınız 200 OK der… aslında 302 demektedir ve requests kullanırken kimse durum koduna bakmadığı için bunu fark eden olmaz.

Zaman aşımı bulgusu: yanlış tahmin ettiğim kısım

httpx’in, başarısız olan aşamayı isimlendireceğini; requests’in ise ikisini tek sınıfta belirsizleştireceğini tahmin etmiştim. Tam tersi çıkıyor.

Resmî kaynak: Requests timeout documentation.

Sistem diyagramı: Timeout nereye düşüyor

Resmî kaynak: HTTPX timeout documentation.

Takılma anırequestshttpx
Durum satırından önceReadTimeoutReadTimeout
Başlıklar geldikten sonra, gövde ortasındaConnectionErrorReadTimeout

httpx her iki durumda da aynı, doğru adı verir. requests ise bunları ayırır — ve bu ayrım, retry kodunun dayandığı sınırın tam üstündedir.

Sonuç, sınıf hiyerarşisine bakarak çıkarılmış bir yorum değil. Koruma kodunu gerçekten çalıştırdım:

Takılma anıexcept requests.exceptions.Timeoutexcept httpx.TimeoutException
Durum satırından önceyakalaryakalar
Gövde ortasındaConnectionError olarak kaçaryakalar

timeout-retry-guard.json. requests.exceptions.ConnectionError, requests.exceptions.Timeout sınıfının alt sınıfı değildir; httpx.ReadTimeout ise httpx.TimeoutException sınıfının alt sınıfıdır.

requests’in istisna mesajı, ConnectionError içinde Read timed out. der. Yani kütüphane ne olduğunu bilir. Sadece bunu tip sistemine anlatmaz; oysa except bloğunuzun baktığı yer tam da tip sistemidir.

Ölçülen durum spesifiktir: başlıklar gelir, ardından gövde ilerlemesi okuma zaman aşımını aşacak kadar durur. Zaman aşımı penceresi içinde parça parça veri gelmeye devam eden bir yanıt — örneğin bilerek tasarlanmış bir stream — farklı davranabilir; burada test edilmedi.

Bağlantı havuzu: farkın tamamı istemci API’sinde

On adet GET, dört farklı şekilde, soketler sunucu tarafında sayıldı:

NasılAçılan soket sayısı
httpx.get() × 1010
requests.get() × 1010
httpx.Client()1
requests.Session()1

Bu sonuçlar aynı ve özellikle vurgulanmalı; çünkü bu ikili hakkında en yaygın şehir efsanesi, httpx’in havuzlama yaptığı, requests’in yapmadığıdır. Aslında modül düzeyinde ikisi de havuzlamaz. Havuzlama, istemci nesnesi üzerinden yapılır. Bugün requests.get()’i döngü içinde çağırıyorsanız, httpx.get()’e geçmek soket trafiğiniz açısından hiçbir şeyi değiştirmez.

Sistem diyagramı: Havuzlama istemcide yaşar

HTTP/2 açıktır ve ekstra paket gerektirir

Ek dosyada kaydedilmiş tek bir herkese açık HTTP/2 endpoint’ine karşı:

Resmî kaynak: RFC 9113: HTTP/2.

İstemciAnlaşma sonucu
httpx.Client(http2=True)HTTP/2
httpx.Client(http2=False)HTTP/1.1
requestsHTTP/1.1, bayrak yok

httpx[http2] ekstra paketine ihtiyacınız var. Sade pip install httpx komutunun, arka planda sessizce 1.1 pazarlayan bir istemci bırakacağını varsaydım ve bunu yazmadan önce kontrol ettim:

ImportError: Using http2=True, but the 'h2' package is not installed.
Make sure to install httpx using `pip install httpx[http2]`.

Hata, tek bir istek atılmadan önce Client oluşturma aşamasında yükselir ve mesajda çözüm açıkça yazılıdır. Bu, bu hatanın iyi versiyonudur; ben ise tersini düşünmüştüm (http2-extra-missing.json).

Bu prob, o endpoint’te protokol pazarlığının başarıyla tamamlandığını gösterir. Bir scraping hız avantajı kanıtlamaz; eşleştirilmiş bir HTTP/1.1 iş yükü test edilmedi.

Ardışık ve eşzamanlı fixture verimi

0.3 saniye uyuyan bir endpoint’e karşı yirmi istek:

ModToplam süreSoket
Senkron, tek Client6.138 s1
Async, tek AsyncClient0.357 s20

Eşzamanlı çalıştırma 0.357 saniyede tamamlandı; ardışık çalıştırma ise 6.138 saniye sürdü. Ancak bu sırada yirmi bağlantı açtı; senkron istemci ise tek bağlantıyı yeniden kullandı. Yani deney, kütüphane hızından çok yürütme modelini ve etkili eşzamanlılığı değiştiriyor.

Sayıyı dürüstçe çerçevelemek budur. Bu, bilerek yavaş bir endpoint’e karşı eşzamanlılığın ölçümüdür; httpx’in saf hız ölçümü değildir. Çalışan bir async hikâyesi olan her istemci benzer bölgede sonuç verir; hızlı bir endpoint’te ise fark büyük ölçüde kaybolur.

Tahmin etmeyi akıl edemediğim charset vakası

Başlığında yalan söyleyen bir yanıtın — utf-8 baytları üzerinde charset=iso-8859-1 — iki tarafta da aynı bozuk metni üreteceğini tahmin etmiştim. Öyle de oluyor. İkisi de, kaynakta Café Ubersetzung — naïve résumé yazmasına rağmen Café Ubersetzung â naïve résumé döndürüyor.

Tahmin edemediğim ama önemli olan vaka şu:

Yanıtrequests nasıl çözerhttpx nasıl çözer
charset=utf-8, utf-8 baytlarıdoğrudoğru
charset=iso-8859-1, utf-8 baytlarıbozuk karakterlerbozuk karakterler
hiç charset yokbozuk karakterlerdoğru

requests, başlık hiçbir şey söylemediğinde ISO-8859-1’e döner; httpx ise varsayılan olarak utf-8 kullanır. Charset’i olmayan fixture’da, .text üzerinden farklı çözümlenmiş metin üretmeleri bu yüzden oldu; response.content kullananlar ise aynı ham baytları görür.

Bellek, çünkü ölçmesi ucuz

Tepe RSS, /usr/bin/time -l, her hücre için tek, yeni bir süreç:

Hücrerequestshttpx
Sadece import36.0 MiB30.6 MiB
Import + bir GET35.8 MiB40.7 MiB

Bunlar tek süreç anlık görüntüleridir ve requests’in bir GET sonrası değerinin import-only değerinden biraz düşük çıkması, ölçüm gürültüsünü gösterir. Yönlü bir bellek sonucu çıkarmak için yeterli değildir; tekrarlı örnekler ve aralıklar gerekir.

Seçim yaparken bunun anlamı

Mevcut requests kodunda hata mı arıyorsunuz? Yönlendirme varsayımlarını, yalnızca requests.exceptions.Timeout yakalayıp gövde ortasında takılmayı da kapsadığını sanan handler’ları ve charset olmadan gelen yanıtları .text ile tüketen kodları gözden geçirin.

Mekanik olarak httpx’e mi geçiyorsunuz? İstisna namespace’lerini httpx.TimeoutException ya da daha dar aşama sınıflarına çevirin, follow_redirects’i açıp açmayacağınıza karar verin ve kod çözme varsayımlarını yeniden test edin. Mevcut requests handler’ı zaten gösterilen gövde ortası vakasını kaçırıyor; geçiş bu özel hatayı üretmez.

Çok sayıda URL çekecek yeni bir şey mi yazıyorsunuz? AsyncClient ve ayrı connect, read, write, pool zaman aşımı gerektiğinde httpx iyi bir adaydır. Bu aşamalar, beklemenin nerede olduğunu söyler — bağlantı kurulumu, yanıt gövdesinin ilerlemesi, istek yüklemesi veya yerel havuzdan kaynak bekleme — ama uzak sunucunun neden öyle davrandığını değil.

Küçük ve senkron bir şey mi yazıyorsunuz? requests gayet uygundur ve her yerdedir. Geçiş yapma nedeni hız değildir.

Hangisini seçerseniz seçin, modül düzeyindeki fonksiyon yerine istemci nesnesini kullanın. Bu listedeki her iki kütüphane için de doğrudan kazanım sağlayan tek değişiklik budur.

Yönetilen bir API nerede devreye girer

Yukarıdakilerin hepsi fetch katmanıdır ve fetch katmanı kolay kısımdır. Bunların hiçbiri JavaScript render etmez, anti-bot engelini çözmez ve HTML’yi istediğiniz satırlara dönüştürmez.

Yazar notu: Thunderbit bizim URL girip render alma ve çıkarım için yönetilen seçeneğimizdir. Bu HTTP client harness’inde test edilmedi. Bu kategoriyi yalnızca sayfa alma veya yapılandırılmış veri çıkarımı sorununu çözmek istiyorsanız düşünün; HTTP istemci semantiği için değil.

Sıradan sayfaları çekip kendiniz ayrıştırıyorsanız, iki istemci de hâlâ kapsam içindedir. Yönetilen servis, bunu satın almak mı inşa etmek mi sorusunun ayrı bir kararıdır; bu kütüphaneler arasında seçim yapmaya dair kanıt değildir.

Daha geniş alan için web scraping API roundup barındırılan seçenekleri, open-source scraper pillar ise kendi barındırdıklarınızı kapsıyor.

Web Veri Çıkarımı için Thunderbit’i Deneyin

Sonuç

Test edilen koşullar altında, async eşzamanlılık, aşamaya özel zaman aşımı ve UTF-8 yedeği gerektiren yeni bir Python fetch katmanı için benim varsayılanım httpx olur. requests ise, olgun senkron kodda geçiş riski bu faydaları geride bırakıyorsa hâlâ mantıklıdır. Proxy’ler, retry politikaları, TLS parmak izi, streaming, upload’lar ve gerçekçi ağ değişkenliği test edilmedi; dolayısıyla bu, evrensel bir scraping istemcisi sıralaması değildir.

Dikkatli olma nedeni redirect varsayılanıdır ve bu, tam da iyi bir tasarım kararı olduğu için gerçek bir risktir. Açıklık gizliden iyidir; ta ki gizli olan şey, zaten ürettiğiniz kodda taşıyıcı bir unsur olana kadar.

Önceden kaydedilmiş skor kartı üç doğru tahmin, iki yanlış tahmin ve bir eksik tahminle bitti. En faydalı düzeltme, gövde ortası istisna sınıfıydı; kararın geri kalanı skor kartı anlatısından değil, gözlenen davranıştan gelmeli.

Web Veri Çıkarımı için Thunderbit’i Deneyin Get Started Free

SSS

httpx gerçekten yönlendirmeleri takip etmiyor mu? Varsayılan olarak hayır. Sunucu, dört adımlı bir zincir için bir istek saydı ve yanıt 302 olarak döndü. Her çağrıda follow_redirects=True geçin ya da bunu bir kez Client üzerinde ayarlayın. Bu davranış belgelenmiştir ve kasıtlıdır; yine de geçişte sessizce en kolay bozulan şeydir, çünkü hata bir istisna değil boş parse sonucudur.

except requests.exceptions.Timeout gerçekten yeterli değil mi? Başlıkları gönderdikten sonra takılan bir sunucu için yeterli değil. O durumda ConnectionError yükselir ve bu sınıf Timeout alt sınıfı değildir; dolayısıyla koruma onu kaçırır — bu çıkarım değil, doğrudan gösterilmiş bir durumdur. Her ikisini de yakalamak istiyorsanız requests.exceptions.RequestException yakalayın; bunun zaman aşımı olmayan şeyleri de yakalayacağını kabul edin.

httpx, requests’ten gerçekten daha hızlı mı? Tek seferlik isteklerde anlamlı biçimde hayır — zaten bunun için tasarlanmadı. Bu testteki 17.2× fark, 0.3 saniyelik bir endpoint’e karşı yirmi eşzamanlı isteğin ölçümüdür; yani eşzamanlılık ölçümüdür. İş yükünüz ardışık ise hız artışı beklemeyin; bunun yerine varsayılanlara göre seçim yapın.

http2 ekstra paketine ihtiyacım var mı? Sadece HTTP/2 istiyorsanız. http2=True verip bunu yüklemezseniz, httpx Client oluştururken ImportError yükseltir ve size httpx[http2] yüklemenizi söyler. Sessiz bir düşüş yok, endişe edecek bir şey yok. Ben bir düşüş bekledim ve bunu yazmadan önce kontrol ettim.

Burada ne test edilmedi? Scraping açısından çok önemli olan ve ayrı bir harness gerektiren proxy davranışı. Retry’lar — httpx’te yerleşik retry mantığı yoktur, requests bunu urllib3 üzerinden alır; dolayısıyla adil bir karşılaştırma aslında iki retry kütüphanesinin karşılaştırmasıdır. Anti-bot sistemlerinin gerçekten baktığı eksen olan TLS parmak izi; iki kütüphane de bunu çözmez. Streaming ve dosya yüklemeleri. Ayrıca buradaki her şey tek makine, tek Python sürümü ve sekiz prob’un altısında localhost üzerinde çalıştı — fixture sunucusundan alınan gecikme sayıları ağınızın değil, tasarımın ölçümüdür.

Ke
Ke
Thunderbit’ta CTO | Kıdemli Veri Bilimci ve ML Uzmanı Makine öğrenimi ve veri bilimi alanında yaklaşık on yıllık deneyime sahip olan Ke Shen, Columbia University mezunu ve Walmart Labs’te eski Kıdemli Veri Bilimci’dir. Python, R, Java ve İstatistik konularında derin ve meslektaşları tarafından tanınan uzmanlığıyla, karmaşık yapay zekâ algoritmalarını teoriden üretim düzeyinde mimariye taşıma konusunda sahada test edilmiş içgörüler paylaşır.
İçindekiler
Thunderbit · AI web veri ajanı

Herhangi bir sayfadan 1 tık içinde veri çıkar

250.000+ kullanıcı tarafından güveniliyor
ücretsiz plan mevcut
Web sayfasından tabloya
İhtiyacını anlat — Thunderbit’in AI Ajanı bunu çeker ve Excel, Google Sheets, Airtable veya Notion’a aktarır. Başlamak ücretsiz.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week