Your scraper runs fine on the first request. By the tenth, you're blocked.
Most websites track repeated requests from the same IP. Hit a rate limit, trigger a CAPTCHA, or look like a bot… and your script stops dead. The fix is IP rotation: swapping your IP address between requests so no single address sends too many.
Python makes this straightforward. With the right proxy setup, you can rotate IP addresses automatically, keep requests flowing, and handle CAPTCHA without rewriting your scraping logic from scratch.
This guide covers how rotating proxy IPs work in Python, which libraries to use, and how to set up IP rotation with code examples you can use today.
Rotating proxy: a crash course
A proxy server sits between your scraper and the target website. Rotating proxy IPs take this further – they swap your IP address automatically between requests, based on a time interval, a status code, or a request count.
Why does this matter? Websites flag repeated requests from the same IP as bot traffic. With rotating proxy IP addresses, your requests look like they're coming from different users – which gets you past rate limits, CAPTCHA triggers, and geo-based blocking.
You have two options: use a third-party rotating proxy service that handles rotation for you, or build your own in Python. This guide covers both.
Rotate IP address – Python guide
This section walks you through setting up your Python environment and building a simple proxy rotator using the Requests library. You'll load a list of proxies from a CSV file and rotate through them, one IP per request.
Install prerequisites
Start by creating a virtual environment. Run:
virtualenv venv
This will install Python, pip, and common libraries in your venv folder. Next, activate the environment:
source venv/bin/activate
Then install the requests module:
pip install requests
Now, run it from a terminal:
python no_proxy.py
128.90.50.100
The output shows your current IP address. Now let's add a proxy and start rotating.
Send requests through a proxy
To use a single proxy, you need four things:
- Scheme (e.g., HTTP)
- IP address
- Port (e.g., 3128)
- Username and password (optional)
Format them like this:
SCHEME://USERNAME:PASSWORD@YOUR_PROXY_IP:YOUR_PROXY_PORT
Here are other proxy formats you might run into:
http://2.56.215.247:3128
https://2.56.215.247:8091
https://my-user:aegi1Ohz@2.56.215.247:8044
You can also map different proxies to specific protocols or domains:
scheme_proxy_map = {
'http': PROXY1,
'https': PROXY2,
'https://example.org': PROXY3,
}
Add these imports to your file:
import requests
from requests.exceptions import ProxyError, ReadTimeout, ConnectTimeout
Then call requests.get with your proxy variables. The exceptions handle network issues, useful for tracking which proxies fail.
try:
response = requests.get('https://ip.oxylabs.io/location', proxies=scheme_proxy_map, timeout=TIMEOUT_IN_SECONDS)
except (ProxyError, ReadTimeout, ConnectTimeout) as error:
print('Unable to connect to the proxy: ', error)
else:
print(response.text)
The output of this script should show you the IP of your proxy:
python single_proxy.py
2.56.215.247
You're now routing requests through a single proxy.
Next up: rotating through a list of them.
Rotating proxy through a pool
For this part, you'll need a CSV file called proxies.csv with one proxy per line:
http://2.56.215.247:3128
https://88.198.24.108:8080
http://50.206.25.108:80
http://68.188.59.198:80
... any other proxy server, each on a separate line
Create a Python file and define the CSV filename and timeout:
import requests
from requests.exceptions import ProxyError, ReadTimeout, ConnectTimeout
import csv
TIMEOUT_IN_SECONDS = 10
CSV_FILENAME = 'proxies.csv'
Next, open the CSV file and build the proxy map:
with open(CSV_FILENAME) as open_file:
reader = csv.reader(open_file)
for csv_row in reader:
scheme_proxy_map = {
'https': csv_row[0],
}
To verify it works, add the request inside the same loop:
with open(CSV_FILENAME) as open_file:
reader = csv.reader(open_file)
for csv_row in reader:
scheme_proxy_map = {
'https': csv_row[0],
}
# Access the website via a proxy
try:
response = requests.get('https://ip.oxylabs.io/location', proxies=scheme_proxy_map, timeout=TIMEOUT_IN_SECONDS)
except (ProxyError, ReadTimeout, ConnectTimeout) as error:
pass
else:
print(response.text)
To stop after the first working proxy, add a break after the print:
try:
response = requests.get('https://ip.oxylabs.io/location', proxies=scheme_proxy_map, timeout=TIMEOUT_IN_SECONDS)
except (ProxyError, ReadTimeout, ConnectTimeout) as error:
pass
else:
print(response.text)
break # Notice the break here
One thing still limits this setup: speed. Sequential requests are slow – async fixes that.
Dynamic rotating proxy for scraping with async aiohttp
To rotate proxies asynchronously, you'll use asyncio and aiohttp. asyncio comes with Python – install aiohttp with:
pip install aiohttp
Then create a new Python file and import the libraries:
import asyncio
import aiohttp
import csv
Next, define your constants:
- CSV filename for the proxy list
- URL to test each proxy against
- Timeout per proxy
CSV_FILENAME = 'proxies.csv'
URL_TO_CHECK = 'https://ip.oxylabs.io/location'
TIMEOUT_IN_SECONDS = 10
Next, you need to define an async function and run it using the asyncio module. It accepts two parameters:
- The URL it needs to request
- The proxy to use to access it
Then, you need to print the response. If the script receives an error when attempting to access the URL via proxy, it will print it as well:
async def check_proxy(url, proxy):
try:
session_timeout = aiohttp.ClientTimeout(
total=None,
sock_connect=TIMEOUT_IN_SECONDS,
sock_read=TIMEOUT_IN_SECONDS
)
async with aiohttp.ClientSession(timeout=session_timeout) as session:
async with session.get(url, proxy=proxy, timeout=TIMEOUT_IN_SECONDS) as resp:
print(await resp.text())
except Exception as error:
# you can comment out this line to only see valid proxies printed out in the command line
print('Proxy responded with an error: ', error)
return
You should then run the main() function. Wait until all the async tasks are completed.
asyncio.run(main())
That's it! Your proxies will now be running at top speed.
Rotating proxy tips for flawless web scraping
Rotating proxy IPs with Python is just step one. The tips below will help you work at scale:
Pair rotating proxy IPs with user-agent rotation. Websites don't just track IPs, they also read user-agent strings to identify your browser, OS, and device. Hundreds of requests from the same browser fingerprint look just as suspicious as requests from the same IP. Rotate both together for better results.
Choose a reliable proxy service. Look for transparent proxy providers that document how their proxies are sourced, especially for residential proxies. Good services include sticky sessions, clear rotation controls, and a large proxy pool. A few of the best rotating proxy IP providers in 2026 are Oxylabs, Decodo, and Webshare – all worth a look.
Free proxies work for small tasks. If you go that route, pick a paid provider that also offers a free tier – they tend to maintain better standards than anonymous free lists.
Skip the infrastructure with a scraper API. Building a rotator in Python works, but it takes time to maintain. For example, Oxylabs' Web Scraper API handles rotation, CAPTCHA, and JavaScript rendering out of the box, no proxy management required.
To summarize
Rotating proxy IPs is one of the most effective ways to make web scraping workflows more resilient. By distributing requests across multiple IP addresses, you can access and collect publicly available data more efficiently.

Top comments (0)