Python requests SOCKS5 Proxy Examplewith Auth, DNS, Retries & Rotation
Complete guide to using SOCKS5 proxies with Python requests library including authentication, DNS resolution, error handling, and proxy rotation patterns.
Quick Start: Minimal SOCKS5 example
import requests # For credentials with special chars, use URL encoding: # from urllib.parse import quote # PROXY = f"socks5h://{quote('user@123')}:{quote('p@ss!')}@host:port" PROXY = "socks5h://username:password@host:port" # e.g. socks5h://user:pass@1.2.3.4:1080 proxies = {"http": PROXY, "https": PROXY} resp = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=20) resp.raise_for_status() print(resp.json())
Important Notes
- • Install SOCKS support with
pip install "requests[socks]"
(this pulls in PySocks) - •
socks5h
ensures the proxy does DNS resolution. Plainsocks5
resolves locally
Production-Ready Session: Timeouts + Retries (with backoff)
Use a Session, mount an adapter with urllib3.Retry, and share connections efficiently:
import os from urllib.parse import quote import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # Build a socks5h proxy URL (remote DNS) user = os.getenv("PROXY_USER") pw = os.getenv("PROXY_PASS", "") host = os.getenv("PROXY_HOST", "127.0.0.1") port = int(os.getenv("PROXY_PORT", "1080")) PROXY = ( f"socks5h://{quote(user)}:{quote(pw)}@{host}:{port}" if user else f"socks5h://{host}:{port}" ) session = requests.Session() session.trust_env = False # optional: ignore env proxies (HTTP_PROXY/HTTPS_PROXY) session.proxies.update({"http": PROXY, "https": PROXY}) retries = Retry( total=5, backoff_factor=0.5, # 0.5, 1, 2, 4... seconds status_forcelist=[429, 500, 502, 503, 504], allowed_methods=frozenset(["HEAD", "GET", "OPTIONS"]), respect_retry_after_header=True, # explicit for portability with urllib3 v1.26+ ) adapter = HTTPAdapter(max_retries=retries, pool_connections=50, pool_maxsize=50) session.mount("http://", adapter) session.mount("https://", adapter) def fetch(url): r = session.get(url, timeout=(5, 30)) # (connect, read) r.raise_for_status() return r if __name__ == "__main__": print(fetch("https://httpbin.org/ip").json())
Pro tip: Retry provides exponential backoff and respects Retry-After headers (default in urllib3 v2.0+, set explicitly for v1.26 compatibility).
Environment variables: session.trust_env = False
prevents HTTP_PROXY/HTTPS_PROXY environment variables from interfering with your explicit proxy config.
⚠️ POST Safety: We removed POST from default retries. If you must retry POST requests, use idempotency keys and accept the risk of duplicate operations.
The socks5 vs socks5h difference (and when it bites)
socks5://...
Local DNS resolution (your machine looks up the hostname, then asks the proxy to connect to that IP).
socks5h://...
Remote DNS resolution on the proxy (prevents DNS leaks and is required for .onion and some providers).
Some proxy networks even require remote DNS (hostname-only targets), so use socks5h
.
IP Rotation: On-Demand & Round-Robin Patterns
Mobile proxy providers typically offer two rotation approaches: API-triggered IP changes or built-in rotating gateways.
Option 1: API-Triggered Rotation (Coronium.io example)
Many providers give you a restart/rotation endpoint. You call it before each scraping batch to get a fresh IP:
import os import requests from urllib.parse import quote from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # Your modem restart token (copy from dashboard.coronium.io) ROTATION_TOKEN = os.getenv("ROTATION_TOKEN", "19a18981f48fa3907f04c19bdcba8666") ROTATION_URL = f"https://dashboard.coronium.io/api/v1/modems/restart-by-token/{ROTATION_TOKEN}/" # Proxy credentials user = os.getenv("PROXY_USER") pw = os.getenv("PROXY_PASS", "") host = os.getenv("PROXY_HOST", "127.0.0.1") port = int(os.getenv("PROXY_PORT", "1080")) PROXY = f"socks5h://{quote(user)}:{quote(pw)}@{host}:{port}" if user else f"socks5h://{host}:{port}" session = requests.Session() session.trust_env = False session.proxies.update({"http": PROXY, "https": PROXY}) retries = Retry( total=5, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504], allowed_methods=frozenset(["HEAD", "GET", "OPTIONS"]), respect_retry_after_header=True, ) adapter = HTTPAdapter(max_retries=retries, pool_connections=50, pool_maxsize=50) session.mount("http://", adapter) session.mount("https://", adapter) def rotate_ip(): """Trigger modem restart to get a new IP (wait ~30-60s for reconnection).""" try: resp = requests.get(ROTATION_URL, timeout=10) resp.raise_for_status() print("✓ IP rotation triggered") return True except Exception as e: print(f"⚠ Rotation failed: {e}") return False def fetch(url): r = session.get(url, timeout=(5, 30)) r.raise_for_status() return r if __name__ == "__main__": # Rotate before starting rotate_ip() # Wait for modem to reconnect (adjust timing based on your provider) import time time.sleep(45) # Now scrape with fresh IP print(fetch("https://httpbin.org/ip").json())
Tip: You can copy your restart link directly from dashboard.coronium.io
- it includes your unique token. Call it whenever you need a new IP (e.g., every N requests or after rate limits).
Option 2: Round-Robin with Multiple Proxies
If you have multiple proxies, use itertools.cycle
to rotate through them:
import itertools from urllib.parse import quote # List of proxies PROXY_LIST = [ "socks5h://user1:pass1@host1:1080", "socks5h://user2:pass2@host2:1080", "socks5h://user3:pass3@host3:1080", ] proxy_pool = itertools.cycle(PROXY_LIST) def fetch_with_rotation(url): proxy = next(proxy_pool) proxies = {"http": proxy, "https": proxy} r = requests.get(url, proxies=proxies, timeout=(5, 30)) r.raise_for_status() return r # Each call uses the next proxy in rotation for i in range(5): print(f"Request {i+1}:", fetch_with_rotation("https://httpbin.org/ip").json())
⚠️ Note: Round-robin works best when your proxies are independent. For mobile proxies with API rotation, use the on-demand pattern above to control exactly when IPs change.
References & Further Reading
Need Reliable SOCKS5 Proxies?
Get premium mobile proxies with authentic carrier IPs, perfect for your Python automation needs.