Comment surveiller automatiquement les prix des concurrents avec des proxies

Construire un système automatisé de surveillance des prix des concurrents à l'aide de procurations résidentielles. Guide d'architecture complet avec code Python et Node.js, stratégies de planification et configuration d'alerte.

Comment surveiller automatiquement les prix des concurrents avec des proxies

Pourquoi le contrôle automatisé des prix est important

Sur les marchés concurrentiels du commerce électronique, les prix changent constamment. Un concurrent pourrait baisser son prix de 5% à 2h du matin, et au moment où vous remarquez, vous avez déjà perdu un jour de vente. La surveillance automatisée des prix élimine ce point mort en suivant en permanence les prix des concurrents et en vous avertissant des changements en temps réel.

Que vous soyez un détaillant ajustant les prix pour rester compétitif, une marque de surveillance MAP (Minimum Advertised Price) conformité, ou un analyste de suivi des tendances du marché, un système de surveillance des prix bien construit paie pour lui-même rapidement. L'ingrédient clé qui rend tout fonctionne de façon fiable est une infrastructure proxy robuste — sans elle, vos demandes de surveillance sont bloquées en quelques heures. Pour un aperçu plus large de la collecte de données sur le commerce électronique, voir notre Guide de suppression des données sur le commerce électronique.

Architecture d'un système de surveillance des prix

Un système de surveillance des prix de qualité de production comprend quatre composants principaux : un gestionnaire d'URL, un moteur de démolition, un data store et une couche d'alerte.

Architecture d'un système de surveillance des prix
ComposanteResponsabilitéTechnologies
Gestionnaire d'URLConserve les URL cibles, les métadonnées de planification et la fréquence de suppressionPostgreSQL, Redis
Moteur de scrapageFetches pages à travers les proxies, extrait les prixPython/Node.js, ProxyHat, BelleSoupe/Cheerio
Magasin de donnéesHistorique des prix des magasins avec horodatagePostgreSQL, TimescaleDB, ClickHouse
Système d'alerteDétecte les changements, envoie des notificationsWebhooks, Slack, Email, SMS

Stratégie de planification

Tous les produits n'ont pas besoin de la même fréquence de surveillance. Les articles hautement prioritaires (votre top 100 UGS, produits concurrents directs) peuvent nécessiter des contrôles horaires, tandis que les articles à longue queue peuvent être vérifiés quotidiennement. Priorité fondée sur:

  • Volatilité des prix : Les produits qui changent de prix nécessitent souvent des contrôles plus fréquents.
  • Incidence sur les recettes : Vos best-sellers méritent une plus grande priorité de surveillance.
  • Densité compétitive: Les catégories avec de nombreux concurrents ont besoin d'une surveillance plus étroite.

Mise en place d'une rotation de proxy pour la surveillance

La surveillance des prix signifie frapper les mêmes URL à plusieurs reprises sur des jours, des semaines et des mois. Ce modèle est exactement ce que les systèmes anti-bot sont conçus pour détecter. Les procurations résidentielles avec rotation automatique sont essentielles.

Configuration ProxyHat

# Standard rotating proxy (new IP per request)
http://USERNAME:PASSWORD@gate.proxyhat.com:8080
# Geo-targeted for regional pricing (e.g., US prices)
http://USERNAME-country-US:PASSWORD@gate.proxyhat.com:8080
# Session-based for multi-page price checks
http://USERNAME-session-price001:PASSWORD@gate.proxyhat.com:8080

Pour la surveillance des prix, la rotation par demande fonctionne mieux parce que chaque contrôle des prix est une opération indépendante. Utilisation Proxies géo-cible lors du suivi des différences régionales de prix.

Mise en œuvre de Python

Voici un système complet de surveillance des prix construit avec Python, en utilisant Python SDK de ProxyHat.

Module de grattage des prix

import requests
from bs4 import BeautifulSoup
import json
import time
import random
from datetime import datetime
from dataclasses import dataclass, asdict
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
USER_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 10_15_7) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
]
@dataclass
class PriceResult:
    url: str
    price: float | None
    currency: str | None
    in_stock: bool
    scraped_at: str
    seller: str | None = None
def scrape_price(url: str, selectors: dict) -> PriceResult:
    """Scrape a product price from any e-commerce site."""
    headers = {
        "User-Agent": random.choice(USER_AGENTS),
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
    }
    proxies = {"http": PROXY_URL, "https": PROXY_URL}
    try:
        response = requests.get(url, headers=headers, proxies=proxies, timeout=30)
        response.raise_for_status()
    except requests.RequestException as e:
        return PriceResult(
            url=url, price=None, currency=None,
            in_stock=False, scraped_at=datetime.utcnow().isoformat()
        )
    soup = BeautifulSoup(response.text, "html.parser")
    price = extract_price(soup, selectors.get("price"))
    currency = selectors.get("currency", "USD")
    in_stock = check_stock(soup, selectors.get("stock"))
    return PriceResult(
        url=url,
        price=price,
        currency=currency,
        in_stock=in_stock,
        scraped_at=datetime.utcnow().isoformat(),
    )
