httpx, çoğu yeni Python projesinin requests’i yetersiz bulmaya başladığında tercih ettiği HTTP istemcisidir; bunun başlıca nedeni, senkron ve asenkron kodlar için tek bir API sunmasıdır. Bu kılavuzda, bir httpx proxy'sini hem Client hem de AsyncClient'ye nasıl bağlayacağınız, dönen bir konut uç noktasında kimlik doğrulaması yapacağınız, kalıcı bir oturumu sabitleyeceğiniz, SOCKS5 ekleyeceğiniz, zaman aşımlarını ve yeniden deneme sayısını ayarlayacağınız ve karşılaşabileceğiniz üç hatayı nasıl teşhis edeceğiniz gösterilmektedir. Kılavuzu tamamladığınızda, bir proxy üzerinden yönlendirme yapan ve çıkış IP'sini kanıtlayabilen, yeniden kullanılabilir bir istemciye sahip olacaksınız.
Örnekler, httpx 0.27 veya daha yeni sürümleri hedeflemektedir. Daha eski bir sürümü kullanıyorsanız, proxies= anahtar sözcüğünün httpx 0.26 sürümünde proxy= ve mounts= olarak yeniden adlandırıldığını unutmayın; aşağıdaki tüm örneklerde güncel isimler kullanılmaktadır.
Bir httpx proxy'sini yapılandırmanın iki yolu: proxy ve mounts
httpx size basit bir seçenek ve hassas bir seçenek sunar. proxy=, tek bir URL alır ve her isteği bu URL üzerinden yönlendirir. mounts=, URL kalıplarını aktarım yöntemlerine eşler; her aktarım yöntemi kendi proxy'sini, yeniden deneme sayısını ve bağlantı sınırlarını belirleyebilir.
| Seçenek | Kapsam | Ne zaman kullanılır |
|---|
proxy="http://..." | Tüm istemci, tüm şemalar | Her şey için tek bir proxy; bu, dönen ağ geçidi kullanımında yaygın olan durumdur |
mounts={"https://": HTTPTransport(proxy=...)} | URL kalıbı başına | Şema veya ana bilgisayar başına farklı proxy'ler ya da dahili hizmetler için proxy'yi atlama |
httpx.get(url, proxy=...) | Tek bir üst düzey çağrı | Uzun ömürlü bir istemci gerektirmeyen hızlı kontroller ve komut dosyaları |
Basit biçim şu şekildedir:
import httpx
PROXY = "http://USERNAME:PASSWORD@premium-residential.geonode.com:9000"
with httpx.Client(proxy=PROXY, timeout=20.0) as client:
r = client.get("https://api.ipify.org?format=json")
print(r.status_code, r.json())
9000 numaralı bağlantı noktası, HTTP(S) dönen ağ geçididir; bu nedenle her yeni bağlantı farklı bir ev IP'si alır. Kimlik bilgileri, URL'de Basic otentikasyon olarak yer alır ve httpx, herhangi bir ek kod gerektirmeden bunları Proxy-Authorization başlığına dönüştürür.
Şema bazlı yönlendirmedeki tuzak
mounts ile http:// ve https:// hedeflerine ayrı aktarımlar atayabilirsiniz. Tuzak, proxy URL’sinin kendisinin şemasıdır. Bir https:// hedefi için httpx, proxy’ye CONNECT komutu gönderir ve ardından o tünel içinde kaynak sunucuyla TLS müzakeresi yapar. Proxy'ye yapılan bağlantı düz HTTP olduğundan, https:// mount'undaki proxy URL'si normalde http://, ile başlamalıdır, https://. ile değil. Buraya https:// yazmak, httpx'e proxy bağlantısını TLS ile sarmalamasını söyler; ancak çoğu ağ geçidi bunu desteklemez ve proxy'lerle ilgisi yokmuş gibi görünen bir el sıkışma hatası alırsınız.
import httpx
PROXY = "http://USERNAME:PASSWORD@premium-residential.geonode.com:9000"
mounts = {
"http://": httpx.HTTPTransport(proxy=PROXY),
"https://": httpx.HTTPTransport(proxy=PROXY), # http:// scheme is correct here
# internal services stay direct: mount a transport without a proxy
"all://*.internal.example": httpx.HTTPTransport(),
}
with httpx.Client(mounts=mounts) as client:
print(client.get("https://api.ipify.org?format=json").json())
Daha spesifik desenler genel olanlara göre önceliklidir; bu nedenle all://*.internal.example bağlantısı o etki alanı için proxy'yi atlarken, diğer her şey yönlendirilir.
URL’de Kimlik Doğrulama
Geonode
’daki kimlik bilgileri düz metin kullanıcı adı ve şifre olduğundan, http://user:pass@host:port
biçimindeki kullanıcı bilgisi formu tek ihtiyacınız olan şeydir. İki pratik not. İlk olarak, şifre @
, :
veya /
gibi karakterler içeriyorsa, URL'yi oluşturmadan önce urllib.parse.quote
ile yüzde kodlamasını yapın. İkinci olarak, gizli bilgileri ortam değişkenlerinden okuyarak kaynak kontrolünün dışında tutun:
import os
from urllib.parse import quote
import httpx
user = os.environ["GEONODE_USER"]
password = quote(os.environ["GEONODE_PASS"], safe="")
proxy = f"http://{user}:{password}@premium-residential.geonode.com:9000"
client = httpx.Client(proxy=proxy)
Aşağıdaki tüm kodlar, URL'yi değil kullanıcı adını genişleterek hedefleme ve oturum seçenekleri ekler; böylece aynı şablon çalışmaya devam eder.
Senkron Client
ile AsyncClient
Karşılaştırması
Asenkron istemci de aynı proxy=
anahtar sözcüğünü kullanır. Tek fark, mounts
kısmına geldiğinizde ortaya çıkar: AsyncClient
, httpx.HTTPTransport
yerine httpx.AsyncHTTPTransport
gerektirir. Senkron aktarımını asenkron istemciye aktarmak, ilk istekte hata verir.
import asyncio
import httpx
PROXY = "http://USERNAME:PASSWORD@premium-residential.geonode.com:9000"
async def fetch(client: httpx.AsyncClient, url: str) -> str:
r = await client.get(url)
r.raise_for_status()
return r.json()["ip"]
async def main() -> None:
transport = httpx.AsyncHTTPTransport(proxy=PROXY, retries=2)
async with httpx.AsyncClient(
mounts={"all://": transport}, timeout=httpx.Timeout(10.0, connect=5.0)
) as client:
urls = ["https://api.ipify.org?format=json"] * 5
ips = await asyncio.gather(*(fetch(client, u) for u in urls))
print(ips)
asyncio.run(main())
9000 numaralı bağlantı noktası her bağlantı için dönüşümlü olarak kullanıldığından, beş eşzamanlı istek genellikle birkaç farklı IP adresi yazdırır. Bu, dönüşümlü havuz için beklenen davranıştır; bunların aynı olmasını istiyorsanız, yapışkan oturum (aşağıda) kullanın.
httpx[socks] aracılığıyla SOCKS5
Bir httpx proxy kurulumunda SOCKS desteği isteğe bağlıdır. pip install "httpx[socks]" komutuyla yükleyin; bu, socksio paketini ekler, ardından şemayı değiştirin. Geonode’un SOCKS5 dönen bağlantı noktası 11000’dir:
import httpx
PROXY = "socks5://USERNAME:PASSWORD@premium-residential.geonode.com:11000"
with httpx.Client(proxy=PROXY) as client:
print(client.get("https://api.ipify.org?format=json").json())
Ekstra paket yüklenmemişse, httpx bir socks5:// proxy URL'si gördüğü anda ImportError hatası verir ve bu hatada socksio'dan bahsedilir. Sıradan veri kazıma işlemlerinde, 407 yanıtları okunabilir olduğu için HTTP bağlantı noktalarında hata ayıklama daha kolaydır.
Ortam değişkenleri ve trust_env
Varsayılan trust_env=True ayarıyla httpx, HTTP_PROXY, HTTPS_PROXY, ALL_PROXY ve NO_PROXY değerlerini okur ve bunları otomatik olarak uygular. Bu, bir iş istasyonunda kullanışlı olsa da, ortamdaki kurumsal bir proxy’nin yönlendirmenizi fark edilmeden yeniden yazdığı CI ortamlarında kafa karışıklığına yol açabilir. Proxy ayarını kodda yapıyorsanız, davranışın her yerde aynı olması için ortam aramasını devre dışı bırakmayı düşünün:
import httpx
client = httpx.Client(
proxy="http://USERNAME:PASSWORD@premium-residential.geonode.com:9000",
trust_env=False,
)
Açıkça belirtilen proxy= ayarı zaten ortam ayarlarına göre önceliklidir; trust_env=False ayarı ayrıca httpx'in SSL_CERT_FILE değerini okumasını da engeller, bu yüzden bu ayarı bilinçli bir şekilde yapın.
Zaman Aşımları ve Aktarım Düzeyinde Yeniden Denemeler
Bir proxy, bağlantı yoluna bir adım daha eklediğinden bağlantı süresi uzar ve varsayılan 5 saniyelik zaman aşımı, ev tipi çıkış sunucuları için bazen yetersiz kalabilir. httpx.Timeout, ayrı bir bağlantı sınırı içeren toplam bir süre bütçesi belirlemenize olanak tanır; HTTPTransport(retries=...) ise istek gönderilmeden önce başarısız bağlantı denemelerini yeniden dener.
import httpx
PROXY = "http://USERNAME:PASSWORD@premium-residential.geonode.com:9000"
transport = httpx.HTTPTransport(proxy=PROXY, retries=2)
timeout = httpx.Timeout(15.0, connect=8.0)
with httpx.Client(mounts={"all://": transport}, timeout=timeout) as client:
r = client.get("https://api.ipify.org?format=json")
print(r.json())
Aktarım yeniden denemeleri, bağlantı kurulurken ortaya çıkan ConnectError ve benzeri hataları kapsar. Durum kodları nedeniyle yeniden deneme yapmazlar ve baytlar gönderildikten sonra da yeniden deneme yapmazlar; bu nedenle, ağ geçidinden gelen bir 502 veya hedef siteden gelen bir 429 hatası yine de kodunuza ulaşır. Bunları, oturum kimliğini değiştirip değiştirmemeye de karar verebileceğiniz kendi küçük döngünüzde işleyin.
Geonode kullanıcı adı sözdizimi ile sabit oturumlar
Giriş, sayfa numaralandırma, indirme gibi çok adımlı işlem akışlarında her bağlantıda IP adresinin değiştirilmesi yanlış bir uygulamadır. Bu tür işlemler için httpx proxy’niz, istekler boyunca aynı çıkış IP adresini korumalıdır. Geonode bunu kullanıcı adına kodlar ve HTTP(S) sabit bağlantı noktası 10000 üzerinden sunar:
USER[-type-residential|datacenter|mix][-country-xx][-state-name|-city-name][-asn-N][-session-XXXXXXXX][-lifetime-SECONDS]
Oturum kimliği, sizin oluşturduğunuz 8 alfasayısal karakterden oluşur; geçerlilik süresi 180 ila 86400 saniye (24 saat) arasındadır. Eyalet ve şehir birleştirilemez ve asn için ülke belirtilmesi zorunludur.
import secrets
import httpx
def sticky_client(country: str = "us", lifetime: int = 600) -> httpx.Client:
session_id = secrets.token_hex(4) # 8 hex characters
username = f"USERNAME-country-{country}-session-{session_id}-lifetime-{lifetime}"
proxy = f"http://{username}:PASSWORD@premium-residential.geonode.com:10000"
return httpx.Client(proxy=proxy, timeout=httpx.Timeout(15.0, connect=8.0))
with sticky_client() as client:
first = client.get("https://api.ipify.org?format=json").json()["ip"]
second = client.get("https://api.ipify.org?format=json").json()["ip"]
print(first == second, first)
Yeni bir session_id, yeni bir IP adresi anlamına gelir; dolayısıyla "elle" döndürme işlemi, basitçe yeni bir istemci oluşturmakla eşdeğerdir. Sticky oturum sürelerini, işin gerektirdiği kadar kısa tutun.
Çıkış IP'sini Doğrulama
Yukarıdaki tüm örnekler https://api.ipify.org?format=json, adresine erişir; bu adres, kendisine ulaşan herhangi bir adres için {"ip": "..."} değerini döndürür. Bunu bir kez doğrudan çağrı (proxy olmadan) ile karşılaştırdığınızda, proxy'nin yol üzerinde olduğunu kanıtlayan iki satırlık bir hızlı test elde edersiniz. Başka herhangi bir hata ayıklama işlemine başlamadan önce bunu yapın: "httpx proxy'si çalışmıyor" şeklindeki birçok rapor, bir ortam değişkeni veya bir mount şablonunun devreye girmesi nedeniyle proxy'yi hiç kullanmamış isteklerden kaynaklanmaktadır.
407 ProxyError ve ConnectError Hatalarının Giderilmesi
Hemen hemen tüm httpx proxy sorunları üç ana hatadan kaynaklanmaktadır. Aşağıdaki tabloda her bir hatanın nedeni ve çözüm yolu belirtilmiştir.
| Belirti | İstisna | Yaygın neden | Çözüm |
|---|
| 407 yanıt durumu | httpx.ProxyError (https hedefleri için tünel kurulumu sırasında ortaya çıkar) veya http hedefleri için düz bir 407 yanıtı | Yanlış kimlik bilgileri veya ağ geçidinin reddettiği bir kullanıcı adı seçeneği | Kullanıcı adı biçimini kontrol edin; şifreyi yüzde kodlamaya tabi tutun |
| Tünel reddedildi, proxy'den 502/503 | httpx.ProxyError | Ağ geçidi tüneli açamadı veya protokol için bağlantı noktası yanlış | HTTP(S) için 9000/10000, SOCKS5 için 11000/12000 olduğunu doğrulayın |
| Proxy sunucusuna ulaşılamıyor | httpx.ConnectError | DNS, güvenlik duvarı veya yanlış ana bilgisayar adı | Ana bilgisayarı manuel olarak çözümleyin; connect zaman aşımını artırın |
| İstek askıda kalıyor ve ardından başarısız oluyor | httpx.ConnectTimeout / httpx.ReadTimeout | Yavaş ev ağı çıkışı veya engellenmiş hedef | Zaman aşımını artırın, yeni bir oturum kimliğiyle yeniden deneyin |
import httpx
PROXY = "http://USERNAME:PASSWORD@premium-residential.geonode.com:9000"
def get_via_proxy(url: str) -> httpx.Response | None:
try:
with httpx.Client(proxy=PROXY, timeout=httpx.Timeout(15.0, connect=8.0)) as client:
r = client.get(url)
if r.status_code == 407:
raise RuntimeError("proxy rejected credentials (407)")
return r
except httpx.ProxyError as e:
print("proxy refused tunnel:", e)
except httpx.ConnectError as e:
print("cannot connect to proxy host:", e)
except httpx.TimeoutException as e:
print("timed out:", type(e).__name__)
return None
resp = get_via_proxy("https://api.ipify.org?format=json")
print(resp.json() if resp else "failed")
Tüm httpx istisnaları httpx.HTTPError sınıfından miras alır, bu nedenle günlüğe kaydetme için tek bir genel except bloğu yeterlidir; ancak ProxyError ile ConnectError'u ayırmak, sorunun kimlik bilgilerinden mi yoksa ağdan mı kaynaklandığını anlamanıza yardımcı olur.
Sık yapılan hatalar
Proxy URL’sinde https://
kullanımı
Yukarıda da belirtildiği gibi, proxy URL şeması proxy’ye giden bağlantıyı tanımlar. Hedef https://.
olsa bile HTTP(S) bağlantı noktaları için http://
kullanın. https://
ifadesini, proxy’ye TLS’yi açıkça bildiren ağ geçitleri için ayırın.
HTTPTransport
'ı AsyncClient
ile karıştırma AsyncClient
üzerindeki
mounts
, AsyncHTTPTransport
kullanmalıdır. Senkron aktarım, oluşturma sırasında kabul edilir ancak istek sırasında yararsız bir hata ile başarısız olur; bu nedenle, hiç istek göndermeyen testlerde bu hatayı gözden kaçırmak kolaydır.
Dönen bağlantı noktasından tek bir IP adresi beklemek
9000 numaralı bağlantı noktası, her bağlantı için döner. Arka arkaya gelen iki isteğin bir IP adresini paylaşması gerekiyorsa, kullanıcı adında -session-
kimliği bulunan 10000 numaralı bağlantı noktasını kullanın. Client
'ın yeniden kullanılması, havuzdaki bağlantılar değiştirilebileceğinden, tek başına IP adresini sabitlemez.
Ortamın kodunuzu geçersiz kılmasına izin verme
Bir Docker görüntüsünde veya CI çalıştırıcısında yanlışlıkla bırakılmış bir HTTPS_PROXY
, doğrudan olduğunu düşündüğünüz trafiği yönlendirecektir; NO_PROXY
ise proxy üzerinden yönlendirilmesini beklediğiniz ana bilgisayarları hariç tutabilir. Proxy yönlendirmesinin belirleyici olması gerektiğinde trust_env=False
ayarını yapın.
Sonraki adım
Yukarıdaki istemci bir ev tipi IP adresi döndürdüğünde ve istekler arasında kalıcı bir oturum kurulduğunda, geriye kalan değişken bunun arkasındaki havuzdur. Geonode'un ev tipi proxy'leri, bu kılavuzda kullanılan uç noktaları sunar: 2,5 milyon çevrimiçi IP, 195'ten fazla ülkede aylık olarak dönüşümlü olarak kullanılan 30–50 milyon benzersiz IP; kullanıcı adı kuralı aracılığıyla ülke, eyalet, şehir ve ASN hedefleme ile 24 saate kadar kalıcı oturumlar. Fiyatlandırma, toplu alımlarda GB başına 0,27 $'dan başlar; giriş seviyesi planı aylık 7,92 $ karşılığında 10 GB'dir ve 3 günlük deneme sürümü 5 $'dır. Bunun üzerine bir tarayıcı geliştiriyorsanız, web kazıma kullanım örneği proxy'leri yeniden deneme mantığıyla nasıl eşleştireceğinizi açıklamaktadır; ayrıca dönen veri merkezi proxy'leri, veri merkezi aralıklarını engellemeyen hedefler için daha ucuz bir seçenektir.
SSS
Tüm istekler için bir httpx proxy'si nasıl ayarlayabilirim?
Proxy URL'sini istemci oluşturucusuna aktarın: httpx.Client(proxy="http://user:pass@host:port"). Bu istemci aracılığıyla yapılan her istek, hem http:// hem de https:// hedefleri için proxy üzerinden yönlendirilir. Aynı anahtar kelime, httpx.AsyncClient ve httpx.get() gibi üst düzey yardımcı işlevlerde de çalışır. URL’deki kimlik bilgileri otomatik olarak Proxy-Authorization olarak gönderilir.
httpx’te proxy ile mounts arasındaki fark nedir?
proxy, her şeyi tek bir proxy üzerinden yönlendiren bir kısayoldur. mounts, "http://" veya "https://" gibi URL kalıplarını aktarımlara eşler; her bir aktarım kendi proxy’sini, yeniden deneme sayısını ve sınırlarını taşıyabilir. Şema veya ana bilgisayar başına farklı proxy'lere ihtiyacınız olduğunda ya da proxy içermeyen bir aktarım bağlayarak bazı hedefler için proxy'yi atlamak istediğinizde mounts kullanın.
Proxy URL'si https://? ile başladığında https:// bağlamam neden başarısız oluyor?
Proxy URL'sindeki şema, httpx'in proxy ile nasıl iletişim kurduğunu açıklar; hedefi değil. https:// hedefleri için httpx, proxy'ye düz bir HTTP bağlantısı üzerinden bir CONNECT tüneli açar; bu nedenle proxy URL'si normalde http://. kullanmalıdır. https:// kullanılması, httpx'ten proxy ile TLS müzakeresi yapmasını ister; ancak çoğu proxy uç noktası bu hizmeti sunmaz.
httpx, SOCKS5 proxy'lerini destekliyor mu?
Evet, ancak yalnızca pip install httpx[socks] komutuyla isteğe bağlı bağımlılığı yükledikten sonra; bu komut socksio kütüphanesini de yükler. Ardından, tıpkı bir HTTP proxy'si kullanır gibi proxy="socks5://user:pass@host:port" parametresini aynen bu şekilde belirtin. Geonode'da SOCKS5 dönen bağlantı noktası 11000 ve SOCKS5 sabit bağlantı noktası 12000'dir; HTTP(S) bağlantı noktaları SOCKS el sıkışmalarını kabul etmez.
Proxy bağlantısı başarısız olduğunda httpx bir isteği otomatik olarak yeniden deneyebilir mi?
Yalnızca aktarım düzeyinde. httpx.HTTPTransport(retries=2), proxy'ye bağlantı hataları da dahil olmak üzere başarısız bağlantı denemelerini yeniden dener, ancak 407 veya 502 gibi bir yanıt almış bir isteği asla yeniden denemez. HTTP durum kodlarına ilişkin yeniden denemeler, oturum kimliğini değiştirebileceğiniz veya kasıtlı olarak geri çekilebileceğiniz kendi döngünüze aittir.
httpx proxy kurulumunun konut IP'leriyle yapabilecekleri konusunda herhangi bir sınırlama var mı?
Bir proxy, çıkış IP'nizi değiştirir; ancak bir sitenin izin verdiklerini değiştirmez. robots.txt dosyasına, hizmet şartlarına ve hız sınırlamalarına uyun, eşzamanlılık sayısını makul düzeyde tutun ve işleme koymak için dayanağınız olmayan kişisel verileri toplamaktan kaçının. Ev tipi oturumlar ayrıca 24 saat ile sınırlıdır; bu sürenin sonunda IP serbest bırakılır ve yeni bir oturum açmanız gerekir.