Python HTTP/HTTPS Proxy Guide for Teams
Configure Requests, session objects, and retries with username/password auth—plus practical tips for sticky vs rotating endpoints.
This article is educational. Buy Mobile, Residential, or Corporate on the product catalog and compare rates on Pricing. Use these patterns for legitimate work: public catalog research, regional SEO sampling, localization QA, and scheduled monitors. Follow applicable law, robots.txt, and each site’s terms.
How do you use an HTTP or HTTPS proxy in Python?
Pass a proxy URL with username and password into your client’s proxy settings, reuse a Session for sticky flows, and keep timeouts plus retries explicit. On Proxy Grove you buy Mobile, Residential, or Corporate, then copy the HTTP endpoint from the dashboard—HTTP is a protocol, not a separate SKU. Start with one allowed public URL before you scale concurrency.
Most Python scrapers and API clients speak HTTP and HTTPS. Pointing them through Proxy Grove is usually a matter of proxy URL, credentials, retry policy, and choosing sticky versus rotating on the plan—not inventing a custom protocol layer in Python.
If you need async concurrency, read the httpx and asyncio guide. If you need a crawl graph with pipelines, read the Scrapy middleware guide. This page stays on synchronous requests and Session objects.
What you buy vs what you configure
Proxy Grove sells IP types: Mobile, Residential, and Corporate. Residential and Corporate start from $2/IP/day; Mobile starts from $4.50/IP/day. Coverage spans 246 countries. HTTP/SOCKS5 and sticky or rotating sessions are options on those products.
Python does not “buy” HTTP. You generate an HTTP (or SOCKS5) endpoint in the dashboard, then point requests at it. For SOCKS5 trade-offs see SOCKS5 vs HTTP. For auth patterns see credentials vs allowlisting.
Install and keep secrets out of git
pip install requests
Put credentials in the environment. Do not commit USER:PASS to a public repo.
export PG_PROXY="http://USER:PASS@host:port"
On Windows PowerShell use $env:PG_PROXY = "http://USER:PASS@host:port". Prefer a secret manager in CI.
Minimal requests example
import os
import requests
proxy = os.environ["PG_PROXY"]
proxies = {"http": proxy, "https": proxy}
r = requests.get("https://example.com", proxies=proxies, timeout=30)
print(r.status_code, len(r.content))
Both http and https keys usually point at the same HTTP proxy URL. HTTPS targets use a CONNECT tunnel through that URL. You do not switch the proxy scheme to https:// just because the target is HTTPS.
Session reuse for sticky flows
Sticky versus rotating is configured on the plan. In Python you still choose whether to reuse a Session. Reuse when multi-step flows should keep cookies and connection state on one client.
import os
import requests
proxy = os.environ["PG_PROXY"]
session = requests.Session()
session.proxies.update({"http": proxy, "https": proxy})
session.headers.update({"User-Agent": "ResearchBot/1.0 (+https://example.com/bot)"})
for path in ["/", "/about", "/pricing"]:
r = session.get(f"https://example.com{path}", timeout=30)
r.raise_for_status()
print(path, r.status_code)
Use a descriptive bot User-Agent with contact info for legitimate research. Do not spoof a random browser string to “look real.” Keep TLS verification on.
Retries, backoff, and status buckets
Treat failures as separate buckets. A 407 is proxy auth or endpoint. A 429 or 503 is the target. A timeout is connect or read budget. Raising concurrency does not fix 407.
import os
import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
proxy = os.environ["PG_PROXY"]
session = requests.Session()
session.proxies.update({"http": proxy, "https": proxy})
retry = Retry(
total=3,
backoff_factor=0.8,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "HEAD"],
)
session.mount("https://", HTTPAdapter(max_retries=retry))
session.mount("http://", HTTPAdapter(max_retries=retry))
def fetch(url):
try:
r = session.get(url, timeout=(5, 30))
return r.status_code, r
except requests.exceptions.ProxyError as e:
print("proxy error", e)
raise
except requests.exceptions.Timeout:
print("timeout", url)
raise
status, resp = fetch("https://example.com")
print(status)
Retry idempotent GETs. Do not blindly retry POST. Space workers with a small sleep when sampling many public pages. For high-volume distribution patterns, pair this with rotating proxies for large-scale scraping.
Sticky vs rotating: what Python controls
Python does not flip Proxy Grove session mode. Sticky: keep concurrency low (1–2 workers) for multi-page identity. Rotating: more start URLs, still capped workers, good for sampling many public pages. Country targeting is selected with the plan, not in a header you invent.
If a site localizes by IP, sticky is how you compare “the same visitor” across paths. Rotating is how you sample many IPs in one country. Mixing sticky expectations with unbounded thread pools usually creates confusing logs, not better data.
SOCKS5 with requests
Default requests speaks HTTP proxies. For SOCKS5 install a SOCKS adapter (commonly requests[socks] / PySocks) and use a socks5:// or socks5h:// URL from the dashboard. Prefer HTTP for most scrapers and SEO tools. Use SOCKS5 when the client expects a SOCKS agent. One process, one proxy URL.
Environment variables vs explicit proxies dict
HTTP_PROXY / HTTPS_PROXY work process-wide. Explicit proxies= on the call or Session is clearer in multi-tenant workers. Prefer explicit config in production services so a library cannot silently inherit a shell proxy.
# Prefer explicit Session config in services
session.proxies.clear()
session.proxies.update({"http": proxy, "https": proxy})
Mapping jobs to Mobile, Residential, Corporate
requests does not care which product you bought. You do. Residential: SERP and storefront checks that should look like a home ISP. Mobile: ad preview and app QA where carrier IPs matter—see mobile proxies for ad verification. Corporate: business-grade space for sticky professional sessions. Generate the endpoint, keep the same client code.
Logging that helps the next engineer
Log URL, status, elapsed ms, proxy host (not password), and whether the plan was sticky or rotating. That line separates pool exhaustion from a blocked target from a bad credential. Do not scrape passwords into logs.
import logging
log = logging.getLogger("pg.fetch")
def logged_get(session, url):
t0 = time.time()
r = session.get(url, timeout=30)
log.info("url=%s status=%s ms=%d", url, r.status_code, int((time.time()-t0)*1000))
return r
What not to do
Do not disable TLS verification to “make the proxy work.” Do not ignore robots.txt because a pool is large. Do not treat Proxy Grove as an unblocker or CAPTCHA solver—it sells IPs. Do not copy this Session pattern into Scrapy pipelines; Scrapy has its own middleware. Do not open unbounded thread pools against one domain and call it production.
Checklist before you scale
- Confirm a 200 on a public page you are allowed to fetch
- Confirm 407 rate is near zero with dashboard credentials
- Set connect and read timeouts separately when jobs differ
- Cap workers; raise only after measuring target 429s
- Document sticky vs rotating per job in the runbook
What to do next
Copy the Session snippet, keep secrets in the environment, and verify one allowed URL. Then choose Residential, Mobile, or Corporate for identity—not for the Python library. Move to httpx when you need async; move to Scrapy when you need a crawl graph. Compare plans on Pricing when you are ready to run the job on a real pool across up to 246 countries with HTTP or SOCKS5.
Threading and process pools
If you must use threads, give each worker a Session or share one Session carefully—requests.Session is not always safe across threads depending on usage. Prefer a process pool with explicit proxy env per process for isolation. Always cap the pool size. An unbounded ThreadPoolExecutor against one domain will create 429s regardless of how large your rotating pool is.
from concurrent.futures import ThreadPoolExecutor, as_completed
import os, requests
proxy = os.environ["PG_PROXY"]
def one(url):
s = requests.Session()
s.proxies.update({"http": proxy, "https": proxy})
r = s.get(url, timeout=30)
return url, r.status_code
urls = ["https://example.com/robots.txt"] # only allowed URLs
with ThreadPoolExecutor(max_workers=4) as ex:
futs = [ex.submit(one, u) for u in urls]
for f in as_completed(futs):
print(f.result())
Testing without burning production IPs
Keep a tiny smoke credential or a single IP for developers. Production jobs should use production secrets from the vault. Mock proxy failures in unit tests; run one live 200-check in integration. Document the difference so new hires do not point local notebooks at the SEO sticky pool.
When you outgrow synchronous requests, move to the httpx guide for asyncio or the Scrapy guide for crawl graphs—do not invent a hybrid that mixes all three in one process.
Questions this article answers
Point requests at the HTTP endpoint with username and password from the dashboard. See the HTTP/HTTPS product lander for the connection model.
Only if you install a SOCKS adapter. Default requests speaks HTTP. Buy any IP type, then pick the protocol.
Session mode is configured on the plan, not in Python. Keep retries polite and respect robots.txt.
HTTP is a protocol. Buy Mobile, Residential, or Corporate, then use the HTTP endpoint.
Related Articles
SOCKS5 vs HTTP Proxies for Automation Stacks
Understand protocol fit for browsers, scrapers, and general tunneling so your automation tools connect cleanly.
How Rotating Proxies Improve Large-Scale Web Scraping
Learn when to rotate every request, when to use sticky windows, and how to design scrapers that distribute load across a healthy IP pool.
Securing Proxy Access: Credentials vs IP Allowlisting
Compare username/password auth with source IP allowlisting, and design access patterns that fit scrapers, servers, and teams.