ProxyGrow LogoProxyGrow

2025-10-30 · 9 min read

Python Requests с ротацией мобильных прокси: полное руководство с кодом

Пошаговый туториал: как использовать ротацию мобильных прокси в Python. Настройка библиотеки requests, конфигурация SOCKS5, авто-ротация через API и паттерны защиты от бана.

Библиотека requests — самый популярный HTTP-клиент в экосистеме Python. Объединение её с ротацией мобильных прокси — это разница между парсером, который работает часами, и тем, который блокируется за минуты.

IP-адреса датацентров блокируются на уровне ASN до отправки первого запроса. Резидентные прокси лучше, но быстро сгорают под интенсивной нагрузкой. Мобильные прокси на реальных 4G/5G модемах несут ASN мобильных операторов, которые практически невозможно заблокировать в масштабе — блокировка означает блокировку тысяч реальных мобильных пользователей, делящих один и тот же IP-диапазон CGNAT.

Этот туториал охватывает полную настройку: от первого pip install до production-парсера с автоматической ротацией IP, логикой повторных попыток и антидетект-заголовками.

Get Rotating Mobile Proxies

Real 4G/5G IPs with API rotation — Ukraine, Romania, Latvia. From $50/mo dedicated.

Real 4G/5G IPsSOCKS5 / HTTP / UDP / VLESSUSDT paymentsFast activation
Get Started Now → @ProxyGrow

Необходимые условия

Установите необходимые пакеты. Расширение requests[socks] добавляет поддержку SOCKS5 через urllib3, а PySocks отвечает за низкоуровневый протокол:

pip install requests "requests[socks]" python-socks

Проверьте, что установка прошла успешно:

import requests
import socks  # from PySocks

print(requests.__version__)

Вам также понадобятся учётные данные ProxyGrow: хост, порт, имя пользователя, пароль и URL ротационного API (доступны в личном кабинете ProxyGrow).

Базовая настройка прокси с requests

Самый простой способ направить запрос через SOCKS5-прокси — параметр proxies:

import requests

proxies = {
    'http': 'socks5h://username:password@host:port',
    'https': 'socks5h://username:password@host:port',
}

response = requests.get('https://httpbin.org/ip', proxies=proxies)
print(response.json())

Запустите это — в ответе будет украинский, румынский или латвийский IP мобильного оператора вместо вашего реального адреса.

Почему socks5h, а не socks5

Это самая важная деталь в конфигурации прокси для Python:

  • socks5: DNS-разрешение происходит на вашем компьютере, затем уже разрешённый IP передаётся через прокси. Ваши DNS-запросы видны.
  • socks5h: DNS-разрешение происходит через прокси, на удалённой стороне. Ваша машина никогда не разрешает имя хоста напрямую.

Буква h означает «host-name» — имя хоста передаётся через туннель и разрешается на сервере прокси. Это критично для анонимности: утечки DNS могут раскрыть ваше реальное местоположение даже когда HTTP-трафик корректно проксируется.

Всегда используйте socks5h для парсинга. Единственная причина использовать обычный socks5 — если сервер прокси не поддерживает удалённое DNS-разрешение, но серверы ProxyGrow поддерживают.

Сессионные прокси (постоянная SOCKS5 сессия)

Создание объекта Session — почти всегда правильный подход. Сессии переиспользуют базовое TCP-соединение, автоматически хранят cookies и позволяют задать прокси и заголовки один раз вместо каждого вызова:

import requests

session = requests.Session()
session.proxies = {
    'http': 'socks5h://user:pass@host:port',
    'https': 'socks5h://user:pass@host:port',
}

# All requests through this session use the proxy
r = session.get('https://example.com')
print(r.status_code)

Для рабочих процессов парсинга с десятками или сотнями запросов сессия экономит накладные расходы на соединение и сохраняет аутентификацию прокси. Вы настраиваете прокси один раз и забываете о нём.

Ротация IP через ProxyGrow API

Ротация IP — это не переключение между разными прокси-серверами, а запуск переподключения на физическом модеме, чтобы оператор назначил новый IP-адрес. ProxyGrow предоставляет это как простой API-вызов.

Вот полный рабочий процесс ротации:

import requests
import time

PROXY_HOST = "your-proxy-host"
PROXY_PORT = 1080
PROXY_USER = "username"
PROXY_PASS = "password"
ROTATION_URL = "https://api.proxygrow.com/rotate?key=YOUR_API_KEY"

def rotate_ip():
    requests.get(ROTATION_URL)
    time.sleep(5)  # wait for modem to reconnect

def get_current_ip(session):
    r = session.get('https://httpbin.org/ip')
    return r.json()['origin']

session = requests.Session()
session.proxies = {
    'http': f'socks5h://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
    'https': f'socks5h://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
}

urls_to_scrape = [
    'https://example.com/page/1',
    'https://example.com/page/2',
    # ... more URLs
]

