К содержимому

Python requests ProxyError: повторы и пауза между ними

По тексту ошибки отличите неверный логин от оборванного соединения и оберните запрос так, чтобы повторялись только стоящие повтора сбои.

Что значит ProxyError и три частые причины

ProxyError это подкласс ConnectionError, то есть ошибка возникает до ответа целевого сайта. По тексту в конце сообщения видно, какой это случай. В нашем локальном тесте отказ в логине закончился словами «Tunnel connection failed: 407 Proxy Authentication Required», а закрытый порт словами «Connection refused».

Причина 1: неверный хост, порт или протокол. У шлюза Proxy302 порт 2222 для HTTP и 3333 для SOCKS5. Для адреса SOCKS5 в requests нужен ещё pip install "requests[socks]". Причина 2: логин отклонён (407) из-за опечатки, пропущенного спецсимвола или пароля с @, который не закодирован через проценты в URL. Причина 3: актив закончился: арендованный IP после даты окончания или израсходованный баланс трафика.

Не каждый сбой это ProxyError. Ответ со статусом 429 или 503 это обычный ответ сайта или шлюза, а тайм-аут это отдельное исключение. Обрабатываются они по-разному, как показано в таблице.

Что делать с каждым сбоем

Что делать с каждым сбоем
ПунктПовторять?Что делать
ProxyError с окончанием 407НетИсправьте логин и остановитесь; каждый повтор будет отклонён снова
ProxyError, Connection refusedНетПроверьте хост, порт, протокол и не закончился ли актив
ConnectTimeoutДа, несколько разВ исходном коде Requests сказано, что такие запросы можно безопасно повторять
ReadTimeoutДа для GET, осторожно с POSTЗапрос мог уже дойти до сайта
429 Too Many RequestsДа, после паузыЕсли пришёл Retry-After, ждите указанное время, затем снизьте скорость
502, 503, 504Да, несколько разОбычно временная проблема на стороне шлюза или сайта
403, 404НетОтвет не изменится; меняйте запрос или цель

Составлено по исходному коду Requests, документации urllib3 Retry, MDN и нашему локальному тесту от 13 ноября 2026. Строки «Да» означают небольшое число повторов, а не гарантию успеха.

Исправление и защита за 5 шагов

  1. Шаг 1: прочитайте конец текста ошибки

    Один раз выведите str(exc). 407 указывает на логин, Connection refused или тайм-аут на адрес, порт, протокол или закончившийся актив.

  2. Шаг 2: проверьте тот же прокси через curl

    Выполните curl -x http://LOGIN:PASSWORD@HOST:2222 https://ipinfo.io/json со значениями из «Мои активы». Если curl работает, а Python нет, проверьте словарь proxies и переменные окружения с прокси: они могут перекрыть session.proxies.

  3. Шаг 3: задавайте тайм-аут в каждом вызове

    Без тайм-аута запрос никогда не сдаётся. Используйте кортеж, например timeout=(3.05, 20): подключение и чтение задаются отдельно.

  4. Шаг 4: добавьте повторы с паузой

    Только для кодов статуса достаточно подключить адаптер Retry (первый блок кода). Чтобы обработать ещё и ProxyError и остановку на 407, используйте цикл из второго блока кода.

  5. Шаг 5: ограничьте число попыток и сохраняйте последнюю ошибку

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

Адаптер Retry для кодов статуса

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

PROXY = "http://LOGIN:PASSWORD@HOST:2222"
PROXIES = {"http": PROXY, "https": PROXY}

retries = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[429, 502, 503, 504],
    allowed_methods={"GET"},
)
session = requests.Session()
session.mount("https://", HTTPAdapter(max_retries=retries))
session.mount("http://", HTTPAdapter(max_retries=retries))

response = session.get("https://ipinfo.io/json", proxies=PROXIES, timeout=(3.05, 20))
print(response.status_code, response.text)

Только пример: подставьте LOGIN, PASSWORD и HOST из «Мои активы»; специальные символы вроде @ в логине кодируйте через проценты. Пауза между повторами равна backoff_factor * 2 ** число предыдущих повторов.

Цикл, который останавливается при неверном логине

import random
import time

import requests

PROXY = "http://LOGIN:PASSWORD@HOST:2222"
PROXIES = {"http": PROXY, "https": PROXY}
RETRY_STATUS = {429, 502, 503, 504}
MAX_ATTEMPTS = 4


def fetch(url):
    last_error = None
    for attempt in range(1, MAX_ATTEMPTS + 1):
        delay = min(2 ** attempt, 30)  # 2, 4, 8, 16 seconds
        try:
            # a new Session opens a new connection, so a rotating line can give a new IP
            with requests.Session() as session:
                response = session.get(url, proxies=PROXIES, timeout=(3.05, 20))
            if response.status_code not in RETRY_STATUS:
                return response
            retry_after = response.headers.get("Retry-After", "")
            if retry_after.isdigit():
                delay = min(int(retry_after), 60)  # the server said how long to wait
            last_error = RuntimeError(f"HTTP {response.status_code}")
        except requests.exceptions.ProxyError as exc:
            if "407" in str(exc):
                raise  # wrong login: retrying will not help
            last_error = exc
        except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout) as exc:
            last_error = exc
        if attempt < MAX_ATTEMPTS:
            time.sleep(delay + random.uniform(0, 1))
    raise RuntimeError(f"gave up after {MAX_ATTEMPTS} attempts: {last_error}")


