# Как использовать прокси в Python с requests, httpx и aiohttp

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


## URL прокси

Каждая HTTP-библиотека Python принимает прокси в виде URL. В HodlProxy URL содержит учётные данные и [параметры таргетинга](https://hodlproxy.com/ru/docs/username-parameters) в имени пользователя; имя хоста указывает шлюз, а порт выбирает протокол.

```text
# Ротация IP: новый домашний выходной узел в США при каждом новом подключении
http://USER-cc-us:PASS@res.hodlproxy.com:9000

# Закреплённая сессия: один домашний выходной узел в Берлине на 30 минут с идентификатором "job42"
http://USER-cc-de-city-berlin-sid-job42-ttl-30m:PASS@res.hodlproxy.com:9000

# SOCKS5 с удалённым DNS (socks5h), параметры те же
socks5h://USER-cc-us:PASS@res.hodlproxy.com:9001
```


## requests

Передайте один и тот же URL для `http` и `https`; requests автоматически использует CONNECT для целей HTTPS. Объект `Session` повторно использует соединения, поэтому выходной узел не меняется до закрытия соединения; создавайте отдельный `Session` для каждой закреплённой задачи, а для нового выходного узла при каждом запросе вызывайте обычный `requests.get`.

```python
import requests

PROXY = "http://USER-cc-us:PASS@res.hodlproxy.com:9000"
proxies = {"http": PROXY, "https": PROXY}

# Один запрос — один выходной узел
r = requests.get("https://api.ipify.org", proxies=proxies, timeout=30)
print(r.text)

# Закреплённая последовательность: один выходной узел для всех запросов этой сессии
sticky = "http://USER-cc-de-city-berlin-sid-cart42-ttl-15m:PASS@res.hodlproxy.com:9000"
s = requests.Session()
s.proxies = {"http": sticky, "https": sticky}
s.get("https://example.com/product/1", timeout=30)
s.post("https://example.com/cart", json={"id": 1}, timeout=30)
```

> Tip: Для SOCKS5 установите дополнительный пакет: `pip install \"requests[socks]\"`, затем используйте `socks5h://`, чтобы DNS-разрешение выполнялось на выходном узле.


## httpx

httpx принимает один аргумент `proxy=` (в старых версиях — `proxies=`). Библиотека поддерживает HTTP/2 до цели через туннель CONNECT и работает так же в асинхронном коде.

```python
import httpx

PROXY = "http://USER-cc-us:PASS@res.hodlproxy.com:9000"

with httpx.Client(proxy=PROXY, timeout=30) as client:
    print(client.get("https://api.ipify.org").text)

# Асинхронный режим: один закреплённый выходной узел на задачу
import asyncio

async def fetch(sid: str, url: str) -> str:
    proxy = f"http://USER-cc-us-sid-{sid}-ttl-10m:PASS@res.hodlproxy.com:9000"
    async with httpx.AsyncClient(proxy=proxy, timeout=30) as client:
        return (await client.get(url)).text

asyncio.run(fetch("task1", "https://api.ipify.org"))
```


## aiohttp

aiohttp позволяет задавать прокси для каждого запроса или сессии и изначально поддерживает HTTP-прокси; для SOCKS5 требуется коннектор `aiohttp-socks`.

```python
import aiohttp, asyncio

PROXY = "http://USER-cc-us:PASS@res.hodlproxy.com:9000"

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.ipify.org", proxy=PROXY, timeout=aiohttp.ClientTimeout(total=30)) as r:
            print(await r.text())

asyncio.run(main())
```


## Ротация IP, keep-alive и повторные попытки

- Новое TCP-соединение означает новый выходной узел. `requests.get` без `Session` открывает его при каждом вызове; `Session` или `Client` из httpx поддерживает соединения, а значит, сохраняет выходной узел, пока пул не обновит соединение.
- Чтобы получить новый выходной узел внутри сессии, измените значение `-sid-`; чтобы получать новый при каждом запросе, отправляйте `Connection: close`.
- При ошибках 403, 429 и ошибках соединения повторите запрос один раз: на шлюзе с ротацией IP повторная попытка будет выглядеть как другой посетитель. Никогда не меняйте выходной узел при повторной попытке посреди закреплённой последовательности.
- Настройте тайм-ауты с учётом типа выходного узла: для резидентских прокси 15 с на подключение и 45 с на чтение, для мобильных — больше.


## Как экономить гигабайты

Трафик резидентских прокси оплачивается за гигабайт в обоих направлениях. Запрашивайте сжатые ответы (в этих библиотеках `Accept-Encoding: gzip, br` включён по умолчанию), предпочитайте конечные точки JSON страницам HTML и не загружайте изображения, шрифты и мультимедиа, если они не являются нужными данными. Страница размером 350 КБ обходится дёшево, а страница размером 4 МБ с ресурсами — нет.


## Вопросы

**Почему requests постоянно возвращает один и тот же IP-адрес?**

Session повторно использует TCP-соединение, а выходной узел выбирается для каждого соединения. Чтобы получить новый выходной узел, вызывайте обычный requests.get, отправляйте Connection: close или изменяйте значение -sid-.

**Нужен ли другой прокси для сайтов HTTPS?**

Нет. Тот же URL прокси с http:// обслуживает цели HTTPS через туннель CONNECT; TLS-соединение устанавливается напрямую между вашим кодом и сайтом.

**Можно ли использовать тот же код для мобильных прокси?**

Да: замените res.hodlproxy.com на mob.hodlproxy.com. Порты, учётные данные и параметры одинаковы.

Источник: https://hodlproxy.com/ru/guides/python-requests-httpx