def extract_price(soup, selector: str) -> float | None:
    """Extract and parse price from a CSS selector."""
    if not selector:
        return None
    el = soup.select_one(selector)
    if not el:
        return None
    text = el.get_text(strip=True)
    # Remove currency symbols, commas, spaces
    cleaned = "".join(c for c in text if c.isdigit() or c == ".")
    try:
        return float(cleaned)
    except ValueError:
        return None
def check_stock(soup, selector: str) -> bool:
    """Check if product is in stock."""
    if not selector:
        return True
    el = soup.select_one(selector)
    if not el:
        return False
    text = el.get_text(strip=True).lower()
    return "in stock" in text or "available" in text
# Site-specific selector configurations
SITE_SELECTORS = {
    "amazon.com": {
        "price": "span.a-price-whole",
        "stock": "#availability span",
        "currency": "USD",
    },
    "walmart.com": {
        "price": "[data-testid='price-wrap'] span.f2",
        "stock": "[data-testid='fulfillment-badge']",
        "currency": "USD",
    },
    "target.com": {
        "price": "[data-test='product-price']",
        "stock": "[data-test='fulfillmentSection']",
        "currency": "USD",
    },
}

Planificateur de surveillance

import schedule
import threading
from collections import defaultdict
class PriceMonitor:
    def __init__(self, db_connection):
        self.db = db_connection
        self.price_history = defaultdict(list)
    def add_product(self, url: str, site: str, check_interval_minutes: int = 60):
        """Register a product for monitoring."""
        selectors = SITE_SELECTORS.get(site, {})
        def check():
            result = scrape_price(url, selectors)
            self.price_history[url].append(result)
            self.store_result(result)
            self.check_alerts(url, result)
            time.sleep(random.uniform(1, 3))
        schedule.every(check_interval_minutes).minutes.do(check)
    def store_result(self, result: PriceResult):
        """Store price result in database."""
        # Insert into price_history table
        self.db.execute(
            "INSERT INTO price_history (url, price, currency, in_stock, scraped_at) "
            "VALUES (%s, %s, %s, %s, %s)",
            (result.url, result.price, result.currency,
             result.in_stock, result.scraped_at)
        )
    def check_alerts(self, url: str, result: PriceResult):
        """Check if price change triggers an alert."""
        history = self.price_history[url]
        if len(history) < 2:
            return
        prev = history[-2]
        curr = history[-1]
        if prev.price and curr.price:
            change_pct = ((curr.price - prev.price) / prev.price) * 100
            if abs(change_pct) >= 5:  # 5% threshold
                self.send_alert(url, prev.price, curr.price, change_pct)
        # Stock status change
        if prev.in_stock and not curr.in_stock:
            self.send_alert(url, msg="Product went out of stock")
        elif not prev.in_stock and curr.in_stock:
            self.send_alert(url, msg="Product back in stock")
    def send_alert(self, url, old_price=None, new_price=None,
                   change_pct=None, msg=None):
        """Send price change notification."""
        if msg:
            print(f"ALERT [{url}]: {msg}")
        else:
            direction = "dropped" if change_pct < 0 else "increased"
            print(f"ALERT [{url}]: Price {direction} {abs(change_pct):.1f}% "
                  f"(${old_price} -> ${new_price})")
    def run(self):
        """Start the monitoring loop."""
        while True:
            schedule.run_pending()
            time.sleep(1)
# Usage
if __name__ == "__main__":
    monitor = PriceMonitor(db_connection=None)  # Replace with actual DB
    # Monitor competitor products
    monitor.add_product(
        "https://www.amazon.com/dp/B0CHX3QBCH",
        site="amazon.com",
        check_interval_minutes=60,
    )
    monitor.add_product(
        "https://www.amazon.com/dp/B0D5BKRY4R",
        site="amazon.com",
        check_interval_minutes=30,  # Higher priority
    )
    monitor.run()

Mise en œuvre de Node.js

Pour les équipes utilisant Node.js, voici une configuration de surveillance équivalente utilisant Le nœud SDK de ProxyHat.

