Как настроить собственный прокси в Scrapy (готово для продакшена)

Последнее обновление: August 11, 2026
Hand-drawn Scrapy crawler routing through a proxy pool, retrying a 503 route and completing through a 200 route
AI-сводка
  • Создайте собственный proxy middleware для Scrapy, который назначает разрешённые маршруты, безопасно добавляет авторизацию, фиксирует причины сбоев и сохраняет metadata запроса при повторных попытках.
  • Разберитесь в порядке выполнения downloader middleware, особенно в том, как кастомная логика прокси взаимодействует с HttpProxyMiddleware, RetryMiddleware, редиректами и обработкой исключений.
  • Добавьте ротацию с ограниченным числом попыток, периодами охлаждения, состоянием здоровья прокси и политиками с учётом цели, а не выбирайте случайный прокси для каждого запроса.
  • Различайте ошибки авторизации прокси, сетевые ошибки, DNS-проблемы, ответы 403 от цели и rate limits, чтобы для каждого случая применялся правильный сценарий реакции.
  • Используйте production-защиту для хранения секретов, конкуррентности, наблюдаемости, согласованности сессий и fail-closed поведения, когда не осталось ни одного разрешённого прокси.

Ваш Scrapy spider легко справляется со 100 тестовыми страницами, а потом ломается на 10 000. Это не столько ошибка парсинга, сколько сеть, которая маскируется под баг скрапинга. Самое очевидное решение — proxy middleware Scrapy, и добавить его в request.meta можно буквально за полминуты.

Проблема в том, что именно на этом многие базовые туториалы и заканчиваются. Они показывают meta={"proxy": "http://IP:PORT"}, иногда — класс middleware, и считают задачу закрытой. Но обычно там не говорится, что делать, если прокси умирает посреди обхода, как не засветить креды в истории Git, или почему при повторной попытке может снова использоваться тот же нерабочий прокси. Именно такие вопросы и разбирает это руководство: конфигурация с fail-closed поведением, безопасное хранение секретов, осознанный выбор прокси при retry, ограничения по протоколам и измеряемые компромиссы по стоимости.

Что такое Proxy Middleware в Scrapy?

Proxy middleware — это код, который находится в цепочке загрузки Scrapy и решает, с какого IP-адреса должен выглядеть запрос до того, как он уйдёт в сеть. В Scrapy уже есть встроенный HttpProxyMiddleware: он читает ключ proxy из request.meta, при необходимости добавляет авторизацию прокси и передаёт запрос обработчику загрузки, который уже открывает соединение. Кастомный proxy middleware не заменяет этот шаг транспортировки — он лишь выбирает, какой прокси подставить до того, как сработает встроенная механика. Это различие важнее, чем кажется, и именно оно обычно стоит за жалобами вида «мой кастомный middleware не работает».

Почему прокси важны для production-проектов на Scrapy

Прокси меняют маршрут в сети и видимый источник IP. Это помогает для легитимного тестирования с привязкой к региону, распределения разрешённого трафика и изоляции сетевых сбоев. Но они не дают разрешения, не обходят лимиты и не гарантируют доступ. Нужен ли вообще прокси для конкретного crawl-задания, зависит от цели, её правил, частоты запросов и требований к надёжности.

Не все прокси одинаковы, и неправильный выбор уровня — это уже отдельный production-инцидент:

Тип проксиНадёжностьСкоростьРиск обнаруженияТипичная стоимость
Бесплатные публичные проксиОчень нестабильнаяНестабильнаяЧасто высокийБез оплаты, но с серьёзным риском для безопасности и операций
Дата-центровые проксиЗависит от провайдера и целиЧасто быстрыеЗависит от целиОбычно оплата за ГБ или за IP
Residential-проксиЗависит от провайдера и целиНестабильнаяЗависит от целиОбычно оплата за ГБ
ISP-проксиЗависит от провайдера и целиНестабильнаяЗависит от целиЗависит от провайдера