# Scrape with rotation every 10 requests
for i, url in enumerate(urls_to_scrape):
    if i > 0 and i % 10 == 0:
        rotate_ip()
        print(f"Rotated IP. New IP: {get_current_ip(session)}")
    r = session.get(url)
    # process r.text

Почему ротация каждые 10 запросов, а не каждый запрос? Слишком частая ротация тратит время (каждое переподключение занимает 3-6 секунд) и может вызвать ограничения скорости на самом ротационном API. Слишком редкая ротация позволяет целевому сайту формировать поведенческий профиль на одном IP. Каждые 10-20 запросов — практический баланс для большинства целей.

Почему time.sleep(5) после ротации? Модем отключается от сети оператора, проводит повторное согласование и получает новый IP через DHCP или назначение CGNAT. Если ваш следующий запрос уйдёт до полного переподключения модема — получите ошибку соединения. Пять секунд надёжно покрывают окно переподключения.

Обработка ошибок и логика повторных попыток

Сетевые ошибки неизбежны при работе с прокси. Модемы переподключаются, операторы ограничивают скорость, цели возвращают 429. Механизм повторных попыток urllib3 автоматически обрабатывает временные сбои:

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[429, 500, 502, 503],
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)

Что делает каждый параметр:

  • total=3: повторять до 3 раз перед отказом
  • backoff_factor=1: ждать 1с, затем 2с, затем 4с между попытками (экспоненциальный откат)
  • status_forcelist: считать эти HTTP-коды повторяемыми ошибками

Монтируйте адаптер на http:// и https:// для охвата всех запросов. Делайте это один раз после создания сессии, до выполнения запросов.

Настройка реалистичных заголовков для обхода детектирования

IP мобильного оператора с заголовками десктопного браузера — статистическая аномалия. Реальный трафик с Kyivstar или Orange Romania преимущественно исходит с мобильных устройств. Антибот-системы знают это и помечают несоответствия.

Задайте заголовки, совместимые с происхождением прокси:

session.headers.update({
    'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15',
    'Accept-Language': 'uk-UA,uk;q=0.9,en;q=0.8',  # match proxy country
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Connection': 'keep-alive',
})

Ключевые моменты:

  • User-Agent: используйте мобильный UA. Для украинских прокси подходят iOS или Android. Для румынских — то же самое: большинство мобильных пользователей в Румынии и Украине используют iOS или Android.
  • Accept-Language: соответствуйте стране прокси. uk-UA для Украины, ro-RO для Румынии, lv-LV для Латвии. Некоторые сайты проверяют это как сигнал согласованности.
  • Accept-Encoding: всегда включайте br (Brotli). Реальные браузеры отправляют его. Парсеры, которые его опускают, легче идентифицировать.

Ограничение скорости между запросами

Запросы со скоростью машины — моментальный сигнал детектирования. Добавляйте случайные задержки между запросами для имитации паттернов просмотра человека:

import time
import random

for url in urls_to_scrape:
    r = session.get(url)
    # process r.text
    time.sleep(random.uniform(1, 3))

random.uniform(1, 3) возвращает число с плавающей точкой от 1.0 до 3.0 секунд — ваш парсер работает со скоростью 20-60 запросов в минуту. Это в диапазоне быстрого пользователя-человека и значительно ниже порогов, которые запускают автоматическое ограничение скорости на большинстве сайтов.

Для более защищённых целей увеличьте диапазон: random.uniform(2, 6). Для внутренних API или целей без антибот-защиты можно уменьшить.

Проверка работы прокси

Перед запуском полноценного парсинга всегда проверяйте, что прокси активен и ротация действительно меняет IP:

import requests
import time

PROXY_HOST = "your-proxy-host"
PROXY_PORT = 1080
PROXY_USER = "username"
PROXY_PASS = "password"
ROTATION_URL = "https://api.proxygrow.com/rotate?key=YOUR_API_KEY"

session = requests.Session()
session.proxies = {
    'http': f'socks5h://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
    'https': f'socks5h://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
}

# Check IP before rotation
ip_before = session.get('https://httpbin.org/ip', timeout=10).json()['origin']
print(f"IP before rotation: {ip_before}")

# Trigger rotation
requests.get(ROTATION_URL)
time.sleep(5)

# Check IP after rotation
ip_after = session.get('https://httpbin.org/ip', timeout=10).json()['origin']
print(f"IP after rotation:  {ip_after}")

if ip_before != ip_after:
    print("Rotation successful.")
else:
    print("Warning: IP did not change. Check rotation URL or wait longer.")

Запускайте это перед каждой новой сессией парсинга. Если IP одинаковые — либо неправильный URL ротации, либо модем не завершил переподключение. Увеличьте время ожидания и попробуйте снова.

Интеграция со Scrapy

Для масштабных проектов парсинга система middleware Scrapy позволяет подключить ротацию прокси на уровне паука. Паттерн — кастомный DownloaderMiddleware, который устанавливает request.meta['proxy'] для каждого исходящего запроса и запускает ротацию на основе счётчика или кода ответа.

Основная идея:

