Перейти к содержимому
Гайды 7 мин чтения 2 просмотров

Асинхронные прокси в Python

Асинхронные прокси в Python: aiohttp и httpx

Python

Асинхронные прокси в Python позволяют эффективно выполнять сетевые запросы через промежуточные серверы, используя библиотеки aiohttp и httpx для неблокирующего ввода-вывода и повышения производительности при работе с большим количеством одновременных соединений.

Преимущества асинхронных запросов с прокси

Использование асинхронных библиотек для работы с прокси-серверами критически важно для приложений, где требуется высокая пропускная способность и низкая задержка. Традиционные синхронные запросы блокируют выполнение программы до получения ответа, что неприемлемо при необходимости одновременной обработки тысяч или миллионов запросов через различные прокси. Асинхронный подход позволяет выполнять множество I/O-операций параллельно, значительно снижая суммарное время выполнения и повышая общую эффективность системы за счет более оптимального использования ресурсов.

Работа с aiohttp и асинхронными прокси

aiohttp — это асинхронный HTTP-клиент/сервер для asyncio. Он предоставляет мощные средства для создания как клиентских, так и серверных приложений, ориентированных на высокую производительность. Работа с прокси в aiohttp осуществляется путем указания URL прокси при создании запроса или сессии.

Настройка прокси в aiohttp

Для использования прокси с aiohttp необходимо передать параметр proxy в метод запроса или при инициализации ClientSession.

Простой GET-запрос через прокси

import asyncio
import aiohttp

async def fetch_with_proxy(url: str, proxy_url: str):
    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(url, proxy=proxy_url, timeout=aiohttp.ClientTimeout(total=10)) as response:
                response.raise_for_status()  # Выбросит исключение для статусов 4xx/5xx
                text = await response.text()
                print(f"URL: {url}, Proxy: {proxy_url}, Status: {response.status}")
                # print(f"Content snippet: {text[:200]}...") # Для отладки
                return text
        except aiohttp.ClientError as e:
            print(f"Ошибка при запросе {url} через прокси {proxy_url}: {e}")
            return None

async def main():
    target_url = "http://httpbin.org/ip"
    # Пример HTTP/HTTPS прокси (замените на свои данные)
    http_proxy = "http://user:password@proxy.example.com:8080"

    print(f"Запрос к {target_url} через {http_proxy}")
    content = await fetch_with_proxy(target_url, http_proxy)
    if content:
        print(f"Получен ответ: {content.strip()}")

if __name__ == "__main__":
    asyncio.run(main())

POST-запрос с данными через прокси

Для POST-запросов используется аналогичный подход, но с передачей данных в параметре data или json.

import asyncio
import aiohttp

async def post_data_with_proxy(url: str, data: dict, proxy_url: str):
    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(url, json=data, proxy=proxy_url, timeout=aiohttp.ClientTimeout(total=15)) as response:
                response.raise_for_status()
                json_response = await response.json()
                print(f"URL: {url}, Proxy: {proxy_url}, Status: {response.status}")
                return json_response
        except aiohttp.ClientError as e:
            print(f"Ошибка при POST-запросе {url} через прокси {proxy_url}: {e}")
            return None

async def main_post():
    target_url = "http://httpbin.org/post"
    post_data = {"key": "value", "number": 123}
    http_proxy = "http://user:password@proxy.example.com:8080"

    print(f"POST-запрос к {target_url} с данными {post_data} через {http_proxy}")
    response_data = await post_data_with_proxy(target_url, post_data, http_proxy)
    if response_data:
        print(f"Получен ответ: {response_data}")

if __name__ == "__main__":
    asyncio.run(main_post())

Управление сессиями и пулами прокси в aiohttp

Использование aiohttp.ClientSession рекомендуется для выполнения нескольких запросов. Сессии управляют пулом соединений, повторно используя их, что снижает накладные расходы на установление новых TCP-соединений. При работе с несколькими прокси можно создавать отдельные сессии для каждого прокси или динамически менять прокси в запросах внутри одной сессии.

import asyncio
import aiohttp

async def fetch_multiple_with_proxies(urls: list[str], proxies: list[str]):
    async with aiohttp.ClientSession() as session:
        tasks = []
        for i, url in enumerate(urls):
            proxy_url = proxies[i % len(proxies)] # Ротация прокси
            print(f"Запрос {url} через прокси {proxy_url}")
            tasks.append(
                session.get(url, proxy=proxy_url, timeout=aiohttp.ClientTimeout(total=10))
            )

        for i, task in enumerate(asyncio.as_completed(tasks)):
            try:
                response = await task
                response.raise_for_status()
                text = await response.text()
                print(f"[{i+1}] URL: {response.url}, Proxy used: {response.request_info.proxy}, Status: {response.status}")
                # print(f"Content snippet: {text[:100]}...")
            except aiohttp.ClientError as e:
                print(f"[{i+1}] Ошибка при запросе: {e}")

