Python’da proxy kullanmanın en yaygın yolu requests kütüphanesidir. Aşağıdaki örnekler protokol seviyesindedir ve herhangi bir proxy sağlayıcısına özel bir SDK gerektirmez. Kimlik bilgileri yer tutucudur: KULLANICI, SIFRE, proxy.example.com ve PORT değerlerini kendi bilgilerinizle değiştirin.
HTTP proxy ile temel istek
requests, proxy’yi proxies sözlüğüyle alır. Anahtar, hedef URL’nin şemasıdır; değer ise proxy’nin adresidir. HTTPS hedefler için de çoğunlukla http:// şemalı bir proxy adresi verilir, çünkü şema hedefi değil istemci ile proxy arasındaki bağlantıyı anlatır.
import requests
PROXY = "http://KULLANICI:[email protected]:PORT"
proxies = {"http": PROXY, "https": PROXY}
r = requests.get("https://example.com/", proxies=proxies, timeout=(5, 20))
print(r.status_code)SOCKS5 ve socks5h farkı
SOCKS5 desteği için requests[socks] ek paketi gerekir (pip install "requests[socks]"). Burada iki şema vardır: socks5:// hedef host adını istemcide çözer, socks5h:// ise ad çözümünü proxy tarafına bırakır. Yerel DNS sorgusunun sızmasını istemiyorsanız socks5h kullanın; konu DNS sızıntısı ve socks5h yazısında ayrıntılı anlatılıyor.
import requests
PROXY = "socks5h://KULLANICI:[email protected]:PORT"
proxies = {"http": PROXY, "https": PROXY}
r = requests.get("https://example.com/", proxies=proxies, timeout=(5, 20))
print(r.status_code)| Şema | Protokol | Host adı çözümü |
|---|---|---|
| http:// | HTTP proxy (HTTPS için CONNECT) | Proxy tarafında |
| socks5:// | SOCKS5 | İstemci tarafında |
| socks5h:// | SOCKS5 | Proxy tarafında |
Oturum (Session) ile çok istek
Birden fazla istek gönderiyorsanız requests.Session kullanın. Proxy ayarı oturuma bir kez verilir, bağlantılar yeniden kullanılabilir ve başlıklar ortak tutulur. Ortam değişkenlerinden (HTTP_PROXY, HTTPS_PROXY) gelen ayarları istemeden devralmamak için trust_env = False yapabilirsiniz.
import requests
PROXY = "http://KULLANICI:[email protected]:PORT"
with requests.Session() as s:
s.trust_env = False
s.proxies.update({"http": PROXY, "https": PROXY})
s.headers.update({"User-Agent": "ornek-istemci/1.0"})
for path in ("/", "/robots.txt"):
r = s.get("https://example.com" + path, timeout=(5, 20))
print(path, r.status_code)Oturumun bir diğer yararı, aynı hosta yapılan ardışık isteklerde TCP ve TLS bağlantısının yeniden kullanılabilmesidir. Ancak oturum içinde proxy’yi değiştirirseniz eski bağlantıların kapanmasını beklemek gerekebilir; farklı proxy’ler için ayrı oturum açmak daha öngörülebilir sonuç verir. Aynı oturumu birden çok iş parçacığında paylaşırken requests oturumunun tamamen iş parçacığı güvenli olmadığını göz önünde bulundurun ve her iş parçacığına ayrı oturum verin.
Zaman aşımı ve hata yönetimi
timeout verilmezse requests süresiz bekleyebilir. Bağlantı ve okuma süresini ayrı veren (bağlantı, okuma) biçimi proxy sorunlarını ayırt etmeyi kolaylaştırır. Hataları türüne göre yakalayın: ProxyError proxy’ye ulaşılamadığını veya kimlik doğrulamanın başarısız olduğunu, ConnectTimeout ve ReadTimeout süre aşımını gösterir.
import requests
from requests.exceptions import ProxyError, ConnectTimeout, ReadTimeout
PROXY = "http://KULLANICI:[email protected]:PORT"
proxies = {"http": PROXY, "https": PROXY}
try:
r = requests.get("https://example.com/", proxies=proxies, timeout=(5, 20))
r.raise_for_status()
except ProxyError as e:
print("Proxy hatasi (adres, port veya kimlik bilgisi):", e)
except (ConnectTimeout, ReadTimeout) as e:
print("Zaman asimi:", e)
except requests.HTTPError as e:
print("Hedef servis hatasi:", e.response.status_code)Hatanın hangi katmandan geldiğini ayırmak önemlidir: ProxyError gateway ile ilgilidir, HTTPError ise isteğin hedefe ulaştığını ve hedefin yanıt kodu döndürdüğünü gösterir. Katmanların rolü için gateway, routing ve çıkış IP yazısına bakın.
Yeniden deneme ve kimlik bilgisini koddan ayırma
Geçici ağ hatalarına karşı urllib3.Retry ile oturuma yeniden deneme kuralı bağlanabilir. Aşağıdaki örnek ayrıca proxy adresini ortam değişkeninden okur; böylece kimlik bilgisi kaynak koda ve sürüm kontrolüne girmez. PROXY_URL değişkeninin değeri http://KULLANICI:[email protected]:PORT biçiminde olur.
import os
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
proxy = os.environ["PROXY_URL"]
retry = Retry(
total=3,
backoff_factor=1.0,
status_forcelist=(502, 503, 504),
allowed_methods=("GET", "HEAD"),
)
with requests.Session() as s:
s.trust_env = False
s.proxies.update({"http": proxy, "https": proxy})
adapter = HTTPAdapter(max_retries=retry)
s.mount("http://", adapter)
s.mount("https://", adapter)
r = s.get("https://example.com/", timeout=(5, 20))
print(r.status_code)Yeniden denemeyi 4xx yanıtlarına genişletmek yaygın bir hatadır: 407 kimlik bilgisi sorunudur, 429 ise hedefin hız sınırıdır. İkisi de tekrar göndermekle çözülmez; isteği seyreltmek ve hedefin kurallarına uymak gerekir.
Çıkış IP’yi doğrulama ve sorumlu kullanım
Kodunuzu üretime almadan önce istediğiniz çıkış adresinin gerçekten kullanıldığını bir IP sorgu servisiyle doğrulayın; IP sorgulama aracı bu iş için kullanılabilir. Veri toplama yapıyorsanız hedef sitenin robots.txt dosyasına, kullanım koşullarına ve ilgili mevzuata uyun; proxy bu yükümlülükleri ortadan kaldırmaz.
Özet
proxiessözlüğü hemhttphemhttpsanahtarını içermelidir.- SOCKS5 için
requests[socks]kurulur; DNS sızıntısını önlemek içinsocks5h://tercih edilir. - Çok istekte
Sessionkullanın; ortam proxy’lerini istemiyorsanıztrust_env = Falseyapın. - Daima
timeoutverin veProxyError, zaman aşımı veHTTPErrorhatalarını ayırın. - Kimlik bilgilerinde özel karakterleri yüzde kodlayın ve bilgileri kaynak koda gömmeyin.