Назад к блогу

Как настроить прокси в Python requests для парсинга, API и автоматизации: полный гайд с примерами кода

Полное руководство по подключению прокси в библиотеке Python requests — от базовой настройки до ротации IP и обхода блокировок при парсинге и автоматизации.

📅3 апреля 2026 г.

Если ваш скрипт на Python получает ошибку 403, CAPTCHA или бан по IP — значит, целевой сайт уже вас заметил. Подключение прокси к библиотеке requests решает эту проблему: вы меняете IP-адрес, обходите географические ограничения и распределяете нагрузку между несколькими адресами. В этом руководстве — всё от базового подключения до продвинутой ротации с реальными примерами кода.

Зачем нужны прокси в Python-скриптах

Большинство сайтов и API отслеживают IP-адреса входящих запросов. Если один адрес делает 100+ запросов в минуту — его блокируют. Это стандартная защита от ботов, которую используют Wildberries, Ozon, Авито, Google, Instagram и сотни других платформ. Прокси позволяет направить запрос через промежуточный сервер с другим IP-адресом, делая вас невидимым для систем защиты.

Вот основные задачи, где прокси в Python критически необходимы:

  • Парсинг маркетплейсов — сбор цен с Wildberries, Ozon, Яндекс.Маркет без блокировок по IP
  • Мониторинг конкурентов — регулярные запросы к сайтам конкурентов каждые 5–15 минут
  • Работа с API с лимитами — распределение запросов между несколькими IP, чтобы не превышать rate limit
  • Геолокационное тестирование — проверка, как сайт выглядит из разных стран и регионов
  • Автоматизация форм и регистраций — создание аккаунтов или заполнение форм с разных IP
  • SEO-мониторинг — снятие позиций из разных регионов России и других стран

Без прокси даже хорошо написанный парсер упрётся в блокировку уже через несколько часов работы. С правильно настроенной ротацией IP тот же скрипт работает неделями без остановок.

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

Библиотека requests поддерживает прокси нативно — никаких дополнительных пакетов не нужно. Прокси передаётся через словарь proxies в параметры запроса.

Самый простой пример — HTTP-прокси для одного запроса:

import requests

proxies = {
    "http": "http://123.45.67.89:8080",
    "https": "http://123.45.67.89:8080",
}

response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
# {'origin': '123.45.67.89'}
  

Обратите внимание: в словаре proxies нужно указывать оба ключа — http и https. Если указать только один, запросы по второму протоколу пойдут напрямую без прокси. Это частая ошибка новичков, из-за которой реальный IP всё равно утекает.

Чтобы убедиться, что прокси работает, используйте сервис httpbin.org/ip — он возвращает IP-адрес, с которого пришёл запрос. Если в ответе вы видите IP прокси-сервера, а не свой — всё настроено правильно.

HTTP, HTTPS и SOCKS5 прокси: отличия и примеры кода

Прокси бывают разных типов, и каждый подходит для своих задач. В контексте Python requests важно понимать разницу между тремя основными протоколами:

Тип Протокол в URL Скорость Поддержка UDP Лучший сценарий
HTTP http:// Высокая Нет Парсинг HTTP-сайтов
HTTPS https:// Высокая Нет Парсинг защищённых сайтов
SOCKS5 socks5:// Средняя Да Полная анонимность, любые протоколы

Для работы с SOCKS5 в Python нужно установить дополнительный пакет:

pip install requests[socks]
# или отдельно:
pip install PySocks
  

После установки подключение SOCKS5 прокси выглядит так:

import requests

# SOCKS5 прокси
proxies = {
    "http": "socks5://123.45.67.89:1080",
    "https": "socks5://123.45.67.89:1080",
}

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

SOCKS5 — предпочтительный протокол для задач, где важна анонимность. В отличие от HTTP-прокси, SOCKS5 не добавляет заголовки X-Forwarded-For, которые могут раскрыть ваш реальный IP.

Прокси с авторизацией по логину и паролю

Большинство платных прокси-сервисов используют аутентификацию по логину и паролю. Это стандартная практика — без авторизации прокси просто не пустит ваш запрос. В библиотеке requests данные авторизации передаются прямо в URL прокси.

import requests

# Формат: протокол://логин:пароль@хост:порт
proxy_url = "http://myuser:[email protected]:8080"

proxies = {
    "http": proxy_url,
    "https": proxy_url,
}

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