async def main_multiple():
    target_urls = [
        "http://httpbin.org/ip",
        "http://httpbin.org/user-agent",
        "http://httpbin.org/headers",
        "http://httpbin.org/get"
    ]
    # Замените на ваши рабочие прокси
    proxy_list = [
        "http://user1:pass1@proxy1.example.com:8080",
        "http://user2:pass2@proxy2.example.com:8080"
    ]

    await fetch_multiple_with_proxies(target_urls, proxy_list)

if __name__ == "__main__":
    asyncio.run(main_multiple())

Для SOCKS-прокси aiohttp требует дополнительную библиотеку aiohttp_socks.

Работа с httpx и асинхронными прокси

httpx — современный HTTP-клиент, поддерживающий как синхронные, так и асинхронные запросы. Его API схож с популярной библиотекой requests, что упрощает переход. httpx поддерживает HTTP/1.1, HTTP/2 и SOCKS прокси "из коробки" или с минимальными дополнительными зависимостями.

Настройка прокси в httpx

В httpx прокси настраиваются через параметр proxies, который принимает словарь, где ключи — схемы протоколов, а значения — URL прокси.

Простой GET-запрос через прокси

import asyncio
import httpx

async def fetch_with_httpx_proxy(url: str, proxy_url: str):
    proxies = {
        "http://": proxy_url,
        "https://": proxy_url,
    }
    async with httpx.AsyncClient(proxies=proxies, timeout=10) as client:
        try:
            response = await client.get(url)
            response.raise_for_status()  # Выбросит исключение для статусов 4xx/5xx
            print(f"URL: {url}, Proxy: {proxy_url}, Status: {response.status_code}")
            # print(f"Content snippet: {response.text[:200]}...")
            return response.text
        except httpx.HTTPStatusError as e:
            print(f"Ошибка статуса HTTP при запросе {url} через прокси {proxy_url}: {e}")
        except httpx.RequestError as e:
            print(f"Ошибка запроса при обращении к {url} через прокси {proxy_url}: {e}")
        return None

async def main_httpx():
    target_url = "http://httpbin.org/ip"
    # Пример HTTP/HTTPS прокси (замените на свои данные)
    http_proxy = "http://user:password@proxy.example.com:8080"

    print(f"Запрос к {target_url} через {http_proxy} с httpx")
    content = await fetch_with_httpx_proxy(target_url, http_proxy)
    if content:
        print(f"Получен ответ: {content.strip()}")

if __name__ == "__main__":
    asyncio.run(main_httpx())

POST-запрос с данными через прокси

import asyncio
import httpx

async def post_data_with_httpx_proxy(url: str, data: dict, proxy_url: str):
    proxies = {
        "http://": proxy_url,
        "https://": proxy_url,
    }
    async with httpx.AsyncClient(proxies=proxies, timeout=15) as client:
        try:
            response = await client.post(url, json=data)
            response.raise_for_status()
            print(f"URL: {url}, Proxy: {proxy_url}, Status: {response.status_code}")
            return response.json()
        except httpx.HTTPStatusError as e:
            print(f"Ошибка статуса HTTP при POST-запросе {url} через прокси {proxy_url}: {e}")
        except httpx.RequestError as e:
            print(f"Ошибка запроса при POST-обращении к {url} через прокси {proxy_url}: {e}")
        return None

async def main_httpx_post():
    target_url = "http://httpbin.org/post"
    post_data = {"key": "value", "number": 456}
    http_proxy = "http://user:password@proxy.example.com:8080"

    print(f"POST-запрос к {target_url} с данными {post_data} через {http_proxy} с httpx")
    response_data = await post_data_with_httpx_proxy(target_url, post_data, http_proxy)
    if response_data:
        print(f"Получен ответ: {response_data}")

if __name__ == "__main__":
    asyncio.run(main_httpx_post())

Управление клиентами и пулами прокси в httpx

httpx.AsyncClient аналогично aiohttp.ClientSession управляет пулом соединений и рекомендуется для выполнения множества запросов. Для ротации прокси можно инициализировать новый AsyncClient для каждого запроса или использовать один клиент, динамически меняя параметр proxies при необходимости, хотя создание нового клиента для каждого прокси часто более предсказуемо.

import asyncio
import httpx

async def fetch_multiple_with_httpx_proxies(urls: list[str], proxies: list[str]):
    tasks = []
    for i, url in enumerate(urls):
        proxy_url = proxies[i % len(proxies)] # Ротация прокси
        proxies_config = {
            "http://": proxy_url,
            "https://": proxy_url,
        }
        # Создаем новый клиент для каждого запроса с его прокси
        # В реальных условиях можно переиспользовать клиенты для одного прокси
        client = httpx.AsyncClient(proxies=proxies_config, timeout=10)
        print(f"Запрос {url} через прокси {proxy_url}")
        tasks.append(
            asyncio.create_task(client.get(url))
        )
        # Важно: закрывать клиент после использования, особенно если он не в контекстном менеджере
        tasks[-1].add_done_callback(lambda t, cl=client: asyncio.create_task(cl.aclose()))

    for i, task in enumerate(asyncio.as_completed(tasks)):
        try:
            response = await task
            response.raise_for_status()
            print(f"[{i+1}] URL: {response.url}, Proxy used: {response.request.url.raw_host}, Status: {response.status_code}")
            # print(f"Content snippet: {response.text[:100]}...")
        except httpx.HTTPStatusError as e:
            print(f"[{i+1}] Ошибка статуса HTTP при запросе: {e}")
        except httpx.RequestError as e:
            print(f"[{i+1}] Ошибка запроса: {e}")

