Install
Python 3.9 or newer. Session-level proxy= needs aiohttp 3.11 or later.
pip install aiohttpRotating residential
force_close=True on the connector closes each connection once its response is read, so every request opens a new tunnel through the residential gateway and leaves from a new address. The three lines should all differ.
import asyncio
import aiohttp
PROXY = "http://USER:[email protected]:8000"
async def main():
connector = aiohttp.TCPConnector(force_close=True)
timeout = aiohttp.ClientTimeout(total=30)
async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
for _ in range(3):
async with session.get("https://httpbin.org/ip", proxy=PROXY) as resp:
print((await resp.json())["origin"])
asyncio.run(main())A static datacenter or ISP IP
On a static datacenter IP you want keep-alive, so leave force_close off and set the proxy once on the session. limit=8 caps the connections in flight while gather works through the list. For an ISP order, use the host and port from your dashboard.
import asyncio
import aiohttp
PROXY = "http://USER:PASS@IP:PORT"
URLS = ["https://httpbin.org/ip", "https://httpbin.org/headers"]
async def fetch(session, url):
async with session.get(url) as resp:
return resp.status, (await resp.text())[:80]
async def main():
connector = aiohttp.TCPConnector(limit=8)
timeout = aiohttp.ClientTimeout(total=30, sock_connect=10)
async with aiohttp.ClientSession(proxy=PROXY, connector=connector, timeout=timeout) as session:
for status, text in await asyncio.gather(*(fetch(session, url) for url in URLS)):
print(status, text)
asyncio.run(main())Keeping one identity
With the default connector, a session reuses idle connections, so requests to one host share a tunnel and its exit address until the connection closes. The session's cookie jar persists across all of them. If a site ties cookies to an IP, run that flow on a static IP or a residential sticky session, whose setting for your account is in the dashboard, rather than on the rotating gateway. Libraries built on aiohttp behave the same way underneath; discord.py is one, and Discord bots with discord.py shows where its proxy goes.