class ProxyRotationMiddleware:
    def process_request(self, request, spider):
        request.meta['proxy'] = 'socks5h://user:pass@host:port'
        # Rotation logic: call the API every N requests

Для более простых настроек Scrapy пакет scrapy-rotating-proxies управляет пулом, но не поддерживает ротацию модема через API, которую предоставляет ProxyGrow. Кастомный middleware даёт полный контроль над временем и способом ротации.

Частые ошибки и способы их устранения

requests.exceptions.ConnectionError

Прокси-сервер недоступен. Причины:

  • Неправильный хост или порт в URL прокси
  • Модем в процессе переподключения после ротации
  • Проблема сети между вашей машиной и прокси-сервером

Решение: проверьте учётные данные, подождите 5-10 секунд после ротации, убедитесь что хост разрешается корректно.

requests.exceptions.ProxyError

Прокси-сервер отклонил соединение — обычно из-за ошибки аутентификации. Причины:

  • Неправильное имя пользователя или пароль
  • Учётные данные истекли или отозваны
  • Ваш IP не в белом списке, если прокси использует аутентификацию по IP

Решение: перепроверьте имя пользователя и пароль в личном кабинете ProxyGrow. Убедитесь, что используете формат socks5h://user:pass@host:port (не http://).

requests.exceptions.Timeout

Запрос не завершился в течение периода тайм-аута. Наиболее распространённые причины в настройках прокси:

  • Запрос сразу после ротации (модем ещё переподключается)
  • Целевой сайт медленно отвечает
  • Модем временно потерял сигнал

Решение: всегда задавайте явные тайм-ауты и всегда выжидайте после ротации:

try:
    r = session.get(url, timeout=(10, 30))  # (connect timeout, read timeout)
except requests.exceptions.Timeout:
    print(f"Request to {url} timed out — retrying after delay")
    time.sleep(10)

Форма кортежа (connect_timeout, read_timeout) полезнее одиночного значения, потому что соединение с прокси и ответ сервера имеют разные характеристики отказа.

Полный рабочий пример

Всё вместе — парсер с сессией, ротацией, повторными попытками, заголовками и обработкой ошибок:

import requests
import time
import random
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

PROXY_HOST = "your-proxy-host"
PROXY_PORT = 1080
PROXY_USER = "username"
PROXY_PASS = "password"
ROTATION_URL = "https://api.proxygrow.com/rotate?key=YOUR_API_KEY"

def build_session():
    session = requests.Session()
    session.proxies = {
        'http': f'socks5h://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
        'https': f'socks5h://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
    }
    session.headers.update({
        'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15',
        'Accept-Language': 'uk-UA,uk;q=0.9,en;q=0.8',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    })
    retry = Retry(total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503])
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    return session

def rotate_ip():
    try:
        requests.get(ROTATION_URL, timeout=10)
        time.sleep(5)
    except Exception as e:
        print(f"Rotation error: {e}")
        time.sleep(10)

def scrape(urls):
    session = build_session()

    for i, url in enumerate(urls):
        if i > 0 and i % 10 == 0:
            rotate_ip()

        try:
            r = session.get(url, timeout=(10, 30))
            r.raise_for_status()
            print(f"[{i}] {url} — {len(r.text)} bytes")
            # process r.text here
        except requests.exceptions.ProxyError:
            print(f"[{i}] Proxy auth error — check credentials")
        except requests.exceptions.Timeout:
            print(f"[{i}] Timeout — skipping {url}")
        except requests.exceptions.HTTPError as e:
            print(f"[{i}] HTTP {e.response.status_code} — {url}")

        time.sleep(random.uniform(1, 3))

urls = [f"https://example.com/page/{n}" for n in range(1, 51)]
scrape(urls)

Этот код обрабатывает 50 URL, выполняет ротацию каждые 10, автоматически повторяет временные сбои и выводит понятные сообщения об ошибках для каждого типа отказа.

Get Rotating Mobile Proxies

Real 4G/5G IPs with API rotation — Ukraine, Romania, Latvia. From $50/mo dedicated.

Real 4G/5G IPsSOCKS5 / HTTP / UDP / VLESSUSDT paymentsFast activation
Get Started Now → @ProxyGrow

Итоги

Ключевые тезисы этого руководства:

  • Используйте socks5h:// вместо socks5:// — удалённое DNS-разрешение обязательно для анонимности
  • Используйте requests.Session для всех многозапросных рабочих процессов
  • Ротируйте IP через ProxyGrow API, а не путём переключения прокси-серверов
  • Всегда ждите 5 секунд после запуска ротации перед следующим запросом
  • Задавайте заголовки, соответствующие стране прокси и типу IP (мобильный UA для мобильных прокси)
  • Добавляйте задержки random.uniform(1, 3) между запросами
  • Используйте Retry с backoff_factor для обработки временных сбоев без ручных циклов повторов
  • Соответствуйте Accept-Language гео-локации прокси — это сигнал согласованности, который проверяют антибот-системы

Ready to get real mobile proxies?

Ukraine · Romania · Latvia — 4G/5G carrier IPs, instant activation.