Geliştirici Rehberleri5 dk okuma
Python ile proxy kullanımı: requests, httpx, SOCKS5 ve hatalar
Python’da proxy kullanmanın en kısa yolu requests’te proxies sözlüğü, httpx’te proxy argümanıdır. Güvenilir bir betik için bunlara zaman aşımı, yeniden deneme, ortam değişkenlerinin etkisi ve doğru hata yakalama eklenmelidir.
Kısa cevap: requests.get(url, proxies={"http": PROXY, "https": PROXY}, timeout=(5, 20)) ya da httpx.Client(proxy=PROXY). Bu rehber, bu iki satırın arkasındaki ayrıntıları çalışır örneklerle açıyor: SOCKS5 ve uzak DNS, oturumlarda ortam değişkeni tuzağı, urllib3.Retry ile yeniden deneme, httpx’in değişen proxy API’si ve hataların ayırt edilmesi. Örneklerde yer tutucular KULLANICI, PAROLA, PROXY_ADRESI ve PORT; test adresi https://api.ipify.org?format=json. Farklı dillerde kısa bağlantı örnekleri için Geliştirici sayfasına bakabilirsiniz.
Kurulum
python -m pip install "requests[socks]" "httpx[socks]"requests[socks] SOCKS desteği için PySocks’u, httpx[socks] ise socksio’yu kurar. Yalnızca HTTP proxy kullanacaksanız ekler gerekmez.
requests ile ilk istek
import requests
PROXY = "http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
proxies = {"http": PROXY, "https": PROXY}
r = requests.get(
"https://api.ipify.org",
params={"format": "json"},
proxies=proxies,
timeout=(5, 20),
)
r.raise_for_status()
print(r.json()["ip"])- Sözlüğün anahtarı hedefin şemasıdır, değeri proxy’nin adresidir.
"https"anahtarınahttp://ile başlayan bir proxy yazmak doğrudur: bu, HTTPS isteklerinin bir HTTP proxy üzerindenCONNECTtüneliyle gideceği anlamına gelir. Değerihttps://ile başlatmak, proxy’ye TLS ile bağlanmak demektir ve yalnızca proxy bunu destekliyorsa çalışır. timeouther zaman verilmeli. requests’in varsayılan zaman aşımı yoktur; yanıt vermeyen bir proxy betiğinizi süresiz bekletebilir.(5, 20)bağlantı için 5, okuma için 20 saniye demektir.- Paroladaki özel karakterleri kodlayın.
@,:,/gibi karakterler URL’yi bozar;urllib.parse.quote(parola, safe="")ile kodlayın.
SOCKS5 ve socks5h
import requests
PROXY = "socks5h://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
proxies = {"http": PROXY, "https": PROXY}
r = requests.get(
"https://api.ipify.org",
params={"format": "json"},
proxies=proxies,
timeout=(5, 20),
)
print(r.json())requests belgelerine (yeni sekmede açılır) göre socks5:// şeması hedef adını istemcide çözer, socks5h:// ise çözümlemeyi proxy’ye bırakır. Yerel ağınızın çözümleyicisine sorgu gitmesini istemiyorsanız socks5h kullanın; nedenini DNS sızıntısı nedir? rehberi anlatıyor. HTTP mi SOCKS5 mi kararını henüz vermediyseniz HTTP & SOCKS5 Proxy sayfası iki protokolün hangi paketlerde seçilebildiğini gösterir.
Kimlik bilgilerini koddan ayırmak
Örneklerde okunabilirlik için proxy adresini doğrudan yazdık; gerçek bir projede kullanıcı adı ve parola kaynak koda girmemelidir. Değerleri ortam değişkeninden ya da bir gizli bilgi yöneticisinden okuyun ve URL’ye yerleştirmeden önce kodlayın. quote(…, safe="") parola içindeki @, : ve / gibi karakterleri URL’yi bozmayacak biçime çevirir; requests bu kodlamayı bağlanmadan önce geri çözer.
import os
from urllib.parse import quote
import requests
user = quote(os.environ["PROXY_KULLANICI"], safe="")
password = quote(os.environ["PROXY_PAROLA"], safe="")
host = os.environ["PROXY_ADRESI"]
port = os.environ["PROXY_PORT"]
PROXY = f"http://{user}:{password}@{host}:{port}"
proxies = {"http": PROXY, "https": PROXY}
r = requests.get(
"https://api.ipify.org",
params={"format": "json"},
proxies=proxies,
timeout=(5, 20),
)
print(r.json()["ip"])Session ve ortam değişkeni tuzağı
Çok sayıda istek yapacaksanız requests.Session bağlantıları yeniden kullanır ve her istekte yeni TCP ve TLS kurulumunu önler. Ancak belgelerde açıkça uyarıldığı gibi session.proxies ile verdiğiniz değerin üzerine ortam değişkenlerindeki proxy ayarları yazılabilir. İki güvenli yol vardır: proxy’yi her isteğe proxies= ile vermek ya da oturumda trust_env = False ayarlamak. İkincisi .netrc kimlik bilgilerini ve REQUESTS_CA_BUNDLE gibi ortam ayarlarını da devre dışı bırakır.
Yeniden deneme: urllib3 Retry
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
PROXY = "http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
PROXIES = {"http": PROXY, "https": PROXY}
retry = Retry(
total=3,
connect=3,
read=2,
backoff_factor=0.5,
status_forcelist=(429, 500, 502, 503, 504),
allowed_methods=frozenset({"GET", "HEAD"}),
respect_retry_after_header=True,
)
adapter = HTTPAdapter(max_retries=retry)
with requests.Session() as s:
s.mount("http://", adapter)
s.mount("https://", adapter)
r = s.get(
"https://api.ipify.org",
params={"format": "json"},
proxies=PROXIES,
timeout=(5, 20),
)
print(r.status_code, r.json())urllib3 Retry (yeni sekmede açılır) denemeler arasında artan aralıklarla bekler ve Retry-After başlığına uyar. Yalnızca güvenle tekrarlanabilen yöntemleri (GET, HEAD) yeniden deneyin. status_forcelist içindeki kodlarda denemeler tükenirse requests RetryError yükseltir. 407’yi listeye eklemeyin: hatalı kimlik bilgisini tekrar göndermek sonucu değiştirmez.
Hataları ayırt etmek
import requests
from requests.exceptions import (
ConnectTimeout,
ProxyError,
ReadTimeout,
RequestException,
SSLError,
)
PROXY = "http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
proxies = {"http": PROXY, "https": PROXY}
try:
r = requests.get(
"https://api.ipify.org",
params={"format": "json"},
proxies=proxies,
timeout=(5, 20),
)
r.raise_for_status()
print("Çıkış IP adresi:", r.json()["ip"])
except ProxyError as exc:
print("Proxy hatası:", exc)
except ConnectTimeout:
print("Bağlantı zaman aşımına uğradı")
except ReadTimeout:
print("Yanıt zaman aşımına uğradı")
except SSLError as exc:
print("TLS hatası:", exc)
except RequestException as exc:
print("Diğer istek hatası:", exc)| Hata | Genellikle ne anlama gelir? |
|---|---|
ProxyError | Proxy’ye bağlanılamadı, bağlantı reddedildi ya da HTTPS tüneli kurulamadı (Tunnel connection failed: 407 kimlik doğrulama hatasıdır). urllib3, proxy’ye bağlanırken oluşan zaman aşımını da bu hatanın içinde sarabilir. |
ConnectTimeout | TCP bağlantısı, bağlantı zaman aşımı içinde kurulamadı. |
ReadTimeout | Bağlantı kuruldu ama okuma zaman aşımı içinde veri gelmedi. |
SSLError | Hedefle TLS el sıkışması başarısız oldu. Sertifikayı kendi sertifikasıyla değiştiren bir ara katman olabilir; verify=False ile susturmayın. |
| Yanıt kodu 407 | Düz HTTP hedeflerde istisna değil, yanıt olarak gelir; kimlik bilgilerini kontrol edin. |
ConnectionError | SOCKS tarafındaki hatalar (el sıkışma, doğrulama) çoğunlukla bu genel bağlantı hatası olarak görünür. |
httpx: proxy= argümanı
httpx’in proxy API’si değişti: proxy= argümanı 0.26.0 sürümünde geldi, eski proxies= argümanı aynı sürümde kullanımdan kaldırıldı ve 0.28.0’da tamamen silindi. Eski örneklerdeki proxies= güncel sürümlerde hata verir. Farklı şemalar için farklı proxy gerekiyorsa mounts= ile taşıyıcı (transport) tanımlanır (httpx proxy belgeleri (yeni sekmede açılır)).
import httpx
PROXY = "http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
timeout = httpx.Timeout(20.0, connect=5.0)
try:
with httpx.Client(proxy=PROXY, timeout=timeout) as client:
r = client.get("https://api.ipify.org", params={"format": "json"})
r.raise_for_status()
print(r.json()["ip"])
except httpx.ProxyError as exc:
print("Proxy hatası:", exc)
except httpx.TimeoutException as exc:
print("Zaman aşımı:", exc)
except httpx.HTTPError as exc:
print("Diğer hata:", exc)import asyncio
import httpx
PROXY = "http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
async def main():
async with httpx.AsyncClient(proxy=PROXY, timeout=20.0) as client:
r = await client.get("https://api.ipify.org", params={"format": "json"})
print(r.json())
asyncio.run(main())requests’ten farklı olarak httpx’in varsayılan bir zaman aşımı vardır (5 saniye). SOCKS5 için httpx[socks] kurulur ve proxy="socks5://…" verilir; 0.28.0’dan itibaren socks5h:// şeması da kabul edilir. httpx’in yerleşik yeniden denemesi yalnızca bağlantı hatalarını kapsar: httpx.HTTPTransport(proxy=PROXY, retries=3) taşıyıcısını transport= ile verebilirsiniz.
Ortam değişkenleriyle yapılandırma
export HTTP_PROXY="http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
export HTTPS_PROXY="http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
export NO_PROXY="localhost,127.0.0.1"
python betik.pyrequests ve httpx bu değişkenleri (ve küçük harfli karşılıklarını) varsayılan olarak okur; ALL_PROXY de desteklenir. httpx’te proxy= açıkça verildiğinde o kullanılır. Ortam değişkenleri alt işlemlere de geçer; parola içeren bir değişkeni paylaşılan makinelerde dikkatle kullanın. Kimlik bilgisi saklama yöntemleri için Proxy kimlik doğrulama rehberine bakın.
Çıkış IP adresini doğrulamak
import requests
URL = "https://api.ipify.org"
PROXY = "http://KULLANICI:PAROLA@PROXY_ADRESI:PORT"
PROXIES = {"http": PROXY, "https": PROXY}
with requests.Session() as s:
s.trust_env = False
direct = s.get(URL, params={"format": "json"}, timeout=(5, 20)).json()["ip"]
via_proxy = s.get(
URL, params={"format": "json"}, proxies=PROXIES, timeout=(5, 20)
).json()["ip"]
print("Doğrudan:", direct)
print("Proxy ile:", via_proxy)
print("Proxy çıkışı farklı" if direct != via_proxy else "Uyarı: iki adres aynı")trust_env = False, “doğrudan” isteğin gerçekten doğrudan gitmesini sağlar. İki adres aynı çıkıyorsa istek proxy’ye hiç uğramamıştır: sözlükte "https" anahtarının bulunduğunu, proxy URL’sinin şemayla başladığını ve NO_PROXY değişkeninin hedef adı kapsamadığını kontrol edin. Adres farklıysa ama beklediğiniz ülke ya da ağ türü değilse sorunu kodda değil, kullandığınız paketin özelliklerinde arayın. Bir liste dolusu proxy’yi tek tek denemek yerine Proxy Kontrol aracını kullanabilirsiniz.
Sık yapılan hatalar
- Sözlükte yalnızca
"http"anahtarı: requests proxy’yi hedefin şemasına göre seçer."https"anahtarı yoksa HTTPS istekleri proxy’ye hiç uğramadan doğrudan gider ve çıkış adresiniz değişmez. - Şemasız proxy adresi:
PROXY_ADRESI:PORTyerinehttp://PROXY_ADRESI:PORTyazın; requests belgeleri proxy URL’sinin şema içermesi gerektiğini belirtir. verify=Falseile TLS hatasını susturmak: Sertifika doğrulamasını kapatmak, araya giren herhangi bir sunucuya güvenmek demektir. Hatanın nedenini bulun; kurum içi bir ara katman varsa onun kök sertifikasınıverify=ile gösterin.- Zaman aşımı vermemek: Tek bir yanıt vermeyen proxy, iş parçacığını veya bütün betiği kilitleyebilir.
socks5yazıp DNS’in yerelde çözüldüğünü fark etmemek: Hedef adının proxy’de çözülmesini istiyorsanızsocks5hkullanın.session.proxiesile ortam değişkenlerini birlikte kullanmak: Hangi proxy’nin kullanıldığı belirsizleşir; proxy’yi her isteğe verin ya datrust_env = Falseayarlayın.
Özet: requests mi, httpx mi?
| İhtiyaç | requests | httpx |
|---|---|---|
| HTTP proxy | proxies={"http": P, "https": P} | proxy=P |
| SOCKS5 | requests[socks], socks5h:// | httpx[socks], socks5:// veya socks5h:// |
| Zaman aşımı | timeout=(5, 20); varsayılan yok | httpx.Timeout(…); varsayılan 5 sn |
| Yeniden deneme | HTTPAdapter + urllib3 Retry | HTTPTransport(retries=…), yalnızca bağlantı hataları |
| Ortam değişkenleri | Okunur (trust_env) | Okunur (trust_env) |
| Asenkron | Yok | AsyncClient |
Sık sorulanlar