Бесплатные прокси заслуживают отдельного предупреждения, потому что подтверждённые риски там очень высоки. 30-месячное исследование Free Proxies Unmasked отслеживало более 640 000 адресов от 11 провайдеров: 34,5% из них были активны хотя бы раз, а 16 923 подменяли контент. Эти данные — сильный аргумент против публичных списков; это не универсальный процент отказов для любого актуального списка, платного пула, цели или сценария нагрузки.

Прокси также не «ломают» современную антибот-защиту по щелчку. Сервисы вроде Cloudflare оценивают запросы по десяткам признаков — TLS-отпечатки, согласованность заголовков, выполнение JavaScript, поведенческие паттерны — и IP-адрес там лишь один из факторов. Чистый residential-прокси не спасёт запрос с противоречивыми заголовками и без cookie jar. Не стройте всю архитектуру вокруг идеи «просто будем менять IP».

Перед началом

  • Сложность: средняя
  • Время: ~30–45 минут на полную production-настройку, ~5 минут на быстрый тест
  • Что понадобится: Python 3.9+, установленный Scrapy (руководство протестировано на Scrapy 2.17.0, выпущенном в июле 2026), рабочий spider из scrapy startproject и как минимум один endpoint прокси (для теста подойдёт бесплатный trial у любого провайдера дата-центровых прокси)

Шаг 1: Проверьте прокси через параметр Request Meta

Самый быстрый способ убедиться, что прокси работает, — временно обойти всю архитектуру middleware и просто попробовать его напрямую.

Встроенный в Scrapy HttpProxyMiddleware читает ключ proxy прямо из request.meta и отправляет запрос через него. Никаких изменений в settings, никакого класса middleware — только один аргумент.

import scrapy

class ProxyTestSpider(scrapy.Spider):
    name = "proxy_test"
    start_urls = ["https://httpbin.org/ip"]

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(
                url,
                meta={"proxy": "http://203.0.113.10:8080"},
                callback=self.parse,
            )

    def parse(self, response):
        self.logger.info(response.text)

Запустите это командой scrapy runspider proxy_test.py. Если всё работает, httpbin.org/ip вернёт IP прокси, а не ваш собственный — это и будет подтверждением. Если ответ зависает и в итоге выдаёт TCP connection timed out, значит прокси мёртв или недоступен, что, спойлер, случается куда чаще, чем любят признавать провайдеры.

Для одноразовых spiders или быстрой проверки этого достаточно. Но как только у вас больше одного spider, подход ломается: один и тот же прокси-адрес оказывается захардкожен в пяти разных файлах.

Шаг 2: Создайте собственный Proxy Middleware

Если проект не ограничивается одним spider, логику прокси лучше держать в одном месте. Создайте класс ProxyMiddleware в middlewares.py вашего проекта:

from scrapy.exceptions import NotConfigured

class ProxyMiddleware:
    def __init__(self, proxy_url):
        self.proxy_url = proxy_url

    @classmethod
    def from_crawler(cls, crawler):
        proxy_url = crawler.settings.get("PROXY_URL")
        if not proxy_url:
            raise NotConfigured("PROXY_URL обязателен; тихий переход на прямое соединение запрещён")
        return cls(proxy_url=proxy_url)

    def process_request(self, request, spider):
        if "proxy" not in request.meta:
            request.meta["proxy"] = self.proxy_url

И зарегистрируйте его в settings.py:

import os

PROXY_URL = os.environ.get("PROXY_URL")

DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.ProxyMiddleware": 350,
}

Обратите внимание на from_crawler, а не на обычный __init__. Именно этот паттерн Scrapy рекомендует для чтения настроек, и к нему мы ещё вернёмся в шаге 4, когда будем говорить о секретах. Плюс здесь простой: меняете одну настройку — и все spiders в проекте получают новый прокси. Больше не нужно искать по пяти файлам старый IP и вручную его заменять.

Шаг 3: Разберитесь с порядком выполнения middleware, чтобы прокси не «молчаливо» не работал