Если в пароле или логине есть специальные символы (например, @, #, %), их нужно URL-кодировать. Для этого используйте модуль urllib.parse:

import requests
from urllib.parse import quote

username = "myuser"
password = "p@ss#word!"  # Специальные символы

# URL-кодируем логин и пароль
encoded_user = quote(username, safe="")
encoded_pass = quote(password, safe="")

proxy_url = f"http://{encoded_user}:{encoded_pass}@123.45.67.89:8080"

proxies = {
    "http": proxy_url,
    "https": proxy_url,
}

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

💡 Совет по безопасности

Никогда не хардкодьте логин и пароль прямо в коде скрипта. Используйте переменные окружения или файл .env с библиотекой python-dotenv. Так вы избежите случайной утечки учётных данных при публикации кода на GitHub.

Ротация прокси: автоматическая смена IP для парсинга

Один прокси — это всё ещё один IP-адрес, который можно заблокировать. Настоящая защита от банов — это ротация: каждый запрос (или каждые N запросов) уходит с нового IP. Ниже — несколько подходов к реализации ротации.

Метод 1: Случайный выбор из списка

import requests
import random

# Список прокси
proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

def get_random_proxy():
    proxy = random.choice(proxy_list)
    return {"http": proxy, "https": proxy}

# Парсинг 10 страниц с ротацией IP
urls = [f"https://example.com/page/{i}" for i in range(1, 11)]

for url in urls:
    proxies = get_random_proxy()
    try:
        response = requests.get(url, proxies=proxies, timeout=10)
        print(f"URL: {url} | IP: {proxies['http'].split('@')[1]} | Status: {response.status_code}")
    except requests.RequestException as e:
        print(f"Ошибка: {e}")
  

Метод 2: Циклическая ротация через itertools

import requests
import itertools

proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

# Создаём бесконечный цикл по списку прокси
proxy_cycle = itertools.cycle(proxy_list)

def get_next_proxy():
    proxy = next(proxy_cycle)
    return {"http": proxy, "https": proxy}

# Каждый запрос использует следующий прокси по кругу
for i in range(9):
    proxies = get_next_proxy()
    response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
    print(f"Запрос {i+1}: {response.json()['origin']}")
  

Для промышленных задач с тысячами запросов в час рекомендуется использовать резидентные прокси с встроенной автоматической ротацией — провайдер сам меняет IP на каждый запрос через единый endpoint, и вам не нужно управлять списком адресов вручную.

Прокси через Session: постоянные соединения и куки

Когда нужно сделать несколько запросов в рамках одной сессии (например, залогиниться и затем делать запросы), используйте объект requests.Session(). Он сохраняет куки, заголовки и настройки прокси между запросами — не нужно передавать прокси в каждый вызов отдельно.

import requests

# Создаём сессию с прокси
session = requests.Session()
session.proxies = {
    "http": "http://user:[email protected]:8080",
    "https": "http://user:[email protected]:8080",
}

# Добавляем заголовки для имитации браузера
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Accept-Language": "ru-RU,ru;q=0.9",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
})

# Шаг 1: Авторизация
login_data = {"username": "myuser", "password": "mypass"}
session.post("https://example.com/login", data=login_data)

# Шаг 2: Запросы уже с куками и через прокси
response = session.get("https://example.com/dashboard")
print(response.status_code)

# Шаг 3: Закрываем сессию
session.close()
  

Использование Session также более эффективно с точки зрения производительности: TCP-соединение переиспользуется, а не открывается заново для каждого запроса. При парсинге 1000+ страниц это даёт ощутимый прирост скорости.

Обработка ошибок, таймаутов и автоматические повторы

Прокси-серверы могут быть недоступны, медленно отвечать или возвращать ошибки соединения. Надёжный скрипт для парсинга должен уметь обрабатывать эти ситуации и автоматически переключаться на другой прокси при сбое.

import requests
import random
import time

proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

