Все статьиРуководства15 мин

Настройка прокси для мониторинга цен конкурентов

Пошаговое руководство по настройке прокси для мониторинга цен: ротация IP, geo-targeting, sticky-сессии, обход антибот-защит. Код на Python и bash.

Команда InfraProxy

13 апреля 2026 г.

#мониторинг цен#прокси#ротация IP#e-commerce#Python#антибот

Почему мониторинг цен ломается без прокси

Мониторинг цен конкурентов — одна из базовых задач e-commerce. Но маркетплейсы и интернет-магазины активно защищаются от автоматического сбора: rate-limiting, CAPTCHA, блокировка по IP, гео-зависимые цены.

Без правильно настроенных прокси система мониторинга деградирует: сначала появляются пустые ответы, потом блокировки, потом — неверные данные (сайт отдаёт другие цены для заблокированных IP). Результат — бизнес-решения на основе мусора.

В этом руководстве — конкретная настройка прокси для стабильного мониторинга цен. Не теория, а рабочие конфигурации и код.

Архитектура: как прокси встраиваются в пайплайн мониторинга

Типичный пайплайн мониторинга цен состоит из четырёх компонентов:

  1. Планировщик — определяет, какие URL и когда проверять
  2. Краулер — выполняет запросы через прокси
  3. Парсер — извлекает цены из HTML/JSON
  4. Хранилище — сохраняет данные для анализа

Прокси работают на уровне краулера. Правильная конфигурация определяет, будут ли запросы успешными.

Планировщик → [URL Queue] → Краулер → [Proxy Pool] → Целевой сайт
                                ↓
                            Парсер → [Price DB] → Дашборд

Подробнее о построении полного инструмента — в нашей статье «Как построить инструмент мониторинга цен». Здесь сфокусируемся на прокси-части.

Шаг 1: Выбор типа прокси для мониторинга цен

Не все прокси одинаково подходят для ценового мониторинга. Выбор зависит от целевых сайтов.

| Характеристика | Datacenter | ISP Static | Residential (rotating) | |---------------|-----------|-----------|----------------------| | Скорость | До 1 Gbps | 100–500 Mbps | 10–50 Mbps | | Стоимость | Низкая | Средняя | Высокая | | Блокировки на маркетплейсах | Средние | Низкие | Минимальные | | Стабильность IP | Постоянный | Постоянный | Меняется | | Подходит для | Открытые каталоги, API | Маркетплейсы, магазины | Антибот-защита |

Рекомендации по типу сайта

  • Открытые каталоги (без антибот-защиты): datacenter прокси — максимальная скорость, минимальная стоимость
  • Маркетплейсы (Ozon, Wildberries, Amazon): ISP static — баланс скорости и успешности
  • Сайты с агрессивным антиботом (Cloudflare Enterprise, Akamai): residential или ISP + fingerprint

Подробнее о различиях — в нашем сравнении datacenter и residential прокси.

Шаг 2: Настройка пула прокси

Базовая ротация через InfraProxy

import asyncio
import aiohttp
import random
from typing import Optional

class PriceMonitorProxy:
    """Менеджер прокси для мониторинга цен"""

    def __init__(self, proxy_host: str, proxy_port: int,
                 username: str, password: str,
                 protocol: str = "socks5"):
        self.base_url = f"{protocol}://{username}:{password}@{proxy_host}:{proxy_port}"
        self.stats = {"success": 0, "failed": 0, "blocked": 0}

    async def fetch_price(self, session: aiohttp.ClientSession,
                          url: str, retries: int = 3) -> Optional[str]:
        """Получить HTML страницы через прокси с ретраями"""
        for attempt in range(retries):
            try:
                async with session.get(
                    url,
                    proxy=self.base_url,
                    timeout=aiohttp.ClientTimeout(total=20),
                    headers=self._get_headers()
                ) as resp:
                    if resp.status == 200:
                        self.stats["success"] += 1
                        return await resp.text()
                    elif resp.status == 403:
                        self.stats["blocked"] += 1
                        await asyncio.sleep(2 ** attempt)
                    else:
                        self.stats["failed"] += 1
            except (aiohttp.ClientError, asyncio.TimeoutError):
                self.stats["failed"] += 1
                await asyncio.sleep(1)
        return None

    def _get_headers(self) -> dict:
        """Ротация User-Agent для естественного профиля"""
        agents = [
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) AppleWebKit/605.1.15 Safari/605.1.15",
            "Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0",
        ]
        return {
            "User-Agent": random.choice(agents),
            "Accept": "text/html,application/xhtml+xml",
            "Accept-Language": "ru-RU,ru;q=0.9,en;q=0.3",
            "Accept-Encoding": "gzip, deflate, br",
        }

    def get_stats(self) -> dict:
        total = self.stats["success"] + self.stats["failed"] + self.stats["blocked"]
        return {
            **self.stats,
            "total": total,
            "success_rate": f"{self.stats['success'] / max(total, 1) * 100:.1f}%"
        }

