Ротация прокси для веб-скрапинга: Python requests, middleware Scrapy и отслеживание позиций
Практическое руководство по ротации прокси в Python и Scrapy — выбор пула, липкие сессии против ротации на каждый запрос, рабочий код middleware, обнаружение блокировок и почему трекерам позиций нужна согласованность локации, а не просто объём IP.
Если вы спарсите несколько сотен страниц с одного IP, рано или поздно вы столкнётесь с ограничением скорости, CAPTCHA или мягкой блокировкой. Ротация — стандартное решение, но плохая ротация хуже, чем её отсутствие: она сжигает бюджет на прокси, усложняет отладку и может выглядеть ещё более по-ботовски, чем стабильный вежливый краулер.
Это руководство рассказывает, как работает ротация, как реализовать её в Python с помощью requests и в Scrapy с помощью middleware загрузчика, и как те же методы применимы к отслеживанию позиций в SERP.
Прежде чем приступать к ротации, проверьте, не в ротации ли проблема
Ротация скрывает блокировки на уровне IP. Она не решает:
- Проблема шаблона. Никакое количество IP не спасёт краулер, который запрашивает один и тот же URL пятьдесят раз в секунду с user-agent по умолчанию.
- Проблема сессии. Если ваш сценарий требует оставаться в системе, новый IP посреди сессии выглядит как кража аккаунта.
- Проблема геолокации. Если нужный вам контент заблокирован по региону, вам нужна правильная страна, а не больше IP.
Сначала проведите диагностику: логируйте коды состояния, тела ответов и время ответа для каждого IP. Если каждый IP получает 200, а одна конкретная страница возвращает блокировку, ваша проблема — в поведении запросов, а не в репутации IP.
Выберите тип прокси, подходящий для задачи
| Тип | Типичные преимущества | На что обратить внимание |
|---|---|---|
| Дата-центр | Быстрые, высокая параллельность, широко доступны | Легко идентифицируются; блокируются строгими сайтами |
| Резидентные | Смешиваются с трафиком реальных пользователей | Медленнее; ограничения по пропускной способности; важна работа с сессиями |
| Мобильные | Высокое доверие, сложнее всего блокировать | Дорогие; нестабильные; меньше одновременных сессий |
| ISP / статические резидентные | Стабильный, постоянный IP | Меньше пулы; меньше ротации |
Для структурированных данных на лояльных сайтах обычно достаточно дата-центров. Для поисковой выдачи, маркетплейсов и туристических сайтов, как правило, требуются резидентные или мобильные прокси. Оценивайте провайдеров по гранулярности ротации, контролю сессий, геопокрытию и обработке блокировок — а не по заявленному количеству IP.
Стратегии ротации
Ротация на каждый запрос
Каждый запрос уходит с IP, выбранного из пула. Многие провайдеры реализуют это как один ротируемый шлюз (имя хоста) плюс порт или как токен сессии в имени пользователя. Лучший вариант для запросов страниц без сохранения состояния.
Липкие сессии
Один и тот же IP переиспользуется в течение заданного окна или пока вы его не освободите. Используйте это для многошаговых сценариев: поиск, открытие листинга, чтение страницы с деталями. В большинстве коммерческих пулов липкость управляется идентификатором сессии в имени пользователя прокси, и новый идентификатор даёт новый IP.
Географическая привязка
Для отслеживания позиций и проверки цен обычно требуется один и тот же город или страна для набора запросов, поскольку результаты зависят от местоположения. Ротируйте внутри гео, а не между гео.
Ограничение параллельности
Ротация и ограничение скорости дополняют друг друга, а не заменяют. Краулер с пятью одновременными запросами, соблюдающий Retry-After, покажет лучшие результаты, чем краулер с двумя сотнями потоков, долбящих каждый IP, пока его не забанят.
Python: ротация прокси с помощью requests
Установите поддержку SOCKS, если она нужна. Библиотека requests использует PySocks под капотом:
pip install "requests[socks]"
Затем выполняйте ротацию по пулу:
import itertools
import requests
POOL = [
'http://user:[email protected]:8000',
'http://user:[email protected]:8000',
'socks5h://user:[email protected]:1080',
]
proxy_cycle = itertools.cycle(POOL)
def fetch(url, timeout=20):
proxy = next(proxy_cycle)
proxies = {'http': proxy, 'https': proxy}
response = requests.get(url, proxies=proxies, timeout=timeout)
response.raise_for_status()
return response.text
Несколько моментов, которые стоит добавить в продакшене:
- Повторяйте запрос с другим прокси при
429или403, а не с тем же самым. - Используйте
requests.Session()для переиспользования соединений, но создавайте одну сессию на IP, а не одну сессию на весь краулинг. - Логируйте, какой прокси дал какой результат, чтобы вы могли отбрасывать плохие IP, а не снова их выбирать.
- Используйте
socks5h://(обратите внимание наh), когда хотите, чтобы имена хостов разрешались на прокси, а не локально.
Scrapy: middleware загрузчика с ротацией прокси
Scrapy уже обрабатывает аутентификацию прокси через встроенный middleware HTTP-прокси, поэтому вам нужно только установить request.meta['proxy'] перед отправкой запроса. Простой middleware ротации выглядит так:
import random
class RotatingProxyMiddleware:
def __init__(self, proxies):
self.proxies = proxies
@classmethod
def from_crawler(cls, crawler):
proxies = crawler.settings.getlist('ROTATING_PROXIES')
if not proxies:
raise ValueError('ROTATING_PROXIES is empty')
return cls(proxies)
def process_request(self, request, spider):
request.meta['proxy'] = random.choice(self.proxies)
Зарегистрируйте его в модуле настроек:
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.RotatingProxyMiddleware': 350,
}
ROTATING_PROXIES = [
'http://user:[email protected]:8000',
'http://user:[email protected]:8000',
]
AUTOTHROTTLE_ENABLED = True
RETRY_HTTP_CODES = [403, 429, 500, 502, 503, 504]
Два замечания:
- Наивный
random.choiceбудет продолжать использовать забаненные IP. Такие проекты сообщества, какscrapy-rotating-proxies, добавляют обнаружение блокировок и статистику по каждому прокси поверх той же идеи; эта зависимость оправдана, когда вы масштабируетесь дальше нескольких запросов. - Middleware повторных попыток Scrapy обычно повторяет запрос с тем же прокси. Если баны — ваша проблема, заставьте путь повторной попытки заново выбирать прокси.
Применение того же подхода к отслеживанию позиций
У трекеров позиций есть требование к прокси, которого нет у обычных скраперов: согласованность локации. Ключевое слово, проверенное из одного города, а затем из другого, даст разные SERP и бессмысленный график движения.
Практические правила для отслеживания позиций:
- Выберите одну локацию для каждого отслеживаемого ключевого слова и сохраняйте её стабильной между запусками.
- Периодически обновляйте IP, чтобы вас не пометили, но оставайтесь в пределах того же города или региона.
- Используйте мобильные прокси при отслеживании мобильной выдачи, потому что десктопные и мобильные SERP различаются достаточно сильно, чтобы это имело значение.
- Агрессивно кэшируйте и проверяйте по расписанию, а не непрерывно.
Также стоит прямо сказать: скрапинг поисковых систем обычно нарушает их условия обслуживания. Если вам нужны надёжные данные о позициях, официальные API и лицензированные фиды для отслеживания позиций — путь с меньшим риском. Прокси нужны для случаев, когда API действительно не существует.
Как понять, работает ли ротация
Отслеживайте эти показатели за весь краулинг, а не по каждому запросу:
- Доля успешных запросов на прокси, то есть ответы 2xx, делённые на количество попыток.
- Доля блокировок на прокси с указанием типа блокировки:
403, CAPTCHA, пустое тело, страница согласия. - Медианное время ответа на прокси. Прокси, который работает, но тратит тридцать секунд на страницу, — чистый убыток.
- Фактически использованные уникальные IP по сравнению с размером настроенного пула.
Если доля успешных запросов одинакова для всех IP, ваша проблема не в репутации IP, и никакая ротация не поможет.
Вывод
Ротируйте только после того, как исправили частоту запросов, заголовки и логику сессий. Используйте ротацию на каждый запрос для запросов без сохранения состояния и липкие сессии для всего многошагового. В Python requests требует дополнения SOCKS и прокси на сессию, тогда как в Scrapy middleware загрузчика, назначающий request.meta['proxy'], делает большую часть работы, а пакеты для отслеживания банов — остальное. А для отслеживания позиций считайте географию требованием, а ротацию — обслуживанием.