Web scraping at scale means dealing with IP blocks. Modern anti-bot systems detect datacenter IPs instantly, throttle residential proxies, and identify patterns in request behavior. The most reliable solution in 2026 is rotating mobile proxies — real 4G/5G IPs that blend in with legitimate mobile traffic.
This guide covers setup, rotation strategies, and code examples for Python-based scrapers.
Mobile Proxies for Scraping
Real 4G/5G carrier IPs — Ukraine, Romania, Latvia. Instant rotation via API.
Why Mobile Proxies Beat Datacenter for Scraping
Datacenter proxies are fast and cheap but get blocked easily because:
- Their ASNs (Amazon, DigitalOcean, Hetzner) are well-known and blocklisted
- IP ranges are small — ban one IP and the whole subnet is suspect
- No CGNAT — each IP maps to one client, easy to identify
Mobile carrier IPs work better because:
- They belong to legitimate mobile ASNs (Kyivstar, Orange, T-Mobile)
- CGNAT means thousands of real users share the same IP pool
- Banning a mobile carrier IP affects real users — sites are reluctant to do it
- Carrier ranges change constantly as IPs rotate between SIM cards
How IP Rotation Works
ProxyGrow mobile proxies support two rotation methods:
Timer-based rotation: The proxy automatically changes the exit IP every N minutes (minimum 3 minutes on Shared plans, configurable on Premium).
API-based rotation: You call a unique URL to trigger an instant IP change. The IP changes in 3–5 seconds. The proxy credentials (host:port:user:pass) stay the same — only the exit IP changes.
GET https://your-rotation-url.proxygrow.com/rotate/TOKEN
This is ideal for scrapers: rotate between requests or after a block is detected.
Python: Basic Proxy Setup
requests library
import requests
proxy = {
'http': 'socks5://user:[email protected]:5000',
'https': 'socks5://user:[email protected]:5000',
}
response = requests.get('https://example.com', proxies=proxy, timeout=15)
print(response.text)
For SOCKS5, install requests[socks]:
pip install requests[socks]
Rotating IP between requests
import requests
import time
PROXY = 'socks5://user:[email protected]:5000'
ROTATION_URL = 'https://your-rotation-url'
def rotate_ip():
requests.get(ROTATION_URL, timeout=10)
time.sleep(5) # wait for IP change to propagate
def scrape(url):
proxies = {'http': PROXY, 'https': PROXY}
return requests.get(url, proxies=proxies, timeout=15)
urls = ['https://example.com/page/1', 'https://example.com/page/2']
for i, url in enumerate(urls):
if i % 5 == 0 and i > 0:
rotate_ip()
response = scrape(url)
print(response.status_code)
Playwright: Browser-Based Scraping
Playwright scrapes JavaScript-heavy sites. Combine it with mobile proxies for maximum stealth.
import asyncio
from playwright.async_api import async_playwright
async def scrape_with_playwright():
async with async_playwright() as p:
browser = await p.chromium.launch(
proxy={
'server': 'socks5://proxy.proxygrow.com:5000',
'username': 'your_user',
'password': 'your_pass',
}
)
page = await browser.new_page()
# Set mobile viewport for better fingerprint match
await page.set_viewport_size({'width': 390, 'height': 844})
await page.goto('https://example.com')
content = await page.content()
print(content[:500])
await browser.close()
asyncio.run(scrape_with_playwright())
Tip: Use mobile viewport (390×844 for iPhone 14) to match the mobile proxy fingerprint. A desktop viewport with a mobile IP looks inconsistent.
Scrapy: Large-Scale Crawling
For high-volume crawls, Scrapy with a rotating proxy middleware is the standard approach.
Install the middleware:
pip install scrapy-rotating-proxies
settings.py:
ROTATING_PROXY_LIST = [
'socks5://user:[email protected]:5000',
]
DOWNLOADER_MIDDLEWARES = {
'rotating_proxies.middlewares.RotatingProxyMiddleware': 610,
'rotating_proxies.middlewares.BanDetectionMiddleware': 620,
}
ROTATING_PROXY_PAGE_RETRY_TIMES = 3
For a single mobile proxy with API rotation, create a custom middleware:
# middlewares.py
import requests
import time
class MobileProxyRotateMiddleware:
def __init__(self, rotation_url, rotate_every=10):
self.rotation_url = rotation_url
self.rotate_every = rotate_every
self.request_count = 0
def process_request(self, request, spider):
self.request_count += 1
if self.request_count % self.rotate_every == 0:
requests.get(self.rotation_url, timeout=10)
time.sleep(5)
request.meta['proxy'] = 'socks5://user:[email protected]:5000'
Anti-Bot Evasion Tips
Respect crawl delays
DOWNLOAD_DELAY = 2 # 2 seconds between requests
AUTOTHROTTLE_ENABLED = True
Random delays are better than fixed ones:
import random
time.sleep(random.uniform(1, 4))
Set realistic headers
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36',
'Accept-Language': 'uk-UA,uk;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
}
Match the User-Agent to your proxy country. An Android Ukrainian UA with a Kyivstar IP is a believable combination.
Handle blocks gracefully
Detect blocks (403, CAPTCHA page, redirect to anti-bot challenge) and rotate IP:
def is_blocked(response):
if response.status_code in (403, 429):
return True
if 'captcha' in response.text.lower():
return True
return False
if is_blocked(response):
rotate_ip()
response = scrape(url)
Shared vs Premium for Scraping
| Shared | Premium | |
|---|---|---|
| Rotation speed | 3 min minimum | Instant |
| Simultaneous connections | Shared with others | Unlimited |
| Speed | 10–50 Mbps | up to 150 Mbps |
| Best for | Light scraping, testing | Heavy scraping, production |
For production scrapers making hundreds of requests per hour, Premium plans with instant rotation and unlimited connections are the right choice.
Get Mobile Proxies for Scraping
Instant API rotation · Unlimited connections on Premium · Real carrier IPs.