Многие системы безопасности сайтов, в том числе файрволы веб-приложений (WAF), блокируют запросы неугодных им пользователей на основе IP-адресов. Более эффективных методов защиты пока не нашли и скорее всего никогда не найдут. Только если не будет внедрена какая-нибудь тотальная система физической верификации пользователей.
А пока IP-адреса в ходу, будут работать и прокси-серверы. Они умеют пересылать запросы к целевым сайтам от своего имени, фактически подменяя реальный IP пользователя или парсера своим IP-адресом.
Чем больше объём собираемых данных, тем острее встаёт вопрос ротации прокси, так как один узел-посредник может не справиться с большим объёмом запросов. Этот материал о том, как обеспечить ротацию IP прокси в нужный вам момент и под нужные вам условия работы, а также о том, какие проблемы могут возникнуть при ротации IP, и как их можно решить.
Вы же не поверите, если мы скажем, что ротируемый IP-прокси — это обязательное условие работы парсера? Поэтому давайте всё разложим по полочкам.
Какие выгоды даёт ротация IP / прокси:
С какими техническими проблемами можно столкнуться при работе через прокси с ротацией IP:
Любая из обозначенных проблем имеет свои решения или обходные пути. Но все такие решения — это дополнительное погружение в тематику, а также расходы времени, сил, а чаще всего бюджета.
Собственно, по этой причине получили такое широкое распространение прокси-сервисы, которые берут на себя вопросы ротации IP, их мониторинга, проверки качества и т.п., вплоть до организации подбора в нужном городе и с выбором провайдера связи. Получается формат инфраструктуры «под ключ». Пример такого сервиса — Froxy.
Основной и максимально простой подход при работе со списками прокси — это рандомизация выбора. Но всегда возникает масса «но». Например, когда список прокси периодически обновляется (в этом случае его нужно вынести отдельным файлом или базой данных), когда прокси низкого качества (потребуется обязательная проверка, хотя бы на доступность и на значение пинга), когда прокси нужно интегрировать с разными библиотеками (процесс подключения может выглядеть по-разному), когда требуется поддержка особых протоколов (например, socks5 вместо стандартного http) и т.п.
У готовых прокси-сервисов вообще может использоваться API-интерфейс и специальные вызовы для принудительной ротации IP. Всё это не имеет ничего общего с прямой ротацией прокси в списках непосредственно в коде скрипта парсинга. Но хватит теории, пора переходить к практике — рассказываем и показываем на примерах как ротировать IP.
Простейший пример с выбором случайного значения из списка. Предположим, что парсинг целевого сайта организован через библиотеку requests (здесь и ниже — язык программирования Python):
import requests, random
proxy_list = ['ip1:port1', 'ip2:port2', 'ip3:port3', 'user:password@123.456.789.002:8080']
proxy = random.choice(proxy_list)
response = requests.get('https://httpbin.org/ip', proxies={'http': f'http://{proxy}'})
print(response.text)
Вместо случайного выбора можно «зациклить» перебор списка:
import requests
from itertools import cycle
proxy_list = ['ip1:port1', 'ip2:port2', 'ip3:port3']
for proxy in cycle(proxy_list):
response = requests.get('https://httpbin.org/ip', proxies={'http': f'http://{proxy}'})
print(f"Proxy: {proxy}, Answer: {response.json()['origin']}")
Более сложный пример, который:
Сам скрипт (не забудьте создать и наполнить файл с прокси):
import requests, time
from playwright.sync_api import sync_playwright
from itertools import cycle
# Порог пинга в миллисекундах
PING_LIMIT = 100
# Тестовый URL для проверки прокси
TEST_URL = "https://httpbin.org/ip"
def check_proxies():
"""Проверяет прокси из all_proxies.txt и сохраняет рабочие с ping < 100 мс в good_proxies.txt."""
good = []
with open("all_proxies.txt", "r", encoding="utf-8") as f:
proxies = [line.strip() for line in f if line.strip() and not line.startswith("#")]
print(f"[INFO] Found {len(proxies)} proxy for verification...")
for proxy in proxies:
proxies_dict = {"http": proxy, "https": proxy}
start = time.perf_counter()
try:
r = requests.get(TEST_URL, proxies=proxies_dict, timeout=5)
latency = (time.perf_counter() - start) * 1000
if r.ok and latency < PING_LIMIT:
good.append(proxy)
print(f"[OK] {proxy} — {latency:.0f} ms")
else:
print(f"[BAD] {proxy} — slowly ({latency:.0f} ms)")
except Exception:
print(f"[ERR] {proxy} — unavailable")
# Сохраняем подходящие прокси
with open("good_proxies.txt", "w", encoding="utf-8") as f:
for p in good:
f.write(p + "\n")
print(f"[DONE] Working proxies are saved: {len(good)} pcs.")
def parse_with_proxies(url):
"""Функция открывает страницу через Playwright, перебирая прокси из good_proxies.txt при ошибках подключения."""
try:
with open("good_proxies.txt", "r", encoding="utf-8") as f:
proxies = [line.strip() for line in f if line.strip()]
except FileNotFoundError:
print("[ERROR] The file good_proxies.txt not found. First, run check_proxies().")
return
if not proxies:
print("[ERROR] There are no suitable proxies for parsing.")
return
proxy_cycle = cycle(proxies)
print(f"[INFO] Uploaded by {len(proxies)} working proxies")
for proxy in proxy_cycle:
print(f"[TRY] Uploading {url} via {proxy}")
try:
with sync_playwright() as p:
browser = p.chromium.launch(
headless=True,
proxy={"server": proxy}
)
page = browser.new_page()
page.goto(url, timeout=15000)
print("[SUCCESS] Page loaded successfully.")
print("Title:", page.title())
browser.close()
break # если страница открылась — выходим из цикла
except Exception as e:
print(f"[FAIL] Error with {proxy}: {e}")
continue
else:
print("[STOP] All proxies from good_proxies.txt exhausted, parsing stopped.")
if __name__ == "__main__":
# Шаг 1. Проверяем прокси и формируем файл good_proxies.txt
check_proxies()
# Шаг 2. Пример использования парсера
parse_with_proxies("https://example.com/")
Идеальные прокси-серверы для доступа к ценным данным со всего мира.
В случае с готовой инфраструктурой ротируемых прокси, достаточно создать аккаунт и приобрести трафик для прокси. В личном кабинете нужно создать новый порт или фильтр, в котором указываются: расположение, из которого будут подбираться прокси, ISP-провайдер (по желанию), логика ротации (замена выходных IP-адресов раз в N-минут/секунд, максимальное удержание или ротация IP при каждом новом запросе).
На выходе вы получаете параметры подключения. Это своего рода точка входа в прокси-сеть. Подробнее о механизме в материале о BackConnect-прокси.
Простейший пример запуска headless-браузера через библиотеку Playwright и прокси Froxy:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(proxy={
'server': 'http://proxy.froxy.com:9000',
'username': 'user', # заполните своими данными
'password': 'pass' # заполните своими данными
})
page = browser.new_page()
page.goto('https://httpbin.org/ip')
print(page.content())
browser.close()
Даже если IP-адреса прокси будут ротироваться на стороне Froxy, данные для подключения в скрипте менять не нужно.
Обратите внимание, у провайдера прокси могут быть свои технические ограничения и лимиты. Например, при автоматической ротации IP по времени — от 90 секунд до 1 часа. Плюс могут быть лимиты на одновременные (параллельные) подключения и на количество устройств в белом списке.
Сайты могут отслеживать не только IP-адреса, но и сессии (через cookies), http-заголовки, а также другие параметры цифровых отпечатков. Поэтому при ротации IP важно корректно синхронизировать сессии, особенно если вы работаете с целевым сайтом после авторизации в аккаунте или после прохождения процедуры валидации (подробнее об обходе блокировок Cloudflare).
Пример «липких» сессий (с фиксированной привязкой сессии к одному прокси):
import requests
def create_session_with_proxy(proxy):
s = requests.Session()
s.proxies.update({"http": proxy, "https": proxy})
s.headers.update({"User-Agent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"})
return s
proxy = "http://user:pass@1.2.3.4:8000"
sess = create_session_with_proxy(proxy)
# Логин — cookies сохранятся в sess.cookies
login_resp = sess.post("https://example.com/login", data={"user":"u","pass":"p"})
# Дальше делать действия в той же сессии и через тот же proxy
resp = sess.get("https://example.com/protected")
Пример синхронизации смены IP с очисткой/обновлением cookies:
# Когда сменили proxy:
sess.close()
sess = create_session_with_proxy(new_proxy) # чистая сессия, новый cookiejar
Если вы используете прокси-сервис с ротируемыми IP, такой как Froxy, то нужно заранее создать несколько разных портов/фильтров с максимальным удержанием выходных IP — это могут быть «липкие» сессии или просто фильтры с большим временем автоматической ротации. Выгрузив список портов, вы получаете почти полный аналог статических прокси, которые можно ротировать по вашим условиям, например, вместе с очисткой сессии.
Дадим рекомендации в формате советов. Соблюдать их или нет, каждый разработчик парсеров решает сам:
Ротируемые IP-адреса и прокси могут решить массу проблем при парсинге целевых сайтов. Но, к сожалению, не все. Чтобы парсер работал без остановок и банов, нужно подойти к вопросу максимально комплексно и вдумчиво. Где-то сессии и прокси нужно удерживать по максимуму, одновременно позаботившись об эмуляции цифровых отпечатков и человеческого поведения, а где-то полезно ротировать IP при каждом запросе.
Стратегию ротации нужно выстраивать исходя из известных систем защиты целевого сайта. А если политики защиты вам неизвестны, то нужно начать двигаться от простого к сложному, так как самые передовые системы обхода блокировок требуют больше вычислительных ресурсов и сложных скриптов.
Но в любом случае, в основе основ качество прокси. Присмотритесь к Froxy — у нас свыше 10 млн домашних и мобильных IP с гибким геотаргетингом.