Прокси в Scrapy: middleware и ротация
Scrapy — асинхронный фреймворк для краулинга на Python. Он масштабируется на тысячи запросов в минуту и имеет встроенную поддержку прокси через middleware. Пул адресов NEONPROXY снижает блокировки при сборе публичных данных — цен, каталогов, SEO-метрик. Ниже — настройка HttpProxyMiddleware, кастомная ротация и обработка ошибок. Соблюдайте robots.txt и Terms of Service целевых сайтов.
Встроенный HttpProxyMiddleware
Самый простой способ — указать один прокси в settings.py с авторизацией в URL:
# settings.py
DOWNLOADER_MIDDLEWARES = {
"scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": 750,
}
PROXY = "http://login:password@123.45.67.89:8080"
В spider переопределите метод, добавляющий meta:
class MySpider(scrapy.Spider):
name = "example"
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(
url,
meta={"proxy": self.settings.get("PROXY")},
callback=self.parse
)
Ротация через middleware
Для пула прокси создайте кастомный middleware — round-robin на каждый request:
import random
from scrapy.exceptions import NotConfigured
class RotatingProxyMiddleware:
def __init__(self, proxies, user, password):
self.proxies = proxies
self.auth = f"{user}:{password}@"
self.index = 0
@classmethod
def from_crawler(cls, crawler):
proxies = crawler.settings.getlist("ROTATING_PROXIES")
user = crawler.settings.get("PROXY_USER")
password = crawler.settings.get("PROXY_PASS")
if not proxies:
raise NotConfigured
return cls(proxies, user, password)
def process_request(self, request, spider):
host = self.proxies[self.index % len(self.proxies)]
self.index += 1
request.meta["proxy"] = f"http://{self.auth}{host}"
request.meta["proxy_host"] = host
Регистрация в settings:
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.RotatingProxyMiddleware": 350,
"scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": 750,
}
ROTATING_PROXIES = ["1.2.3.4:8080", "5.6.7.8:8080", "9.10.11.12:8080"]
PROXY_USER = "login"
PROXY_PASS = "password"
Стратегии sticky vs round-robin — в гайде по ротации.
Обработка 403 и 429
Помечайте «холодные» прокси и повторяйте запрос с другим IP:
from scrapy.downloadermiddlewares.retry import RetryMiddleware
class ProxyRetryMiddleware(RetryMiddleware):
def process_response(self, request, response, spider):
if response.status in (403, 429, 502, 503):
host = request.meta.get("proxy_host")
spider.crawler.engine.slot.scheduler.df.cold_proxies.add(host)
reason = f"proxy_banned_{response.status}"
return self._retry(request, reason, spider) or response
return response
Задайте RETRY_TIMES = 3 и DOWNLOAD_DELAY = 1 — уважайте лимиты сайта.
SOCKS5 в Scrapy
Стандартный HttpProxyMiddleware работает с HTTP-прокси. Для SOCKS5 установите scrapy-socks или используйте HTTP-режим NEONPROXY на том же порту — оба протокола доступны на одном заказе, см. SOCKS5 vs HTTPS.
Загрузка пула из API
При старте проекта подгружайте список из API NEONPROXY:
import requests
def load_proxies(api_key):
r = requests.get(
"https://svyaz.mom/api/v2/proxy/list",
headers={"Authorization": f"Bearer {api_key}"}
)
return [f"{p['ip']}:{p['port_http']}" for p in r.json()["data"]]
Для IPv6-пулов при парсинге открытых сайтов см. IPv6 vs IPv4.
Отладка и метрики
Перед добавлением в пул проверяйте адреса в чекере. Логируйте success rate по каждому IP в spider stats. Для JS-страниц Scrapy не подходит — используйте Playwright или Puppeteer. Простые запросы — requests.
Выбор типа прокси
Массовый краулинг публичных каталогов — IPv6 или shared IPv4 с ротацией. Редкие запросы к чувствительным площадкам — приватный IPv4. Критерии — как выбрать прокси. Заказ — NEONPROXY.