Ошибки прокси в httpx и aiohttp

Асинхронные библиотеки Python настраивают прокси иначе, чем requests, и по-своему сообщают об отказах. Ниже собраны тексты ошибок, которые они выдают, и что каждый означает.

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

Коротко
  • В httpx с версии 0.28.0 параметра proxies нет: прокси задаётся через proxy= или mounts=
  • Отказ прокси httpx выдаёт как ProxyError, aiohttp как ClientHttpProxyError, а слово после 407 называет причину
  • SOCKS в httpx требует httpx[socks], а в aiohttp работает только через пакет aiohttp-socks

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

В httpx прокси задаётся параметром proxy=. Старый параметр proxies= объявили устаревшим в версии 0.26.0 и убрали в 0.28.0, поэтому теперь он даёт TypeError: Client.__init__() got an unexpected keyword argument 'proxies'. Если прокси не принял запрос CONNECT, httpx выдаёт httpx.ProxyError с кодом и текстом ответа, например 407 NO_USER. Если к прокси не удалось подключиться, это уже httpx.ConnectError.

В aiohttp ошибка подключения к прокси — ClientProxyConnectionError с текстом Cannot connect to host gw.prokso.com:823. Отказ на CONNECT — ClientHttpProxyError, например 407, message='NO_USER'. Обратите внимание: в тексте этого исключения есть адрес прокси вместе с логином и паролем, так что не публикуйте такие журналы.

SOCKS обе библиотеки поддерживают только через дополнительные пакеты. Httpx без них пишет Using SOCKS proxy, but the 'socksio' package is not installed и советует pip install httpx[socks]. В aiohttp встроенной поддержки SOCKS нет совсем: нужен пакет aiohttp-socks.

Причины

  • Старый параметр proxies в httpx. Код, написанный для версий до 0.28, падает с TypeError сразу при создании клиента.
  • Логин, пароль или лимит. 407 NO_USER означает неверные данные входа, TRAFFIC_EXHAUSTED и THREADS_EXHAUSTED указывают на лимиты плана. Для сайтов на https:// это исключение, для http:// обычный ответ со статусом 407.
  • SOCKS без дополнительного пакета. У httpx нет socksio, а aiohttp получил строку socks5:// в параметре proxy=. Aiohttp такую строку не отклоняет, а отправляет на порт SOCKS обычный HTTP-запрос CONNECT, и ошибка получается непонятной.
  • Неверный хост или порт. ConnectError в httpx и ClientProxyConnectionError в aiohttp: в строке не gw.prokso.com или порт вне 823, 824 и 10000–20000.
  • Схема https:// в строке прокси. Порт 823 ждёт обычный HTTP. Документация httpx советует писать http:// даже для https-сайтов, а у aiohttp лишь ограниченная поддержка прокси с https://.

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

  1. В httpx замените proxies= на httpx.Client(proxy='http://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823'). Для разных прокси под разные адреса используйте mounts=.
  2. Для SOCKS в httpx установите pip install 'httpx[socks]' и пишите proxy='socks5h://ЛОГИН:ПАРОЛЬ@gw.prokso.com:824'. Схему socks5h httpx принимает с версии 0.28.0.
  3. В aiohttp передавайте логин и пароль в самой строке: session.get(url, proxy='http://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823'). Параметр proxy_auth с версии 3.14 объявлен устаревшим.
  4. Для SOCKS в aiohttp установите aiohttp-socks и создайте сессию с ProxyConnector.from_url('socks5://ЛОГИН:ПАРОЛЬ@gw.prokso.com:824'). Этот метод принимает схемы socks5, socks4 и http, а имя сайта для SOCKS5 по умолчанию превращает в IP прокси (параметр rdns). Полный пример есть в инструкции aiohttp.
  5. Обрабатывайте 407 по тексту ответа: NO_USER значит проверить логин и список IP, TRAFFIC_EXHAUSTED пополнить трафик, THREADS_EXHAUSTED уменьшить число одновременных задач до 1000 на план. Все порты и форматы строки собраны в справочнике о шлюзе.

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

Сделайте запрос к https://prokso.com/ip тем же клиентом и с той же строкой прокси. Если в ответе JSON с IP, страной и ASN прокси, настройка правильная. Строку также можно проверить без кода в проверке прокси, чтобы отделить ошибку в коде от ошибки в данных.

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

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

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

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

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

Почему httpx пишет ProxyError: 407, а для http-сайта возвращает ответ?

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

Берёт ли aiohttp прокси из переменных окружения?

По умолчанию нет. Переменные HTTP_PROXY и HTTPS_PROXY читаются только тогда, когда сессия создана с trust_env=True.

Можно ли писать socks5h в aiohttp-socks?

В пакете python-socks, на котором работает aiohttp-socks, метод from_url принимает socks5, а не socks5h. Превращение имени сайта в IP на стороне прокси для SOCKS5 там включено по умолчанию. О самом протоколе — в глоссарии: <a href="/ru/glossary/socks5">SOCKS5</a>.

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

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

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