Вот та часть, которую почти все остальные статьи пропускают фразой вроде «просто поставьте priority 350, поверьте». Downloader middleware в Scrapy выполняются в строго определённом порядке, и если его не понимать, настройка прокси начнёт порождать ошибки, которые на прокси вообще не похожи.

Хуки на этапе запроса (process_request) идут по возрастанию приоритета — от меньшего числа к большему. Хуки на этапе ответа (process_response, process_exception) идут по убыванию — от большего числа к меньшему, разворачивая цепочку назад.

Поток запроса (по возрастанию):
  Spider → [100] RobotsTxt → [300] HttpAuth → [350] ВАШ PROXY MIDDLEWARE
         → [500] UserAgent → [550] Retry → [700] Cookies → [750] HttpProxy
         → Downloader

Поток ответа (по убыванию):
  Downloader → [750] HttpProxy → [700] Cookies → [550] Retry
             → [500] UserAgent → [350] ВАШ PROXY MIDDLEWARE → [300] HttpAuth
             → [100] RobotsTxt → Spider

Ниже — актуальная таблица приоритетов встроенных middleware Scrapy (проверено на версии 2.17.0):

MiddlewareПриоритет по умолчанию
RobotsTxtMiddleware100
HttpAuthMiddleware300
DownloadTimeoutMiddleware350
DefaultHeadersMiddleware400
UserAgentMiddleware500
RetryMiddleware550
RedirectMiddleware600
CookiesMiddleware700
HttpProxyMiddleware750
DownloaderStats850
HttpCacheMiddleware900

Когда RetryMiddleware планирует повторную попытку, он копирует неудачный запрос — вместе с его metadata — и новый запрос снова проходит через цепочку downloader middleware. Числовое соотношение selector-кода к приоритету 550 не гарантирует ротацию. Ротация происходит только тогда, когда код selector распознаёт retry и намеренно перезаписывает скопированное meta["proxy"]. Приоритет 350 удобен для selector-а, потому что он срабатывает до встроенного транспортного шага на 750, но сам по себе он не является механизмом ротации.

Пути запросов и ответов Scrapy через приоритеты 350, 550 и 750, где retry после 503 снова входит в цепочку middleware

Частые ошибки при настройке порядка middleware

  • Ставить ваш middleware на тот же приоритет, что и HttpProxyMiddleware (750): это создаёт гонку, в которой порядок обработки запроса зависит от порядка в словаре Scrapy, а не от вашей логики. Симптом: периодическое, необъяснимое поведение прокси.
  • Использовать setdefault() или if "proxy" not in request.meta в selector с ротацией: у копии retry остаётся старый прокси. Симптом: каждый повтор снова идёт по тому же провальному маршруту. Исправление: распознавать retry (например, через retry_times > 0) и явно заменять значение прокси, которым управляет selector.
  • Полностью отключать HttpProxyMiddleware: некоторые туториалы советуют поставить "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": None, потому что «всё делает кастомный middleware». На самом деле нет — ваш middleware лишь выбирает прокси, а не выполняет транспортный слой. Если отключить встроенный модуль, заголовки авторизации прокси никогда не добавятся, и запросы либо уйдут без авторизации, либо не уйдут вовсе.

Шаг 4: Перестаньте хардкодить учётные данные прокси

Почти каждый топовый туториал по proxy в Scrapy предлагает писать http://username:password@proxy.example.com:8080 прямо в Python-файл. Это значит, что секрет навсегда попадёт в Git history, будет виден в каждом clone и fork и может всплыть в логах, если кто-то неаккуратно использует print().

На практике есть три уровня решения:

МетодБезопасностьГибкостьЛучше всего подходит для
Захардкожено в spider/settings.pyПлохо — секреты живут в репозиторииНизкаяТолько для быстрого локального тестирования
Переменная окружения http_proxy (нативно для Scrapy)Лучше — вне кодаНизкая (один прокси)CI/CD, Docker
.env + python-dotenv + from_crawlerЛучшее — вне кода, под разные окруженияВысокая (несколько прокси, ротация)Production-скраперы