def fetch_with_retry(url, max_retries=3, timeout=10):
    """
    Делает запрос с автоматической сменой прокси при ошибке.
    Возвращает объект Response или None при исчерпании попыток.
    """
    available_proxies = proxy_list.copy()
    random.shuffle(available_proxies)

    for attempt, proxy_url in enumerate(available_proxies[:max_retries], 1):
        proxies = {"http": proxy_url, "https": proxy_url}
        try:
            response = requests.get(
                url,
                proxies=proxies,
                timeout=timeout,
                headers={"User-Agent": "Mozilla/5.0"}
            )
            response.raise_for_status()  # Бросает исключение при 4xx/5xx
            print(f"✓ Успех с попытки {attempt}")
            return response

        except requests.exceptions.ProxyError:
            print(f"✗ Попытка {attempt}: прокси недоступен — {proxy_url}")
        except requests.exceptions.Timeout:
            print(f"✗ Попытка {attempt}: таймаут — {proxy_url}")
        except requests.exceptions.HTTPError as e:
            print(f"✗ Попытка {attempt}: HTTP ошибка {e.response.status_code}")
            if e.response.status_code == 403:
                print("  → Получен бан, пробуем следующий прокси...")
        except requests.exceptions.RequestException as e:
            print(f"✗ Попытка {attempt}: общая ошибка — {e}")

        time.sleep(1)  # Пауза между попытками

    print(f"✗ Все {max_retries} попытки исчерпаны для {url}")
    return None

# Использование
result = fetch_with_retry("https://httpbin.org/ip")
if result:
    print(result.json())
  

Обратите внимание на raise_for_status() — этот метод автоматически выбрасывает исключение при HTTP-статусах 4xx и 5xx. Без него скрипт будет считать успешным даже ответ с кодом 403 (бан) или 429 (превышен лимит запросов).

Прокси через переменные окружения: безопасное хранение данных

Библиотека requests автоматически читает переменные окружения HTTP_PROXY и HTTPS_PROXY. Это позволяет не хранить учётные данные в коде и легко переключаться между прокси без изменения скрипта.

Установка переменных в терминале (Linux/macOS):

export HTTP_PROXY="http://user:[email protected]:8080"
export HTTPS_PROXY="http://user:[email protected]:8080"
export NO_PROXY="localhost,127.0.0.1"
  

Или через файл .env с библиотекой python-dotenv:

# Файл .env (добавьте в .gitignore!)
HTTP_PROXY=http://user:[email protected]:8080
HTTPS_PROXY=http://user:[email protected]:8080
  
# Скрипт Python
from dotenv import load_dotenv
import requests
import os

load_dotenv()  # Загружаем переменные из .env

# requests автоматически использует HTTP_PROXY и HTTPS_PROXY
response = requests.get("https://httpbin.org/ip")
print(response.json())

# Или явно из переменных окружения:
proxies = {
    "http": os.getenv("HTTP_PROXY"),
    "https": os.getenv("HTTPS_PROXY"),
}
response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
  

⚠️ Важно: переменная NO_PROXY

Переменная NO_PROXY позволяет исключить определённые адреса из проксирования. Обязательно добавьте туда localhost и 127.0.0.1, чтобы локальные запросы не шли через прокси.

Реальные сценарии: парсинг маркетплейсов, работа с API и автоматизация

Рассмотрим три практических сценария, с которыми чаще всего сталкиваются разработчики.

Сценарий 1: Парсинг цен с маркетплейса

При мониторинге цен на Wildberries или Ozon важно имитировать поведение реального пользователя: передавать правильные заголовки браузера, добавлять задержки между запросами и ротировать IP. Для этой задачи хорошо подходят прокси дата-центров — они быстрые и дешёвые при работе с большими объёмами данных.

import requests
import time
import random

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "ru-RU,ru;q=0.9",
    "Referer": "https://www.wildberries.ru/",
}

PROXIES = [
    {"http": "http://user:[email protected]:8080",
     "https": "http://user:[email protected]:8080"},
    {"http": "http://user:[email protected]:8080",
     "https": "http://user:[email protected]:8080"},
]

def get_product_price(article_id: int) -> dict:
    """Получает цену товара по артикулу с Wildberries."""
    url = f"https://card.wb.ru/cards/v1/detail?appType=1&curr=rub&nm={article_id}"
    proxies = random.choice(PROXIES)

    try:
        resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        product = data["data"]["products"][0]
        return {
            "id": product["id"],
            "name": product["name"],
            "price": product["salePriceU"] / 100,  # цена в копейках
        }
    except (requests.RequestException, KeyError, IndexError) as e:
        return {"error": str(e)}

# Парсим несколько артикулов с задержкой
articles = [12345678, 87654321, 11223344]
for article in articles:
    result = get_product_price(article)
    print(result)
    time.sleep(random.uniform(1.5, 3.0))  # Случайная задержка 1.5-3 сек
  

Сценарий 2: Работа с API через прокси