async def main_httpx_multiple():
    target_urls = [
        "http://httpbin.org/ip",
        "http://httpbin.org/user-agent",
        "http://httpbin.org/headers",
        "http://httpbin.org/get"
    ]
    # Замените на ваши рабочие прокси
    proxy_list = [
        "http://user1:pass1@proxy1.example.com:8080",
        "http://user2:pass2@proxy2.example.com:8080"
    ]

    await fetch_multiple_with_httpx_proxies(target_urls, proxy_list)

if __name__ == "__main__":
    asyncio.run(main_httpx_multiple())

Для SOCKS-прокси httpx использует библиотеку socksio, которая автоматически устанавливается при необходимости, либо httpx-socks для более явного управления.

Сравнение aiohttp и httpx для работы с прокси

Обе библиотеки предоставляют надежные средства для асинхронной работы с прокси, но имеют различия в архитектуре и API.

Характеристика aiohttp httpx
Базовый фреймворк Основан на asyncio, низкоуровневый. Высокоуровневый, вдохновлен requests, также на asyncio.
API Более низкоуровневый, требует ClientSession для эффективной работы. requests-подобный, интуитивно понятный, AsyncClient для асинхронных операций.
Поддержка HTTP/2 Требует дополнительной конфигурации. Встроенная поддержка HTTP/2.
SOCKS-прокси Требует aiohttp_socks. Встроенная поддержка через socksio или httpx-socks.
Синхронные запросы Только асинхронный. Поддерживает как синхронные, так и асинхронные запросы.
Обработка ошибок aiohttp.ClientError и его подклассы. httpx.RequestError, httpx.HTTPStatusError и другие.
Конфигурация прокси Параметр proxy='http://...'. Словарь proxies={'http://': 'http://...', 'https://': 'http://...'}.
Гибкость Высокая гибкость, контроль над низкоуровневыми аспектами. Высокая гибкость при сохранении простоты API.
Размер/Зависимости Может быть немного легче при базовой установке. Чуть больше зависимостей из-за широкой функциональности.

Выбор библиотеки

  • aiohttp предпочтителен, когда требуется максимальный контроль над сетевыми операциями, или если проект уже активно использует aiohttp для других целей (например, как веб-сервер). Он предоставляет более детальный доступ к настройкам соединения и обработки запросов.
  • httpx является отличным выбором для большинства задач, где требуется баланс между простотой использования и мощной функциональностью. Его API, схожий с requests, делает его удобным для разработчиков, знакомых с синхронными HTTP-клиентами. Поддержка HTTP/2 и SOCKS из коробки также является преимуществом.

Продвинутые сценарии и рекомендации

Ротация прокси

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

  • Циклическая ротация: Простейший метод, где прокси выбираются по очереди из списка.
  • Умная ротация: Использование метрик (время ответа, количество ошибок) для исключения неработающих прокси или предпочтения более быстрых.
  • Пул прокси: Поддержание актуального списка доступных и работоспособных прокси, с возможностью их динамического добавления/удаления.

Обработка ошибок и таймаутов

Адекватная обработка ошибок и таймаутов критична для стабильной работы с прокси.

  • Таймауты: Устанавливайте разумные таймауты для соединения и чтения ответа, чтобы избежать зависания программы на не отвечающих прокси.
  • Повторные попытки (Retries): Реализуйте логику повторных попыток для запросов, которые завершились ошибкой (например, 5xx статусы, сетевые ошибки). Используйте экспоненциальную задержку.
  • Исключения: Обрабатывайте специфические исключения каждой библиотеки (aiohttp.ClientError, httpx.RequestError, httpx.HTTPStatusError) для принятия решений о смене прокси или повторе запроса.

Авторизованные прокси

Большинство коммерческих прокси требуют аутентификации. Оба клиента поддерживают HTTP Basic Authentication через URL прокси: http://user:password@host:port.

SOCKS-прокси

Для SOCKS-прокси:
* aiohttp: Требует установку aiohttp_socks (pip install aiohttp_socks). Затем прокси указывается как socks5://user:password@host:port или socks4://host:port.
* httpx: Поддерживает SOCKS5 "из коробки" при наличии socksio или httpx-socks (pip install httpx-socks). URL прокси указывается как socks5://user:password@host:port.

Мониторинг и логирование

Ведите логи запросов, ответов, используемых прокси и возникающих ошибок. Это помогает в отладке, мониторинге производительности прокси и выявлении проблемных серверов.

Обновлено: 03.03.2026
Назад к категории

Попробуйте наши прокси

20,000+ прокси в 100+ странах мира