Sticky-сессии для многостраничных каталогов

Некоторые сайты показывают разные цены в зависимости от «сессии» пользователя. Если IP меняется между страницами каталога, вы получите несогласованные данные. Решение — sticky-сессии.

import hashlib

def get_sticky_proxy(base_proxy: str, site_domain: str,
                     duration_minutes: int = 10) -> str:
    """Генерация sticky-прокси для конкретного сайта.

    Один и тот же IP будет использоваться для всех запросов
    к данному домену в течение duration_minutes.
    """
    session_id = hashlib.md5(
        f"{site_domain}:{duration_minutes}".encode()
    ).hexdigest()[:12]

    # Формат InfraProxy: добавляем session-ID в URL
    # socks5://user-session-abc123:pass@dc.infraproxy.ru:1080
    parts = base_proxy.split("://")
    protocol = parts[0]
    auth_host = parts[1]
    user, rest = auth_host.split(":", 1)
    password, host_port = rest.rsplit("@", 1)

    return f"{protocol}://{user}-session-{session_id}:{password}@{host_port}"

# Все запросы к ozon.ru пойдут через один IP в течение 10 минут
sticky = get_sticky_proxy(
    "socks5://myuser:mypass@dc.infraproxy.ru:1080",
    "ozon.ru"
)

Подробнее о стратегиях ротации — в нашей статье «Стратегии ротации прокси».

Шаг 3: Geo-targeting для региональных цен

Многие сайты показывают разные цены в зависимости от региона. Это нормальное поведение: доставка в Москву и Владивосток стоит по-разному, региональные скидки и акции различаются.

Почему geo-targeting критичен

Без привязки к региону вы получите:

  • Среднюю цену, которая не соответствует ни одному реальному региону
  • Ошибки в ценовой стратегии — вы думаете, что конкурент дешевле, а на самом деле дешевле только в Москве
  • Упущенные региональные акции

Настройка в curl

#!/bin/bash
# Сбор цен с привязкой к региону

REGIONS=("moscow" "spb" "novosibirsk" "ekaterinburg")
PROXY_BASE="socks5://user:pass@dc.infraproxy.ru:1080"

for region in "${REGIONS[@]}"; do
    echo "=== Регион: $region ==="

    # Через InfraProxy: выбор гео через параметр в URL
    # Формат: user-country-RU-city-moscow:pass@host:port
    PROXY="socks5://user-country-RU-city-${region}:pass@dc.infraproxy.ru:1080"

    curl -s --proxy "$PROXY" \
        -H "Accept-Language: ru-RU,ru;q=0.9" \
        -o "prices_${region}.html" \
        "https://example-shop.ru/catalog/electronics"

    echo "Сохранено: prices_${region}.html"
    sleep 2  # пауза между регионами
done

Шаг 4: Rate-limiting и scheduling

Агрессивный краулинг — верный путь к блокировке. Правильный rate-limiting увеличивает success rate и уменьшает расход прокси.

Расчёт оптимальной скорости

| Тип сайта | Безопасный RPS | С прокси-ротацией | |-----------|--------------|-------------------| | Малый магазин | 1–2 req/s | 5–10 req/s | | Средний маркетплейс | 0.5–1 req/s | 10–30 req/s | | Крупный маркетплейс (антибот) | 0.2–0.5 req/s | 5–15 req/s | | API (с ключом) | По документации | По документации |