Третий вариант стоит внедрять нормально. Установите python-dotenv, создайте файл .env и сразу же добавьте его в .gitignore — серьёзно, сделайте это сразу:

PROXY_USER=myuser
PROXY_PASSWORD=my$ecret!Pass
PROXY_HOST=proxy.example.com
PROXY_PORT=8080

Затем загрузите переменные в начале settings.py:

from dotenv import load_dotenv
import os

load_dotenv()

PROXY_USER = os.getenv("PROXY_USER")
PROXY_PASSWORD = os.getenv("PROXY_PASSWORD")
PROXY_HOST = os.getenv("PROXY_HOST")
PROXY_PORT = os.getenv("PROXY_PORT")

После этого читайте их безопасно внутри middleware через from_crawler — именно этот паттерн решает тот самый вопрос, который часто всплывает на форумах: «как задать это до запуска scrapy crawl, если креды нужно менять от запуска к запуску?»:

import os
from urllib.parse import quote

class SecureProxyMiddleware:
    def __init__(self, user, password, host, port):
        self.user = quote(user, safe="")
        self.password = quote(password, safe="")
        self.host = host
        self.port = port

    @classmethod
    def from_crawler(cls, crawler):
        settings = crawler.settings
        return cls(
            user=settings.get("PROXY_USER"),
            password=settings.get("PROXY_PASSWORD"),
            host=settings.get("PROXY_HOST"),
            port=settings.get("PROXY_PORT"),
        )

    def process_request(self, request, spider):
        proxy_url = f"http://{self.user}:{self.password}@{self.host}:{self.port}"
        request.meta["proxy"] = proxy_url

Обратите внимание на urllib.parse.quote() для логина и пароля. Если в пароле есть @, : или / (а генераторы паролей обожают такие символы), URL сломается, если сначала не закодировать их в percent-encoding. Это однострочное исправление экономит очень неловкий час отладки ошибки «invalid proxy URL», которая на самом деле не связана с тем, что ваш прокси плохой.

Держите креды подальше от логов и тестируйте percent-encoding на реалистичных, но фейковых значениях. HTTPS-tunneling, SOCKS5 и не-латинские символы в учётных данных имеют ограничения на уровне конкретных handlers; не надо считать, что один и тот же паттерн авторизации без тестов будет работать везде.

Безопасный поток от защищённого файла окружения через percent-encoded proxy-настройки в metadata запросов Scrapy

Шаг 5: Добавьте ротацию прокси

Один прокси — даже хороший — рано или поздно будет замечен, если отправить через него 5000 запросов на один и тот же сайт. Нужен пул.

Вариант A — собрать всё самому. На самом деле это очень просто:

import random

class RotatingProxyMiddleware:
    def __init__(self, proxy_pool):
        self.proxy_pool = proxy_pool

    @classmethod
    def from_crawler(cls, crawler):
        return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))

    def process_request(self, request, spider):
        request.meta["proxy"] = random.choice(self.proxy_pool)

Для базового сценария это работает, но здесь вообще нет понимания, какие прокси реально живы. По сути, вы кидаете кости на каждый запрос.

Вариант B — использовать scrapy-rotating-proxies. Этот сторонний пакет сразу даёт детект банов и автоматический backoff:

pip install scrapy-rotating-proxies

Скажу честно: последний релиз на PyPI — версия 0.6.2, датированная 2019 годом, а проект помечен как Alpha. Это не значит, что он сломан на современном Scrapy, но «не обновлялся с 2019 года» — это не то же самое, что «обкатан на production-трафике 2026 года». Зафиксируйте версию, проверьте её на реальных целевых сайтах и не думайте, что она хорошо работает с аутентифицированными endpoint-ами прокси — в целом это не так.

Шаг 6: Сделайте middleware устойчивым к сбоям (обнаружение мёртвых прокси)

Это раздел, который конкурирующие статьи обычно пропускают полностью, и именно он отделяет демо от решения, которое переживает 6-часовой crawl без присмотра.

