Python httpx and aiohttp with AeonProxy proxies
Route httpx and aiohttp requests, sync or async, through residential or mobile IPs, with the login in the proxy URL.
- Protocols
- HTTP and HTTPS sites over an HTTP proxy, or SOCKS5 with
httpx[socks]oraiohttp-socks - Authentication
- Login and password in the proxy URL
- Rotation
- A new IP per connection, or one IP per
-sid-key for up to 60 minutes - Works with
- Residential and mobile proxies
Before you start
- Python 3.10 or newer, then
pip install httpxorpip install aiohttp, or both. - Your proxy login and password from the Residential or Mobile page of the dashboard.
- Traffic on the product you use: a login without traffic gets 402.
- Host
gate.aeonproxy.com- Port (HTTP / HTTPS)
7000- Port (SOCKS5)
7001- Login
- your proxy login, with targeting keys if you need them:
LOGIN-cc-us-sid-abc123 - Password
- your proxy password
Copy the login and password from the Residential or Mobile page of the dashboard; the generator there also writes ready lines. Key syntax: targeting and sessions.
httpx: rotating proxy
Pass the proxy URL with the login and password as proxy=. The scheme stays http:// for HTTPS sites: httpx opens a CONNECT tunnel through the proxy.
import httpx
proxy = "http://LOGIN-cc-us:[email protected]:7000"
limits = httpx.Limits(max_keepalive_connections=0) # a new connection, so a new IP, per request
with httpx.Client(proxy=proxy, limits=limits, timeout=30) as client:
for _ in range(3):
print(client.get("https://api.ipify.org").text)A Client sends the next request down the open connection, and the gateway picks the IP per connection: without limits, our three test requests shared one tunnel and one IP.
httpx: sticky session with AsyncClient
Add -sid- with a key of letters and digits, and -ttl- with the minutes to keep the IP (1–60). Every connection with the same key leaves from the same IP, so the five parallel requests below share it.
import asyncio
import secrets
import httpx
async def main():
sid = secrets.token_hex(4) # one key = one IP for up to ttl minutes
proxy = f"http://LOGIN-cc-de-sid-{sid}-ttl-30:[email protected]:7000"
async with httpx.AsyncClient(proxy=proxy, timeout=30) as client:
replies = await asyncio.gather(*(client.get("https://api.ipify.org") for _ in range(5)))
print([r.text for r in replies]) # the same IP five times
asyncio.run(main())httpx: SOCKS5
Install pip install "httpx[socks]" and use port 7001. With socks5:// or socks5h://, httpx sends the host name to the proxy, so DNS is resolved there and not on your machine.
import httpx
proxy = "socks5://LOGIN-cc-gb:[email protected]:7001"
with httpx.Client(proxy=proxy, timeout=30) as client:
print(client.get("https://api.ipify.org").text)aiohttp: HTTP proxy
aiohttp takes proxy= per request or once per ClientSession. A session also reuses connections, so the connector below has force_close=True for a new IP per request.
import asyncio
import aiohttp
PROXY = "http://LOGIN-cc-us:[email protected]:7000"
async def main():
connector = aiohttp.TCPConnector(force_close=True) # no keep-alive: a new IP per request
timeout = aiohttp.ClientTimeout(total=30)
async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
for _ in range(3):
async with session.get("https://api.ipify.org", proxy=PROXY) as r:
print(await r.text())
asyncio.run(main())aiohttp writes the proxy URL, password included, into ClientHttpProxyError messages. To keep the password out of logs, send it as a header instead: proxy_headers={"Proxy-Authorization": aiohttp.encode_basic_auth(login, password)} (aiohttp 3.14 or newer). The older proxy_auth=aiohttp.BasicAuth(...) is deprecated.
aiohttp: one sticky IP per worker
Give each task its own key. The three workers below run in parallel, each on its own IP for up to 15 minutes.
import asyncio
import secrets
import aiohttp
async def worker(session, n):
sid = secrets.token_hex(4) # each worker keeps its own IP
proxy = f"http://LOGIN-cc-us-sid-{sid}-ttl-15:[email protected]:7000"
for _ in range(2):
async with session.get("https://api.ipify.org", proxy=proxy) as r:
print(n, sid, await r.text())
async def main():
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=30)) as session:
await asyncio.gather(*(worker(session, n) for n in range(3)))
asyncio.run(main())aiohttp: SOCKS5
aiohttp has no SOCKS support of its own: a socks5:// URL in proxy= fails with Bad status line. Install aiohttp-socks and pass its connector to the session; rdns=True, its default, sends the host name to the proxy.
import asyncio
import aiohttp
from aiohttp_socks import ProxyConnector
async def main():
connector = ProxyConnector.from_url("socks5://LOGIN-cc-gb:[email protected]:7001", rdns=True)
async with aiohttp.ClientSession(connector=connector) as session:
async with session.get("https://api.ipify.org") as r:
print(await r.text())
asyncio.run(main())If it does not work
| What you see | What to check |
|---|---|
httpx.ProxyError: 407 Proxy Authentication Required or ClientHttpProxyError: 407 | The login, the password, or a key in the login that is not in the lists (a misspelled city, for example). |
| The same errors with 402 or 502 | 402: no traffic left on the product, or the sub-user reached its limit. 502: the exit failed; retry, and a rotating login takes a new IP. |
httpx.ConnectTimeout or ReadTimeout | httpx gives up after 5 seconds by default. Pass timeout=30, as in the examples. |
TypeError: ... unexpected keyword argument 'proxies' | Code written for older httpx: 0.28 removed proxies=. Use proxy=. |
ImportError: Using SOCKS proxy, but the 'socksio' package is not installed | Install httpx[socks]. |
Invalid username/password (httpx) or Username and password authentication failure (aiohttp-socks) | The SOCKS5 login: the same checks as for 407. |
| Every request shows the same IP | The client reuses one connection. Turn keep-alive off as shown, or give each request its own -sid- key. |
Questions
In httpx a client has one proxy, so open one client per country. In aiohttp the proxy is set per request, so one session can send each request with its own -cc- key.
As many as your code opens: bought traffic has no thread or connection limit on the gateway. Both libraries cap a client at 100 connections by default; raise httpx.Limits(max_connections=...) or TCPConnector(limit=...) if you need more.