Правило: с пулом 100 000+ IP (InfraProxy) на каждый IP приходится 1 запрос в 10–60 секунд при параллельности 100–500. Этого достаточно, чтобы не вызывать подозрений.

Планировщик с адаптивным rate-limiting

import asyncio
import time
from collections import deque

class AdaptiveRateLimiter:
    """Адаптивный rate-limiter: замедляется при блокировках,
    ускоряется при стабильной работе"""

    def __init__(self, initial_rps: float = 5.0,
                 min_rps: float = 0.5, max_rps: float = 50.0):
        self.current_rps = initial_rps
        self.min_rps = min_rps
        self.max_rps = max_rps
        self.window = deque(maxlen=100)  # последние 100 запросов
        self._lock = asyncio.Lock()

    async def acquire(self):
        """Ожидание перед следующим запросом"""
        async with self._lock:
            delay = 1.0 / self.current_rps
            await asyncio.sleep(delay)

    def report_result(self, success: bool):
        """Сообщить результат запроса для адаптации"""
        self.window.append(success)

        if len(self.window) < 20:
            return

        success_rate = sum(self.window) / len(self.window)

        if success_rate > 0.95:
            # Всё хорошо — можно ускориться на 10%
            self.current_rps = min(
                self.current_rps * 1.1, self.max_rps
            )
        elif success_rate < 0.8:
            # Много блокировок — замедляемся вдвое
            self.current_rps = max(
                self.current_rps * 0.5, self.min_rps
            )

# Использование
limiter = AdaptiveRateLimiter(initial_rps=10)

async def monitored_fetch(proxy_manager, url):
    await limiter.acquire()
    result = await proxy_manager.fetch_price(session, url)
    limiter.report_result(result is not None)
    return result

Шаг 5: Обработка антибот-защит

Маркетплейсы используют несколько уровней защиты. Вот как справляться с каждым.

JavaScript-рендеринг

Некоторые цены загружаются через JavaScript. Обычный HTTP-запрос вернёт пустую страницу.

from playwright.async_api import async_playwright

async def fetch_with_js(url: str, proxy_url: str) -> str:
    """Получить цену с JS-рендерингом через Playwright + прокси"""
    async with async_playwright() as p:
        # Парсим прокси URL
        # socks5://user:pass@host:port
        parts = proxy_url.replace("socks5://", "").split("@")
        auth = parts[0].split(":")
        server_parts = parts[1].split(":")

        browser = await p.chromium.launch(
            proxy={
                "server": f"socks5://{parts[1]}",
                "username": auth[0],
                "password": auth[1]
            },
            headless=True
        )

        page = await browser.new_page()
        await page.goto(url, wait_until="networkidle")

        # Ждём появления элемента с ценой
        await page.wait_for_selector(
            "[data-price], .price, .product-price",
            timeout=10000
        )

        content = await page.content()
        await browser.close()
        return content

CAPTCHA

При появлении CAPTCHA — не пытайтесь решать её автоматически на каждый запрос. Лучше:

  1. Сменить IP (ротация прокси)
  2. Увеличить задержку между запросами
  3. Проверить fingerprint (User-Agent, заголовки)

Подробнее о методах обхода антибот-защит — в нашей статье «Антибот-системы 2026».

Шаг 6: Мониторинг здоровья прокси

Прокси-пул — живая система. IP блокируются, разблокируются, скорость меняется. Без мониторинга вы узнаете о проблемах, когда данные уже устарели.

Метрики для отслеживания

import json
import time
from datetime import datetime