СценарийЧто показывают большинство туториаловЧто добавляет это middleware
Прокси возвращает 407Не рассматриваетсяСчитает это ошибкой авторизации прокси
Цель возвращает 403/429Часто смешивают вместеРазделяет политику/лимиты цели и здоровье прокси
Прокси таймаутитсяНе рассматриваетсяНастраиваемый порог таймаута, деградация health score
Все прокси мертвыНе рассматриваетсяАккуратный fallback или пауза crawl с логированием предупреждения
Прокси флапает (работает нестабильно)Не рассматриваетсяПериод охлаждения перед повторным добавлением в пул
import time
import random
from scrapy.exceptions import IgnoreRequest

class FaultTolerantProxyMiddleware:
    MAX_FAILURES = 3
    COOLDOWN_SECONDS = 300

    def __init__(self, proxy_pool):
        self.pool = {p: {"failures": 0, "banned_until": 0} for p in proxy_pool}

    @classmethod
    def from_crawler(cls, crawler):
        return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))

    def _healthy_proxies(self):
        now = time.time()
        return [p for p, s in self.pool.items() if s["banned_until"] < now]

    def process_request(self, request, spider):
        healthy = self._healthy_proxies()
        if not healthy:
            spider.logger.warning("Все прокси проблемные — приостанавливаем crawl")
            raise IgnoreRequest("Нет доступных здоровых прокси")
        request.meta["proxy"] = random.choice(healthy)

    def process_response(self, request, response, spider):
        proxy = request.meta.get("proxy")
        if proxy and response.status == 407:
            self._mark_failure(proxy)
        return response

    def process_exception(self, request, exception, spider):
        proxy = request.meta.get("proxy")
        if proxy:
            self._mark_failure(proxy)

    def _mark_failure(self, proxy):
        state = self.pool[proxy]
        state["failures"] += 1
        if state["failures"] >= self.MAX_FAILURES:
            state["banned_until"] = time.time() + self.COOLDOWN_SECONDS
            state["failures"] = 0

Пара важных замечаний из практики: не считайте каждый 403 доказательством того, что сам прокси мёртв — RFC 9110 определяет 403 как «сервер понял запрос, но отказывает в выполнении», а значит проблема может быть в заголовках или сессии, а не в прокси. А вот 407, наоборот, означает, что именно прокси отклоняет авторизацию — это более сильный и конкретный сигнал. Смешивать эти сигналы в одну корзину — быстрый способ сжечь нормальные прокси без причины.

Держите стандартные retry-коды Scrapy явными в production, чтобы ревьюерам была видна политика:

RETRY_HTTP_CODES = [500, 502, 503, 504, 522, 524, 408, 429]
RETRY_TIMES = 2

Это дефолты Scrapy 2.17. Не надо бездумно добавлять сюда 403 или 407: 403 — это отказ со стороны цели по множеству возможных причин, а 407 — проблема авторизации прокси, которую обычный retry не исправит. Если конкретный контракт с целью оправдывает retry для другого статуса, это нужно отдельно задокументировать и протестировать.

Раздельная обработка ошибки авторизации 407, ограничения 429, retry на 503, успешного 200 и закрытых ворот, когда прокси недоступны

Шаг 7: Измеряемый паттерн proxy-on-retry

Некоторые разрешённые цели могут отдавать валидный контент напрямую, а прокси им нужны только после документированного временного ответа. Это может уменьшить объём трафика через прокси, но универсального процента экономии или переносимого процента успешных прямых запросов не существует. Прежде чем применять такой подход, измерьте свой собственный workload.

Используйте публичный helper Scrapy get_retry_request() и ограничивайте escalation только теми статусами цели, которые вы явно классифицировали. В этом примере 429 и 503 считаются сигналами нагрузки, требующими retry; 403 и 407 намеренно исключены.

from scrapy.downloadermiddlewares.retry import get_retry_request

