ProxyError в requests: Unable to connect to proxy

Библиотека requests не смогла пройти через прокси: либо не соединилась с ним, либо прокси отказался открывать туннель к сайту. Что именно произошло, видно из длинного текста ошибки.

Обновлено · Редакция Prokso

Коротко
  • ProxyError означает, что requests не прошёл через прокси: не подключился или не получил туннель
  • Настоящую причину видно в скобках после Caused by, а слово после 407 или 503 называет её точно
  • Задайте строку прокси со схемой http:// для обоих ключей словаря и проверьте переменные окружения

Что означает ошибка

Сообщение выглядит так: HTTPSConnectionPool(host='example.com', port=443): Max retries exceeded with url: / (Caused by ProxyError('Unable to connect to proxy', ...)). Главное стоит в скобках после Caused by. Библиотека urllib3, на которой работает requests, оборачивает настоящую причину в ProxyError, а requests выдаёт её как requests.exceptions.ProxyError.

Слова Max retries exceeded не означают, что попыток было много. По документации requests по умолчанию не повторяет неудачные соединения, так что этот текст появляется уже после первой попытки. В старой ветке urllib3 1.26 вместо Unable to connect to proxy писалось Cannot connect to proxy. Смысл тот же.

Внутри обычно один из двух вариантов. NewConnectionError с Connection refused или ConnectTimeoutError значит, что к прокси не удалось даже подключиться. OSError('Tunnel connection failed: 407 NO_USER') значит, что соединение с прокси есть, но на запрос CONNECT он ответил не кодом 200. После кода стоит текст ответа, и в Prokso он называет причину: NO_USER, TRAFFIC_EXHAUSTED, THREADS_EXHAUSTED, NO_RAY или NO_HOST_CONNECTION.

Причины

  • Неверный хост или порт. Connection refused или тайм-аут подключения: в строке не gw.prokso.com или порт вне 823, 824 и 10000–20000.
  • Логин или пароль не приняты. Tunnel connection failed: 407 NO_USER означает ошибку в логине или пароле. Если вы входите по IP, текущего адреса нет в списке разрешённых.
  • Исчерпан лимит плана. 407 TRAFFIC_EXHAUSTED: закончился трафик. 407 THREADS_EXHAUSTED: открыто больше 1000 одновременных соединений на план.
  • Нет адреса под гео или сайт недоступен. 503 NO_RAY: под выбранные страну, город или ASN сейчас нет свободного IP. 502 NO_HOST_CONNECTION: прокси не смог соединиться с сайтом.
  • Спецсимволы в пароле без кодирования. Символы @, : или # в логине или пароле ломают разбор строки, и к прокси доходят не те данные.

Как исправить

  1. Скопируйте строку прокси из личного кабинета заново и задайте её для обоих ключей: proxies={'http': 'http://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823', 'https': 'http://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823'}. Схема самого прокси здесь http://, даже когда сайт работает на https://.
  2. Если в пароле есть спецсимволы, закодируйте логин и пароль через urllib.parse.quote(ПАРОЛЬ, safe='') перед тем, как вставить их в строку.
  3. Прочитайте слово после кода в Tunnel connection failed. При NO_USER проверьте логин и список IP, при TRAFFIC_EXHAUSTED пополните трафик, при THREADS_EXHAUSTED уменьшите число потоков, при NO_RAY расширьте гео.
  4. Проверьте переменные окружения HTTP_PROXY, HTTPS_PROXY и ALL_PROXY. Requests их читает, и документация предупреждает, что они могут перекрыть session.proxies. Надёжнее передавать proxies= в каждый запрос.
  5. Задайте timeout=(10, 30) и добавьте повтор с паузой для 502 и 503: на порту 823 повтор пойдёт уже через другой IP. Полный пример есть в инструкции Python requests, а общий порядок поиска причины описан на странице устранения неполадок.

Как проверить, что всё заработало

Выполните requests.get('https://prokso.com/ip', proxies=proxies, timeout=30).json(). Если в ответе IP и страна прокси, а не ваши, соединение работает. Ту же строку можно проверить без кода в проверке прокси: если там всё в порядке, причину нужно искать в коде или переменных окружения.

Диагностика за 2 минуты

Сначала вставьте строку в проверку прокси. Если там прокси работает, причина в программе или её настройках. Если нет — проверьте строку из терминала:

curl -v -x "http://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823" https://api.ipify.org
  • Строка < HTTP/1.1 407 сразу после CONNECT — отвечает прокси. Название после кода, например NO_USER, подсказывает причину.
  • Прокси ответил на CONNECT кодом 200, а дальше пришёл другой код — прокси работает, этот ответ дал сайт.
  • Никакого ответа, только тайм-аут — соединение не дошло до прокси: проверьте хост, порт и сеть.

Инструкции, где встречается эта ошибка

Вопросы и ответы

Почему для http-сайта 407 приходит как ответ, а не как исключение?

Для адресов http:// requests не открывает туннель, а отправляет запрос прокси напрямую. Поэтому 407 возвращается как обычный response.status_code. Туннель CONNECT нужен только для https://, и там отказ становится исключением ProxyError. Что означает сам код, объяснено на странице <a href="/ru/errors/407-proxy-authentication-required">407 Proxy Authentication Required</a>.

Что делать, если внутри ConnectTimeoutError?

Прокси не ответил за отведённое время подключения. Проверьте хост и порт, сеть и файрвол, а затем страницу <a href="/ru/errors/proxy-timeout">тайм-аут прокси</a>.

Почему сайт видит мой адрес, хотя прокси задан?

Чаще всего в словаре есть только ключ 'http', а сайт работает на https://. Ключ соответствует схеме сайта, так что запросы к https:// идут напрямую. Задайте оба ключа.

Достаточно ли перехватывать только ProxyError?

ProxyError является подклассом requests.exceptions.ConnectionError. Ошибки SOCKS-прокси requests выдаёт как ConnectionError, поэтому, если работаете с обоими протоколами, перехватывайте ConnectionError.

Резидентские $1.59, мобильные $2.50, серверные $0.65 за 1 ГБ

Регистрация за минуту, доступы сразу после оплаты.

Создать аккаунт