class ProxyHealthMonitor:
    """Мониторинг состояния прокси в реальном времени"""

    def __init__(self):
        self.metrics = {
            "requests_total": 0,
            "requests_success": 0,
            "requests_blocked": 0,
            "requests_timeout": 0,
            "avg_latency_ms": 0,
            "unique_ips_used": set(),
            "started_at": datetime.now().isoformat()
        }
        self._latencies = []

    def record(self, status: str, latency_ms: float,
               proxy_ip: str = ""):
        self.metrics["requests_total"] += 1

        if status == "success":
            self.metrics["requests_success"] += 1
        elif status == "blocked":
            self.metrics["requests_blocked"] += 1
        elif status == "timeout":
            self.metrics["requests_timeout"] += 1

        self._latencies.append(latency_ms)
        if proxy_ip:
            self.metrics["unique_ips_used"].add(proxy_ip)

    def report(self) -> dict:
        total = self.metrics["requests_total"]
        if total == 0:
            return {"status": "no data"}

        return {
            "total_requests": total,
            "success_rate": f"{self.metrics['requests_success'] / total * 100:.1f}%",
            "block_rate": f"{self.metrics['requests_blocked'] / total * 100:.1f}%",
            "timeout_rate": f"{self.metrics['requests_timeout'] / total * 100:.1f}%",
            "avg_latency_ms": round(
                sum(self._latencies) / len(self._latencies)
            ),
            "p95_latency_ms": round(
                sorted(self._latencies)[int(len(self._latencies) * 0.95)]
            ),
            "unique_ips": len(self.metrics["unique_ips_used"]),
        }

# Алерт, если success rate падает ниже 90%
monitor = ProxyHealthMonitor()
# ... после серии запросов:
report = monitor.report()
if float(report["success_rate"].rstrip("%")) < 90:
    print(f"ALERT: Success rate {report['success_rate']} — проверьте прокси")

Полный пример: мониторинг каталога

Собираем всё вместе — рабочий скрипт мониторинга цен:

#!/bin/bash
# Быстрый мониторинг цен через curl + SOCKS5 прокси

PROXY="socks5://user:pass@dc.infraproxy.ru:1080"
URLS_FILE="target_urls.txt"
OUTPUT_DIR="prices/$(date +%Y-%m-%d)"
mkdir -p "$OUTPUT_DIR"

SUCCESS=0
FAILED=0

while IFS= read -r url; do
    FILENAME=$(echo "$url" | md5sum | cut -c1-12)

    HTTP_CODE=$(curl -s -o "$OUTPUT_DIR/${FILENAME}.html" \
        -w "%{http_code}" \
        --proxy "$PROXY" \
        --connect-timeout 10 \
        --max-time 20 \
        -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0" \
        -H "Accept-Language: ru-RU,ru;q=0.9" \
        "$url" 2>/dev/null)

    if [ "$HTTP_CODE" = "200" ]; then
        ((SUCCESS++))
    else
        ((FAILED++))
        echo "FAIL [$HTTP_CODE]: $url"
    fi

    # Случайная задержка 1-3 секунды
    sleep $(( RANDOM % 3 + 1 ))
done < "$URLS_FILE"

echo "Готово: $SUCCESS успешных, $FAILED неудачных из $(wc -l < $URLS_FILE) URL"

Чек-лист настройки

Перед запуском мониторинга убедитесь:

  • [ ] Выбран тип прокси под целевые сайты (DC/ISP/residential)
  • [ ] Настроена ротация IP с пулом не менее 10 000 адресов
  • [ ] Sticky-сессии включены для многостраничных каталогов
  • [ ] Geo-targeting настроен для региональных цен
  • [ ] Rate-limiting адаптивный (замедление при блокировках)
  • [ ] User-Agent и заголовки ротируются
  • [ ] Мониторинг success rate настроен + алерты
  • [ ] Ретраи с экспоненциальной задержкой

Итог

Настройка прокси для мониторинга цен — это не «вставить прокси-URL в requests.get()». Это инженерная задача с несколькими измерениями: тип прокси, ротация, geo-targeting, rate-limiting, обработка антиботов и мониторинг здоровья.

С правильной настройкой пул из 100 000+ datacenter IP обеспечивает стабильный мониторинг десятков тысяч товаров ежедневно при success rate > 95%.

Для задач ценовой разведки в B2B также рекомендуем прочитать наше руководство по конкурентной разведке — там описана общая стратегия за пределами технической настройки.


Попробуйте InfraProxy для мониторинга цен — 100 000+ IP, SOCKS5/HTTP, пропускная способность до 1 Gbps, тестовый доступ за 1 рабочий день. Оставить заявку →

Нужны надёжные прокси для вашего проекта?

InfraProxy предоставляет серверные и резидентные прокси для российского бизнеса. Договор, постоплата, техподдержка.