class CostAwareEscalationMiddleware:
    def process_response(self, request, response, spider):
        if response.status not in {429, 503}:
            return response

        retry = get_retry_request(
            request,
            spider=spider,
            reason=f"proxy_escalation_{response.status}",
            max_retry_times=2,
        )
        if retry is None:
            return response

        current_tier = request.meta.get("proxy_tier", "direct")
        if current_tier == "direct":
            retry.meta["proxy"] = spider.settings["DATACENTER_PROXY"]
            retry.meta["proxy_tier"] = "datacenter"
        elif current_tier == "datacenter":
            retry.meta["proxy"] = spider.settings["RESIDENTIAL_PROXY"]
            retry.meta["proxy_tier"] = "residential"
        else:
            return response
        return retry

Логируйте долю валидного контента при прямом доступе, долю валидного контента через прокси, байты на успешно собранную запись, число retries на один успех и добавленную задержку. Архитектура direct-first допустима только тогда, когда прямой доступ разрешён, а система уходит в fail-closed, если прокси всё же требуется. Экономия — это измеренное снижение объёма трафика через прокси, а не предположение в процентах.

Когда не стоит делать управление прокси своими силами

Хочу сказать это прямо, чтобы не создавать ощущение, будто всё, что было выше, — пустая трата времени: всё описанное выше — реальная и полезная инженерия, и для многих проектов — high-volume crawl, кастомные пайплайны, задачи, где нужен полный контроль над планированием запросов — это правильный путь.

Но если ваша настоящая цель — «получить структурированные данные со страницы», а не «поддерживать инфраструктуру прокси», то extraction API может быть лучшей границей ответственности. Текущая документация Thunderbit для POST /extract принимает URL страницы и необязательный JSON Schema; если схема не указана, сервис может сгенерировать её по содержимому страницы. Endpoint также поддерживает режимы none, basic и full, а также настройки таймаута и ожидания после загрузки. Prompt-only extraction в текущем поддерживаемом интерфейсе запроса нет, поэтому production-интеграции стоит строить вокруг документированного контракта схемы. Это переносит интерфейс извлечения за один запрос; это не означает универсального обещания по обходу любого антибота или CAPTCHA.

ФакторDIY Scrapy + проксиИзвлечение через API (например, Thunderbit)
Сложность настройкиВысокая — middleware, ротация, retry-логикаНизкая — один API-запрос со схемой
Поведение сети и рендерингаВы настраиваете handlers, прокси, заголовки и задержкиУправляется документированными опциями API
Поддержка и сопровождениеВы отвечаете за селекторы, здоровье пула и изменения целиВы отвечаете за качество схемы, валидацию и интеграцию
Модель стоимостиОплата прокси + вычисления + время инженеровВ текущей документации указано 20 единиц за страницу (проверено 2026-08-10)
КонтрольПолный — кастомные пайплайны, цепочка middlewareОграничен возможностями API
Лучше всего дляСложные crawl-задачи, высокий объём, кастомная логикаТочечное извлечение, прототипирование, enrichment

Если вам в основном нужно извлекать структурированные страницы для списков лидов, данных о товарах или исследований, проведите пилот на реальном кейсе с Thunderbit Chrome Extension или через API и сравните число валидных записей, latency, units и время на сопровождение. Если проекту нужны кастомные графы обхода и полный контроль над pipeline, Scrapy по-прежнему будет сильнее.

Узнать больше

Советы и частые ошибки

  • Совет: проверьте прокси на httpbin.org/ip перед тем, как направлять их на реальную цель. Это самый быстрый способ понять, что маршрутизация работает, до того как вы усложните систему.
  • Ошибка: указывать прокси в request.headers вместо request.meta. Это очень распространённая ошибка по невнимательности — HttpProxyMiddleware читает только meta["proxy"], а попытка через header просто тихо не сработает без очевидной ошибки.
  • Ошибка: считать, что HTTP- и HTTPS-прокси настраиваются одинаково. URL HTTP-прокси, ведущий к HTTPS-цели, обычно работает через CONNECT-туннелирование при совместимом handler-е, но https:// для самого endpoint-а прокси — это другая, менее поддерживаемая конфигурация. Не путайте эти случаи.
  • Совет: если вам нужна поддержка SOCKS5, сначала проверьте возможности download handler в вашей версии Scrapy. В экспериментальном Httpx handler у Scrapy 2.17 появилась поддержка SOCKS5 через httpx[socks], но статус всё ещё экспериментальный — не делайте на этом production-зависимость без собственного тестирования.