const axios = require("axios");
const cheerio = require("cheerio");
const { HttpsProxyAgent } = require("https-proxy-agent");
const cron = require("node-cron");
const PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080";
const agent = new HttpsProxyAgent(PROXY_URL);
const USER_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 10_15_7) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
];
async function scrapePrice(url, selectors) {
  try {
    const { data } = await axios.get(url, {
      httpsAgent: agent,
      headers: {
        "User-Agent": USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)],
        "Accept-Language": "en-US,en;q=0.9",
      },
      timeout: 30000,
    });
    const $ = cheerio.load(data);
    const priceText = $(selectors.price).first().text().trim();
    const price = parseFloat(priceText.replace(/[^0-9.]/g, "")) || null;
    return {
      url,
      price,
      currency: selectors.currency || "USD",
      inStock: $(selectors.stock).text().toLowerCase().includes("in stock"),
      scrapedAt: new Date().toISOString(),
    };
  } catch (err) {
    return { url, price: null, currency: null, inStock: false, scrapedAt: new Date().toISOString() };
  }
}
class PriceMonitor {
  constructor() {
    this.products = [];
    this.history = new Map();
  }
  addProduct(url, selectors, cronExpression = "0 * * * *") {
    this.products.push({ url, selectors, cronExpression });
    this.history.set(url, []);
    cron.schedule(cronExpression, async () => {
      const result = await scrapePrice(url, selectors);
      const prev = this.history.get(url);
      prev.push(result);
      if (prev.length >= 2) {
        const last = prev[prev.length - 2];
        if (last.price && result.price) {
          const changePct = ((result.price - last.price) / last.price) * 100;
          if (Math.abs(changePct) >= 5) {
            console.log(`ALERT [${url}]: Price changed ${changePct.toFixed(1)}%`);
          }
        }
      }
      console.log(`Checked ${url}: $${result.price} (${result.inStock ? "in stock" : "out of stock"})`);
    });
  }
}
// Usage
const monitor = new PriceMonitor();
monitor.addProduct(
  "https://www.amazon.com/dp/B0CHX3QBCH",
  { price: "span.a-price-whole", stock: "#availability span", currency: "USD" },
  "0 * * * *"  // Every hour
);
monitor.addProduct(
  "https://www.amazon.com/dp/B0D5BKRY4R",
  { price: "span.a-price-whole", stock: "#availability span", currency: "USD" },
  "*/30 * * * *"  // Every 30 minutes
);

Stockage et analyse des données

Les données sur les prix bruts deviennent précieuses lorsque vous pouvez analyser les tendances au fil du temps.

Schéma de base de données

