Как вращать прокси в Python: Полное руководство 2026 года
Краткое содержание
Ротация прокси в Python означает выбор другого URL прокси из списка при каждом запросе, а не специальный режим библиотеки requests.requests знает, как использовать любой прокси-словарь, который вы передаете для этого вызова; ваш код определяет, какой это прокси.
Словарь proxies, ключи которого представляют схемы ({"http": ..., "https": ...}), — единственный формат, который принимает requests, и его можно передавать для каждого запроса или устанавливать один раз в Session. Вариант с указанием для каждого запроса безопаснее для ротации, потому что обновление session.proxies на каждой итерации цикла легко сделать неправильно.
Переменные окружения без уведомления переопределяют session.proxies. Документация requests предупреждает, что HTTP_PROXY/HTTPS_PROXY в окружении имеют приоритет над тем, что вы установили в сессии, и эта статья демонстрирует это переопределение в реальном времени, чтобы вы могли увидеть, как это происходит.
itertools.cycle обеспечивает ротацию по кругу за три строки, но не знает, когда прокси не работает. Ротация в продакшене требует цикла с повторной попыткой и пропуском, которые создает и запускает эта статья на реальном сбое прокси.
Класс Retry из urllib3 повторяет одно и то же соединение; он не переключается между разными прокси. Путать их — распространенная причина, по которой код ротации «кажется, что не работает» — и ротация прокси решают разные задачи, и обычно нужно то и другое.
Попробуйте Nstproxy - Начните бесплатный тест сегодня
Retry
Ротация URL прокси не зависит от того, откуда берутся эти URL. Один и тот же цикл работает, независимо от того, является ли список тремя IP-адресами, которые вы закодировали для тестирования, или большим пулом от платного провайдера; код в этой статье был проверен на локальных тестовых серверах именно для того, чтобы он не зависел от какого-либо одного поставщика.
Что на самом деле означает "Ротация прокси" в скрипте
Ротация прокси означает отправку различных запросов через разные прокси-серверы, чтобы ни один исходящий IP-адрес не обрабатывал каждый запрос. Ничего в Python или requests не ротация не выполняет автоматически — requests.get(url, proxies=proxy_dict) отправляет ровно один запрос через ровно один прокси, и именно ваш цикл решает, какой proxy_dict передать при следующем вызове. Это различие имеет значение, потому что многие ошибки ротации оказываются "цикл никогда не менял словарь", а не проблемой прокси. Остальная часть этой статьи создает этот цикл от одного жестко закодированного прокси до потокобезопасного пула с автоматическим переключением на резервный прокси, выполняя каждый пример против реальных локальных серверов, чтобы вы могли увидеть фактическое поведение, а не доверять фрагменту кода.
Установка нужного
Вам нужна библиотека requests, которая также подтягивает в качестве зависимости urllib3 и обрабатывает как простые HTTP-прокси, так и с версии requests 2.10+ SOCKS-прокси, если вы также установите дополнительный пакет socks:
pip install requests
pip install"requests[socks]"# требуется только для URL прокси socks5://
Другие пакеты не требуются для паттернов в этой статье — ротация состоит из нескольких десятков строк стандартного кода библиотеки (itertools, random, threading, concurrent.futures) и самой библиотеки requests.
Конфигурирование одного прокси перед ротацией
Ответьте на заголовок напрямую: requests ожидает словарь с ключами "http" и "https", каждый из которых указывает на URL прокси, и вы либо передаете этот словарь для отдельного вызова, либо прикрепляете его к Session. Документация requests показывает вариант для запроса как:
и вариант для Session как session.proxies.update(proxies), после чего следует session.get(...). Учетные данные помещаются прямо в URL как http://user:pass@host:port. Та же документация отмечает момент, о котором стоит знать, прежде чем строить что-либо на основе этого: она прямо утверждает, что «значения, предоставленные вами, будут переопределены переменными окружения», что означает, что переменные окружения HTTP_PROXY или HTTPS_PROXY имеют приоритет над тем, что вы установили в session.proxies. Это действительно и легко упустить случайно — выполнение следующего на машине (или CI runner), на которой HTTP_PROXY уже экспортирован, воспроизводит это:
import os
import requests
os.environ["HTTP_PROXY"]="http://127.0.0.1:8002"session = requests.Session()session.proxies.update({"http":"http://127.0.0.1:8001"})resp = session.get("http://internal.test/", timeout=5)print(resp.json()["served_by"])
proxy-2
Сессии было указано использовать прокси на порту 8001; переменная окружения все равно победила, и каждый запрос в сессии проходил через порт 8002 вместо этого. Если ваш код ротации является Session и, кажется, игнорирует ваш список прокси, проверьте переменные окружения, прежде чем проверять логику ротации.
Быстрый обзор
```html
Тестирование логики ротации на трех локальных серверах показывает, что цикл работает, но не скажет вам, как ведут себя реальные прокси под нагрузкой — шлюз Nstproxy предоставляет вам большой пул реальных IP-адресов, на которые можно указать тот же код, как только вы будете готовы.
Самый простой цикл ротации проходит через фиксированный список URL-адресов прокси и передает новый на каждый вызов requests. Этот пример был запущен на трех локальных HTTP-серверах, запущенных на портах 8001–8003 для этой статьи, каждый из которых идентифицирует себя в своем ответе, чтобы ротация могла быть проверяемой, а не предполагаемой:
import itertools
import requests
PROXIES =["http://127.0.0.1:8001","http://127.0.0.1:8002","http://127.0.0.1:8003",]proxy_cycle = itertools.cycle(PROXIES)for i inrange(6): proxy =next(proxy_cycle) resp = requests.get("http://internal.test/products", proxies={"http": proxy,"https": proxy}, timeout=5,)print(f"запрос {i +1}: отправлен через {proxy} -> {resp.json()['served_by']}")
Фактический вывод из этого запуска:
запрос 1: отправлен через http://127.0.0.1:8001 -> proxy-1
запрос 2: отправлен через http://127.0.0.1:8002 -> proxy-2
запрос 3: отправлен через http://127.0.0.1:8003 -> proxy-3
запрос 4: отправлен через http://127.0.0.1:8001 -> proxy-1
запрос 5: отправлен через http://127.0.0.1:8002 -> proxy-2
запрос 6: отправлен через http://127.0.0.1:8003 -> proxy-3
itertools.cycle — это весь трюк: это бесконечный итератор, который бесконечно возвращается к началу списка, так что next(proxy_cycle) всегда возвращает прокси без необходимости отслеживания индекса. Замените PROXIES на реальные URL-адреса прокси, и цикл будет работать точно так же — он не знает, пришел ли список с трех локальных тестовых серверов или из коммерческого пула, что и есть смысл тестировать его таким образом сначала.
Расширенные шаблоны: резервирование и одновременная ротация
Круговая ротация сама по себе не отвечает на вопрос, который в конечном итоге должен задать каждый сценарий ротации: что происходит, когда один из прокси не работает? Шаблон ниже выбирает случайный прокси из пула, перехватывает специфические исключения, которые requests выводит для ошибок прокси и подключения, и переходит к следующему кандидату вместо того, чтобы позволить всему запросу завершиться неудачей:
ProxyError задокументирован как подкласс ConnectionError, который возникает специально для ошибок, связанных с прокси, почему он перехватывается вместе с более общим ConnectionError и Timeout. Запуск этого с пулом из четырех адресов — трех реальных локальных серверов и одного порта, на котором никто не слушает — дал следующий вывод:
попытка 1: http://127.0.0.1:8004 не удалась (ProxyError), ротация
успешно через http://127.0.0.1:8003 -> proxy-3
Мертвый адрес неудачно завершил запрос сразу, и цикл продолжил работу, не раздавая ошибки в сценарии. Поскольку random.shuffle переупорядочивает пул при каждом вызове, другой запуск может пройти успешно с первой попытки, если перемешивание ставит рабочий прокси на первое место — оба исхода являются правильным поведением для этого шаблона.
Ротация из нескольких потоков добавляет еще одно требование: то, что выбирает "следующий прокси", должно быть безопасно вызывать из нескольких потоков одновременно. Разделяемый itertools.cycle, защищенный threading.Lock, управляемый ThreadPoolExecutor, сохраняет порядок круговой ротации в условиях параллельного доступа:
пути = [f"/item/{i}" для i в диапазоне(9)]
с ThreadPoolExecutor(max_workers=4) как пул:
будущее = [pool.submit(fetch, p) для p в путях]
для future в as_completed(будущее):
print(future.result())
Девять запросов через четыре потока-работника все равно распределились ровно по три на прокси, в порядке, потому что блокировка сериализует доступ к общему итератору, даже если сами запросы выполняются одновременно. ThreadPoolExecutor является частью стандартной библиотеки concurrent.futures — для этой модели не требуется дополнительных зависимостей.
Честные ограничения: что этот код ротации не может исправить
Этот код определяет, какой URL прокси используется в каждом запросе; он не высказывает мнения о том, откуда эти URL берутся или хороши ли они. Список из трех мёртвых IP будет вращаться точно так же гладко, как и список из трех здоровых — цикл переключения выше лишь доказывает, что он может восстановиться от некоторых плохих прокси, но не то, что ваш конкретный список совместим.
Retry из urllib3 не является заменой логики ротации в этой статье. Его собственные параметры — total, backoff_factor, status_forcelist — описывают повторный запрос одного и того же запроса к тем же соединениям с задержкой между попытками; ничто в urllib3.util.Retry не переключается на другой прокси. Если вы монтируете Retry-конфигурированный HTTPAdapter на сессию, в которой установлен один прокси, каждое повторный запрос все равно проходит через тот же самый прокси. Переход на другой прокси при сбое — вот что делает функция get_with_rotation, и две техники призваны быть комбинированы, а не выбраны одна вместо другой.
Ни один из примеров не обрабатывает ограничения по скорости аутентификации прокси, семантику постоянных сессий или маршрутизацию по странам — это свойства любого сервиса прокси, который находится за URL, а не что-то, что itertools.cycle или цикл повторных попыток могут добавить.
Устранение неполадок с общими ошибками ротации
requests.exceptions.ProxyError означает, что соединение с самим прокси не удалось — прокси не работает, порт неверен или брандмауэр блокирует его. Это то, что вызывает неработающий порт в приведенном выше примере переключения.
requests.exceptions.ConnectionError без более специфичного подкласса ProxyError, как правило, означает, что прокси принял соединение, но не смог достичь целевого сайта, что часто проявляется как прокси, близкий к концу своего рабочего срока, если вы берете из вращающегося пула.
Повороты, похоже, не происходят, даже если ваш цикл выглядит правильно — сначала проверьте наличие переменной окружения HTTP_PROXY или HTTPS_PROXY в соответствии с живой репродукцией ранее в этой статье; она безмолвно переопределяет session.proxies и заставляет каждый запрос проходить через один и тот же адрес, независимо от того, что выбрал ваш цикл.
Каждый запрос истекает одновременно на одном и том же значении timeout, вместо того чтобы быстро завершаться на неработающих прокси — уменьшите аргумент timeout, специально для проверки состояния нового пула, так как щедрый таймаут, предназначенный для реальных запросов, заставит неработающий прокси зависать на всю продолжительность каждой попытки ротации.
Настройка кода ротации на реальный пул прокси
Циклы в этой статье ротации обходят любой список, который вы им предоставите, а замена его на коммерческий шлюз означает изменение списка, а не логики. Nstproxy — это провайдер инфраструктуры прокси, предлагающий пул нерезиденциальных, дата-центровых, статических ISP, IPv6 и мобильных IP, доступный через HTTP, HTTPS или SOCKS5 через единый шлюз, а не список отдельных IP, которые вы управляете сами. Его страница продукта Residential Lite Proxies непосредственно документирует шаблон подключения: фиксированный шлюз и порт, с фактической ротацией IP, происходящей за этим единственным адресом со стороны провайдера, а не в вашем Python-списке — смотрите документацию Nstproxy для текущего хоста, порта и параметров аутентификации перед их подключением к примерам выше. Это подходит командам, которые хотят поведение ротации от этой статьи, не поддерживая и не проверяя здоровье своего собственного списка отдельных прокси IP. Компромисс заключается в том, что вы доверяете поведению ротации провайдера за шлюзом, а не контролируете его напрямую, как это делают примеры itertools.cycle и переключения выше.
Один шлюз вместо списка для управления — код из базового примера этой статьи сводится к одному словарю прокси, указывающему на этот единственный адрес шлюза, а не на список множества; проверьте ссылку на документацию выше для точного текущего хоста и порта перед использованием.
50 миллионов+ резиденциальных IP по более чем 200 странам и регионам — в соответствии со страницей продукта Residential Lite, что означает, что ротация, происходящая за шлюзом, извлекается из гораздо более крупного пула, чем большинство самостоятельно управляемых списков.
Поддержка HTTP, HTTPS и SOCKS5 — те же протоколы, которые уже используются в примерах requests в этой статье, поэтому код запроса не нужно изменять.
Оплата по предоплаченному пакету — опубликованные тарифы Nstproxy продаются в метered пакетах, а не по подписке, что важно, если ваш скрипт ротации работает лишь время от времени, а не непрерывно.
Если вы используете ротацию прокси конкретно для управления безголовым браузером, а не просто для вызовов requests, конфигурирование прокси в Playwright охватывает версию этой проблемы в контексте браузера.
Ротация прокси в Python — это цикл, который меняет один словарь между запросами, а не функция, которую вы устанавливаете — все в этой статье, от трехстрочной версии itertools.cycle до потокобезопасного пула с резервированием, основано на том же словаре {"http": ..., "https": ...}, который всегда принимал requests. Начните с базового цикла, чтобы подтвердить, что ваш код запроса вообще работает, добавьте цикл резервирования, как только вы обращаетесь к прокси, которые могут действительно выйти из строя, и обращайтесь к потокам только тогда, когда задержка одного запроса — это ваше фактическое узкое место.
В: Нужна ли мне специальная библиотека для ротации прокси в Python, или это обрабатывает requests?
Вам не нужна специальная библиотека — requests принимает только один словарь прокси за вызов, а ротация — это цикл в вашем собственном коде, который изменяет, какой словарь передается в каждом запросе, как показано на протяжении всей этой статьи.
В: Почему мой код ротации, похоже, всегда использует один и тот же прокси?
Сначала проверьте наличие переменной окружения HTTP_PROXY или HTTPS_PROXY, так как документация requests подтверждает, что она тихо заменяет все, что вы установили на session.proxies, что эта статья воспроизводит в реальном времени.
В: Класс Retry из urllib3 ротуирует прокси за меня?
Нет — Retry повторяет тот же запрос к тому же подключению с задержкой повторной попытки и не переключается на другой прокси; вам нужен цикл ротации, как пример резервирования в этой статье, а не вместо него.
В: Безопасно ли ротация прокси из нескольких потоков одновременно?
Это безопасно, пока то, что выбирает "следующий прокси", защищено блокировкой, как в примере itertools.cycle, защищенном threading.Lock; небезопасный общий итератор, доступный из нескольких потоков, является обычным источником тонких ошибок ротации при параллельном выполнении.
В: В чем разница между ротацией моего собственного списка прокси и использованием ротационного шлюза от провайдера?
Ротация вашего собственного списка означает, что ваш код отслеживает, какие прокси активны, и выбирает из них, в то время как ротационный шлюз выполняет ту же задачу за одним фиксированным хостом и портом со стороны провайдера, что является схемой, которую Nstproxy документирует для своих Residential Lite Proxies.
Microsoft Edge по умолчанию читает настройки прокси операционной системы, поэтому вход в настройки прокси Edge просто открывает диалог Windows или macOS. В этом руководстве рассматриваются четыре способа, которые фактически настраивают его, а также ограничения платформы, которые нарушают большинство конфигураций, включая тот факт, что Edge не поддерживает аутентификацию на SOCKS5.
Lena Zhou
Aug. 3rd 2026
110M+ реальных IP с 99.9% успешных доступов
Средний отклик ~0.5с для задач высокой конкуренции
Всего от $0.1/GB
Мгновенный доступ к премиальным residential, datacenter, IPv6 и ISP пулам.