Альтернативные способы

Помимо scrapy-rotating-proxies, некоторые команды выносят всю логику прокси в gateway провайдера — единый URL прокси, где ротацией, закреплением сессий и geo-targeting управляет сам поставщик. Это немного снижает контроль, но сильно уменьшает объём middleware-кода, и такой вариант стоит просчитать по цене до того, как собирать всё с нуля.

Заключение

Настроить прокси в Scrapy можно одной строкой. Но чтобы эта схема выдержала настоящий production-crawl, нужны явная политика отказов, защищённые секреты, протестированные границы handler-ов и selector-код, который сознательно заменяет скопированную metadata прокси при retry. Если унести с собой две привычки, пусть это будут следующие: уходить в fail-closed, когда прокси обязателен, и никогда не коммитить пароль прокси в Python-файл.

FAQ

Как настроить собственный прокси в Scrapy с авторизацией? Используйте формат URL protocol://username:password@host:port, но сначала закодируйте имя пользователя и пароль через urllib.parse.quote(), если в них есть специальные символы. Для production-чтения берите эти креды через from_crawler, загружая их из переменных окружения, а не хардкодьте в коде.

Какой номер приоритета использовать для кастомного proxy middleware в Scrapy? 350 — распространённый приоритет selector-а, потому что он срабатывает до HttpProxyMiddleware на 750. Но это не гарантирует ротацию. Повторный запрос получит новый прокси только если selector распознает копию retry и перезапишет прежнее значение meta["proxy"].

Как автоматически обрабатывать мёртвые прокси в Scrapy? Сделайте middleware, которое считает число ошибок по каждому прокси в process_response и process_exception, исключает прокси из активного пула после порога сбоев и возвращает их обратно после периода охлаждения, а не банит навсегда.

Можно ли использовать Scrapy с SOCKS5-прокси? В экспериментальном HttpxDownloadHandler Scrapy 2.17 указана поддержка SOCKS5 при установленном httpx[socks]. Стандартный HTTP/1.1 handler SOCKS-прокси не поддерживает. Зафиксируйте версию handler-а и проверьте это интеграционным тестом, прежде чем считать путь production-ready.

Сколько реально можно сэкономить с паттерном proxy-on-retry? Универсального процента нет. Измеряйте долю разрешённых запросов, которые возвращают валидный контент напрямую, количество байтов, идущих через каждый уровень прокси, число retries на одну успешную запись и добавленную задержку. Реальная экономия — это измеренное сокращение трафика через прокси; если прямой доступ не разрешён или не работает, не используйте этот подход.

Ke
Ke
Технический директор в Thunderbit | Senior Data Scientist и эксперт по ML Имея почти десятилетний опыт в машинном обучении и data science, Кэ Шэнь — выпускник Колумбийского университета и бывший Senior Data Scientist в Walmart Labs. Обладая глубокой, признанной коллегами экспертизой в Python, R, Java и статистике, он делится проверенными на практике наблюдениями о том, как переводить сложные AI-алгоритмы из теории в production-grade архитектуру.
Topics
Промежуточное ПО Scrapy для проксиВеб-скрапинг на PythonРотация прокси
Содержание
Thunderbit · AI-агент для веб-данных

Извлекай данные с любой страницы за 1 клик

Нам доверяют более 250 000 пользователей
доступен бесплатный тариф
От веб-страницы к таблице
Опиши, что тебе нужно, — AI-агент Thunderbit соберет это и экспортирует в Excel, Google Sheets, Airtable или Notion. Старт бесплатный.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week