Настройка прокси в Scrapy: использование meta proxy для разных IP в каждом запросе
Это руководство объясняет, как подключить HTTP-прокси Socks5Proxy через meta proxy в Scrapy, циклически использовать список, полученный через API, в middleware загрузчика, и настроить скорость для целевого сайта.
Как Scrapy обрабатывает прокси?
В Scrapy по умолчанию включен HttpProxyMiddleware. Если добавить адрес прокси в meta-словарь запроса с ключом proxy, запрос пойдет через этот прокси, а логин и пароль из адреса middleware автоматически преобразует в заголовок Proxy-Authorization. HTTPS-адреса передаются через CONNECT-туннель.
Стандартный обработчик загрузки Scrapy поддерживает HTTP-прокси. Если вам обязательно нужен SOCKS5, потребуется дополнительный обработчик, поэтому в Scrapy мы рекомендуем использовать HTTP-порт того же IP. Целевой сайт увидит тот же IP.
Пример использует IP 198.51.100.23, HTTP-порт 8000, имя пользователя spx_user, пароль spx_pass.
pip install scrapy
scrapy startproject shop
cd shopКак добавить прокси в один запрос?
Добавьте proxy в meta при создании Request в start_requests. В callback для запроса следующей страницы используйте тот же метод. Чтобы сохранить сессию, передавайте proxy из meta предыдущего ответа - это сохранит IP.
import scrapy
PROXY = "http://spx_user:spx_pass@198.51.100.23:8000"
class IpCheckSpider(scrapy.Spider):
name = "ip_check"
def start_requests(self):
yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": PROXY})
def parse(self, response):
self.logger.info("seen as %s", response.json()["ip"])Как ротировать IP для каждого запроса?
Создайте промежуточное ПО для загрузки, которое будет добавлять прокси ко всем запросам, и вы сможете ротировать их без изменения кода паука. Пример ниже загружает список через API при запуске и сохраняет существующий proxy в meta, позволяя сочетать фиксацию сессии и ротацию.
API-ключи можно разместить в settings.py или читать из переменных окружения. Регистрируйте их с числом, меньшим чем у HttpProxyMiddleware(750), чтобы базовый middleware обрабатывал адреса, добавленные middleware.
import itertools
import requests
class RotatingProxyMiddleware:
def __init__(self, key):
text = requests.get(
"https://socks5proxy.io/api/v1/proxies/download",
params={"format": "user:pass@ip:port", "protocol": "http"},
headers={"Authorization": "Bearer " + key},
timeout=30,
).text
self.pool = itertools.cycle(["http://" + l.strip() for l in text.splitlines() if l.strip()])
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings.get("SPX_API_KEY"))
def process_request(self, request, spider):
if "proxy" not in request.meta: # keep a proxy that was set on purpose (sticky sessions)
request.meta["proxy"] = next(self.pool)SPX_API_KEY = "YOUR_API_KEY"
DOWNLOADER_MIDDLEWARES = {
"shop.middlewares.RotatingProxyMiddleware": 740,
}
CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 16
DOWNLOAD_DELAY = 0.25
AUTOTHROTTLE_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 30Как настроить скорость и повторные попытки?
CONCURRENT_REQUESTS_PER_DOMAIN - количество одновременных запросов к одному домену. Чем больше прокси-IP, тем выше можно установить это значение без увеличения нагрузки на один IP. Например, при 500 IP и 50 одновременных запросах каждый IP будет использоваться в среднем один раз на 10 запросов.
Включите AUTOTHROTTLE для автоматической регулировки интервалов запросов по скорости ответа. При увеличении ответов 429 используйте RETRY_HTTP_CODES для повторных попыток, но можно также удалить proxy из meta при повторной попытке, чтобы middleware использовал следующий прокси.
Добавление этапа проверки, что собранные данные - реальные страницы, а не подтверждения, улучшит качество данных. Ответы без нужных элементов можно запросить повторно с другого IP.
- Настройка количества одновременных запросов на домен в зависимости от числа IP
- AUTOTHROTTLE для автоматической регулировки интервалов по скорости ответа
- При 429 и 5xx ошибках попробуйте другой IP
- Проверка содержимого ответа для фильтрации капчи
Что меняется при подключении с авторизацией по IP?
Если зарегистрировать IPv4 сервера, где запущен Scrapy, в панели управления, то можно использовать meta proxy без логина и пароля, например http://198.51.100.23:8000. Список можно получить в формате ip:port. Если вы запускаете пауков на нескольких серверах, зарегистрируйте IP каждого сервера. Можно зарегистрировать до 10 IP.
Как связать запросы, требующие сессии, с одним IP?
Для последовательностей с куки, таких как вход в систему или корзина покупок, используйте один и тот же IP. Укажите meta proxy в первом запросе, а в callback передавайте значение proxy из response.meta, чтобы ротационное middleware не меняло его. Использование cookiejar meta key в Scrapy также помогает разделять куки по сессиям.
Если связать один прокси и один набор cookies с одной сессией, несколько сессий могут работать одновременно, не смешиваясь.
import scrapy
PROXIES = [
"http://spx_user:spx_pass@198.51.100.23:8000",
"http://spx_user:spx_pass@198.51.100.24:8000",
]
class SessionSpider(scrapy.Spider):
name = "sessions"
def start_requests(self):
for i, proxy in enumerate(PROXIES):
yield scrapy.Request("https://example.com/", meta={"proxy": proxy, "cookiejar": i}, dont_filter=True)
def parse(self, response):
# follow-up request keeps the same proxy and the same cookie jar
yield response.follow("/account", meta={"proxy": response.meta["proxy"], "cookiejar": response.meta["cookiejar"]}, callback=self.parse_account)
def parse_account(self, response):
self.logger.info("status %s via %s", response.status, response.meta["proxy"])Как временно исключить проблемный прокси?
Если middleware получает ответ 403 или 429, можно временно отключить этот прокси на несколько минут и отправить тот же запрос через другой прокси. Скопируйте запрос, удалите proxy из meta, включите dont_filter и верните его - следующий прокси возьмёт его в работу.
Управление списком отдыхающих прокси и временем их повторного использования можно упростить с помощью словаря. Избегая повторного использования одних и тех же IP, вы даёте сайтам время снять ограничения.
Какие настройки Scrapy помогают экономить трафик?
Scrapy по умолчанию загружает только HTML и использует значительно меньше трафика, чем инструменты для браузеров. Встроенный HttpCompressionMiddleware поддерживает сжатие ответов, что еще больше сокращает объем передачи. Поэтому даже на общих тарифах можно собрать много страниц в рамках месячного лимита трафика.
Чтобы избежать повторных загрузок одной страницы, включите HTTPCACHE_ENABLED во время разработки - это избавит от лишних запросов к сайту и прокси. В продакшене оставьте фильтрацию дублей (включена по умолчанию) и используйте dont_filter только для запросов, которые действительно нужно повторить.
Важно ограничивать глубину парсинга, чтобы не переходить на ненужные страницы. Это экономит время, трафик и снижает нагрузку на сайт.
Как решить распространенные проблемы?
При ответе 407 проверьте имя пользователя и пароль в адресе. Если в пароле есть специальные символы, используйте процентное кодирование. TunnelError означает, что прокси не получил CONNECT запрос - проверьте, используете ли вы HTTP порт.
Если все запросы идут с одного IP, возможно, middleware стоит после HttpProxyMiddleware или spider напрямую использует meta proxy. Проверьте порядок в settings.py и код spider.