if __name__ == "__main__":
    print(fetch("https://ipinfo.io/json").text)

Только пример, логин условный. Каждая попытка открывает новую Session, то есть новое соединение; на ротационной линии новое соединение получает новый IP. Проверка 407 читает текст ошибки, это подтверждено локальным тестом на requests 2.32.5.

Повторы и ротация в Proxy302

В ротационных резидентных прокси каждое новое соединение получает новый IP, но requests.Session держит соединение открытым, поэтому много вызовов в одной Session обычно идут с одним IP. Потому цикл выше открывает новую Session на каждую попытку. Статические ISP и дата-центровые IP не меняются в течение аренды, и повтор через них идёт с тем же IP; от $0,25 за 1 день (дата-центр) и $0,50 (статический ISP).

Держите число попыток небольшим. На линиях с оплатой за ГБ каждая попытка, дошедшая до сайта, расходует трафик. Бесплатного пробного периода нет; минимальная покупка это 1 ГБ ротационного резидентного трафика или один IP на день.

Частые вопросы

Что значит requests.exceptions.ProxyError?

Проблема соединения с прокси, подкласс ConnectionError. Конец сообщения показывает, отклонён ли логин (407) или соединение не удалось открыть.

Повторяет ли requests запросы по умолчанию?

Нет. В документации сказано, что Requests по умолчанию не повторяет неудавшиеся соединения. Повторы добавляются через urllib3.util.Retry в HTTPAdapter.

Повторяет ли Retry запросы POST?

По умолчанию нет. allowed_methods по умолчанию содержит идемпотентные методы: DELETE, GET, HEAD, OPTIONS, PUT и TRACE. Добавляйте POST, только если его повтор безопасен.

Сколько длится пауза?

Пауза удваивается с каждым повтором вплоть до backoff_max (по умолчанию 120 секунд). В документации urllib3 для коэффициента 0,1 показаны 0,0, 0,2, 0,4 и 0,8 секунды, то есть перед первым повтором паузы нет. Заголовок Retry-After по умолчанию учитывается для 413, 429 и 503.

Почему ProxyError появляется только иногда?

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

Ссылки и источники

6
  1. Исходный код Requests: requests.exceptions

    Официальная документация · Проверено:

    Прочитано 13 ноября 2026: ProxyError наследует ConnectionError; ConnectTimeout наследует ConnectionError и Timeout, в его описании сказано, что запросы с этой ошибкой можно безопасно повторять; ReadTimeout наследует только Timeout; RetryError описан как «сбой пользовательской логики повторов».

  2. Документация Requests: расширенное использование

    Официальная документация · Проверено:

    Прочитано 13 ноября 2026: Requests по умолчанию не повторяет неудавшиеся соединения; повторы настраиваются через urllib3.util.Retry в HTTPAdapter(max_retries=...); без явного тайм-аута запрос не прерывается по времени, а кортеж задаёт тайм-ауты подключения и чтения отдельно; адрес прокси можно писать как http://user:password@host; session.proxies могут быть перекрыты прокси из переменных окружения; keep-alive внутри Session работает автоматически.

  3. Документация urllib3: urllib3.util.Retry

    Официальная документация · Проверено:

    Прочитано 13 ноября 2026: backoff_factor по умолчанию выключен (0); пауза равна backoff_factor * (2 ** число предыдущих повторов) вплоть до backoff_max (по умолчанию 120 с); status_forcelist по умолчанию выключен; allowed_methods по умолчанию содержит идемпотентные методы DELETE, GET, HEAD, OPTIONS, PUT, TRACE; заголовок Retry-After по умолчанию учитывается для 413, 429 и 503; raise_on_status решает, поднимать ли исключение после исчерпания повторов по статусу.

  4. MDN: 429 Too Many Requests

    Официальная документация · Проверено:

    Прочитано 13 ноября 2026: 429 означает, что клиент отправил слишком много запросов за период; заголовок Retry-After может указывать, сколько ждать до следующего запроса.

  5. Локальная проверка кода со страницы

    Локальный пример · Проверено:

    Запущено 13 ноября 2026 с requests 2.32.5 и urllib3 2.6.3 против локального тестового сервера в роли прокси: отказ 407 на CONNECT дал ProxyError с окончанием «Tunnel connection failed: 407 Proxy Authentication Required»; закрытый порт дал ProxyError с окончанием «Connection refused»; прокси, всегда отвечавший 503, привёл к RetryError у Retry; функция fetch() со страницы сразу подняла исключение на 407 и сдалась после заданного числа попыток на 503.

  6. Факты о продуктах и прайс Proxy302

    Наблюдение за продуктом · Проверено:

    Файл фактов о продуктах сайта (цены в долларах, 1 PTC = $1, протоколы и порты, сроки аренды; тесты протоколов от 4 ноября 2026 и линии динамических дата-центровых прокси от 10 ноября 2026). Проверено 13 ноября 2026.

Готовы попробовать?

Создайте аккаунт, пополните баланс и выберите ротируемый резидентный, статический ISP или дата-центр IP — настроить его в браузере можно за несколько минут.