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.