CREATE TABLE monitored_products (
    id SERIAL PRIMARY KEY,
    url TEXT NOT NULL,
    site VARCHAR(100) NOT NULL,
    product_name VARCHAR(500),
    our_sku VARCHAR(100),
    check_interval_minutes INT DEFAULT 60,
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE price_history (
    id SERIAL PRIMARY KEY,
    product_id INT REFERENCES monitored_products(id),
    price DECIMAL(10, 2),
    currency VARCHAR(3) DEFAULT 'USD',
    in_stock BOOLEAN,
    scraped_at TIMESTAMPTZ NOT NULL,
    created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_price_history_product_time
    ON price_history (product_id, scraped_at DESC);

Demandes de renseignements sur la tendance des prix

-- Average daily price for the last 30 days
SELECT
    date_trunc('day', scraped_at) AS day,
    AVG(price) AS avg_price,
    MIN(price) AS min_price,
    MAX(price) AS max_price
FROM price_history
WHERE product_id = 1
  AND scraped_at >= now() - INTERVAL '30 days'
GROUP BY day
ORDER BY day;
-- Products with price drops > 10% in the last 24 hours
SELECT
    mp.product_name,
    mp.url,
    old_prices.avg_price AS price_yesterday,
    new_prices.avg_price AS price_today,
    ((new_prices.avg_price - old_prices.avg_price) / old_prices.avg_price * 100) AS change_pct
FROM monitored_products mp
JOIN LATERAL (
    SELECT AVG(price) AS avg_price
    FROM price_history
    WHERE product_id = mp.id
      AND scraped_at BETWEEN now() - INTERVAL '48 hours' AND now() - INTERVAL '24 hours'
) old_prices ON true
JOIN LATERAL (
    SELECT AVG(price) AS avg_price
    FROM price_history
    WHERE product_id = mp.id
      AND scraped_at >= now() - INTERVAL '24 hours'
) new_prices ON true
WHERE ((new_prices.avg_price - old_prices.avg_price) / old_prices.avg_price * 100) < -10;

Alertes et notifications

Les alertes automatisées vous assurent de réagir rapidement aux changements de prix. Les voies de notification communes comprennent:

  • Slack webhooks : Idéal pour une visibilité à l'échelle de l'équipe. Envoyer des messages structurés avec des détails de changement de prix.
  • Digests de courrier électronique: Résumés quotidiens ou horaires de tous les changements de prix au-dessus de votre seuil.
  • Callbacks Webhook : Déclenchez votre moteur de remorquage ou toute autre automatisation lorsque les prix changent.
  • Tableau de bord: Visualisation en temps réel des tendances des prix pour tous les produits contrôlés.

Seuils d'alerte

Configurer différents seuils d'alerte pour différents scénarios:

Seuils d'alerte
ScénarioSeuilDécision
Baisse des prix des concurrents > 5%5%Notification de slack
Baisse des prix des concurrents > 15%15%E-mail à l'équipe de prix + auto-reprix
Produit épuiséVariation des stocksAlerte d'opportunité
Prix en dessous du MAPValeur inférieure à la valeur MAPAlerte de conformité

Pratiques exemplaires proxy pour la surveillance

La surveillance continue crée des défis uniques pour la gestion des procurations par rapport à l'élimination ponctuelle.

  • Répartir les demandes dans le temps : Au lieu de vérifier tous les 10 000 produits à minuit, étalez les contrôles sur tout l'intervalle. Cela crée un modèle de demande stable et à profil bas.
  • Utiliser des procurations résidentielles : Proxies résidentielles sont essentiels pour la surveillance à long terme car les mêmes IP de datacenter qui frappent quotidiennement les mêmes sites seront interdits.
  • Synchroniser la géolocalisation : Pour surveiller les prix régionaux, utilisez des procurations de la région cible. Un contrôle IP américain des prix allemands verra les mauvaises données ou sera redirigé.
  • Gérez les échecs gracieusement : Si une demande échoue, attendez et réessayez avec un retour exponentiel plutôt que de demander immédiatement. Surveillez votre taux de réussite et réduisez la convergence si elle baisse.
  • Cache et doublon: Si un prix n'a pas changé, ne stockez pas un enregistrement en double. Cela maintient votre base de données maigre et rend l'analyse plus rapide.
À emporter : La surveillance des prix est un marathon, pas un sprint. Concevez votre système pour des motifs de demande stables et durables plutôt que de déchirer.

Élargir votre système de surveillance

À mesure que votre catalogue de produits grandit, l'échelle devient critique. Voici les modèles qui fonctionnent :

  • Groupe de travailleurs: Utilisez plusieurs travailleurs tirant d'une file d'attente d'emploi (Redis, RabbitMQ). Chaque travailleur a ses propres connexions par procuration et fonctionne de manière indépendante.
  • Dossiers prioritaires : Les produits de haute valeur sont vérifiés d'abord et plus fréquemment. Les articles peu prioritaires remplissent la capacité restante.
  • Horaire adaptatif : Si le prix d'un produit n'a pas changé en 7 jours, réduire la fréquence de vérification automatiquement. Si elle a changé deux fois aujourd'hui, augmentez la fréquence.
  • Taux limite par site: Respecter les limites de tarifs de chaque site cible. Les magasins Amazon, Walmart et niche ont toutes des tolérances différentes.

Pour en savoir plus sur les opérations de grattage, consultez notre guide les meilleurs proxies pour le grattage de toile en 2026 et explorer Les plans de prix de ProxyHat pour la surveillance en volume élevé.

A emporter des clés

  • La surveillance automatisée des prix nécessite une architecture robuste : gestionnaire d'URL, moteur de grattage, stockage de données et système d'alerte.
  • Les procurations résidentielles avec rotation par demande sont essentielles pour une surveillance soutenue sans blocs.
  • Des contrôles de calendrier fondés sur la priorité — tous les produits n'ont pas besoin d'une surveillance horaire.
  • Stocker l'historique des prix dans un schéma adapté aux séries chronologiques pour l'analyse des tendances.
  • Configurer des seuils d'alerte échelonnés pour équilibrer la réactivité avec la réduction du bruit.
  • Distribuer les demandes de façon uniforme au fil du temps pour un modèle de grattage durable et à faible profil.

Prêt à construire votre système de surveillance des prix? Commencez par Proxies résidentielles de ProxyHat et lisez notre Guide sur la démolition du commerce électronique pour la stratégie complète. Pour plus de détails techniques, voir nos guides sur utilisant des proxies dans Python et utilisant des proxies dans Node.js.

Prêt à commencer ?

Accédez à plus de 50M d'IPs résidentielles dans plus de 148 pays avec filtrage IA.

Voir les tarifsProxies résidentiels
← Retour au Blog