Некоторые API ограничивают количество запросов с одного IP (rate limiting). Распределение запросов между несколькими прокси позволяет обойти это ограничение:

import requests
import itertools
from typing import Optional

class ProxyAPIClient:
    """Клиент для работы с API через ротацию прокси."""

    def __init__(self, api_key: str, proxy_list: list):
        self.api_key = api_key
        self.proxy_cycle = itertools.cycle(proxy_list)
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        })

    def _get_proxy(self) -> dict:
        proxy = next(self.proxy_cycle)
        return {"http": proxy, "https": proxy}

    def get(self, url: str, **kwargs) -> Optional[dict]:
        proxies = self._get_proxy()
        try:
            resp = self.session.get(url, proxies=proxies, timeout=10, **kwargs)
            resp.raise_for_status()
            return resp.json()
        except requests.RequestException as e:
            print(f"API запрос провалился: {e}")
            return None

# Использование
proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

client = ProxyAPIClient(api_key="your_api_key", proxy_list=proxy_list)
data = client.get("https://api.example.com/products")
  

Сценарий 3: Геолокационное тестирование

Маркетологи и SEO-специалисты часто проверяют, как сайт выглядит из разных регионов. С помощью прокси из нужных локаций можно автоматизировать этот процесс:

import requests

# Прокси из разных регионов
regional_proxies = {
    "Москва":        "http://user:[email protected]:8080",
    "Санкт-Петербург": "http://user:[email protected]:8080",
    "Новосибирск":   "http://user:[email protected]:8080",
    "США":           "http://user:[email protected]:8080",
}

url = "https://example.com/prices"

for region, proxy_url in regional_proxies.items():
    proxies = {"http": proxy_url, "https": proxy_url}
    try:
        resp = requests.get(url, proxies=proxies, timeout=15)
        print(f"[{region}] Статус: {resp.status_code} | "
              f"Размер: {len(resp.content)} байт")
    except requests.RequestException as e:
        print(f"[{region}] Ошибка: {e}")
  

Какой тип прокси выбрать для своей задачи

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

Задача Тип прокси Почему
Парсинг маркетплейсов (Wildberries, Ozon) Резидентные Выглядят как обычные пользователи, реже банятся
Парсинг открытых данных, новостей Дата-центры Быстрые, дешёвые, достаточно анонимные
Работа с Facebook API, Instagram Мобильные Соцсети доверяют мобильным IP больше всего
Геолокационное тестирование Резидентные с геотаргетингом Точная геолокация, реальные IP нужного региона
Высоконагруженный парсинг (10k+ запросов/час) Дата-центры (пул) Скорость и стоимость при больших объёмах
Авторизация и работа с аккаунтами Резидентные или мобильные Меньше триггеров антифрод-систем

Для задач, где важна максимальная надёжность и минимальный риск блокировки при работе с защищёнными сайтами, разработчики чаще всего выбирают мобильные прокси — они используют IP-адреса реальных мобильных операторов (МТС, Билайн, Мегафон), которые крайне редко попадают в блок-листы.

Чек-лист проверки прокси перед использованием

  • ✅ Проверьте IP через httpbin.org/ip — виден ли ваш реальный адрес?
  • ✅ Проверьте скорость — время ответа не должно превышать 2-3 секунды
  • ✅ Убедитесь, что прокси не в блок-листах через blocklist.de или ipqualityscore.com
  • ✅ Проверьте геолокацию через ipinfo.io — совпадает ли с ожидаемым регионом?
  • ✅ Протестируйте на целевом сайте с одним запросом перед запуском полного скрипта
  • ✅ Убедитесь, что HTTPS-трафик тоже идёт через прокси (оба ключа в словаре)

Заключение

Настройка прокси в Python requests — это не сложно, но требует внимания к деталям. Главные принципы, которые стоит запомнить: всегда указывайте оба ключа (http и https) в словаре прокси, используйте Session для многошаговых сценариев, обязательно обрабатывайте ошибки и таймауты, а учётные данные храните в переменных окружения, а не в коде.

Для промышленного парсинга с тысячами запросов в сутки ручного списка прокси недостаточно — нужна ротация. Если вы парсите защищённые маркетплейсы вроде Wildberries или Ozon, работаете с социальными сетями или тестируете геолокацию, рекомендуем попробовать резидентные прокси — они обеспечивают высокий уровень доверия со стороны антибот-систем и поддерживают автоматическую ротацию IP через единый endpoint, что значительно упрощает код вашего скрипта.