Come monitorare i prezzi dei concorrenti automaticamente con i proxy

Costruire un sistema di monitoraggio dei prezzi competitivo automatizzato utilizzando proxy residenziali. Guida di architettura completa con il codice Python e Node.js, le strategie di pianificazione e la configurazione di avviso.

Come monitorare i prezzi dei concorrenti automaticamente con i proxy

Perché automatizzati di monitoraggio dei prezzi

Nei mercati e-commerce competitivi, i prezzi cambiano costantemente. Un concorrente potrebbe cadere il loro prezzo del 5% alle 2 AM, e al momento si nota, hai già perso una giornata di vendite. Il monitoraggio automatizzato dei prezzi elimina questo punto cieco monitorando continuamente i prezzi dei concorrenti e avvisando i cambiamenti in tempo reale.

Che tu sia un rivenditore che regola i prezzi per rimanere competitivo, un marchio di monitoraggio MAP (Minimum Advertised Price) conformità, o un analista che traccia le tendenze del mercato, un sistema di monitoraggio dei prezzi ben costruito paga per sé rapidamente. L'ingrediente chiave che lo rende tutto funziona in modo affidabile è una robusta infrastruttura proxy — senza di essa, le vostre richieste di monitoraggio vengono bloccate entro ore. Per uno sguardo più ampio alla raccolta di dati e-commerce, vedere il nostro e-commerce dati scraping guida.

Architettura di un sistema di monitoraggio dei prezzi

Un sistema di monitoraggio dei prezzi di produzione ha quattro componenti principali: un gestore di URL, un motore di demolizione, un data store e uno strato di allerta.

ComponentiResponsabilitàTecnologie
Gestione dell'URLMemorizza gli URL di destinazione, la pianificazione dei metadati e la frequenza di scrapingPostgreSQL, Redis
Motore di scorrimentoFetches pagine attraverso i proxy, estrae i prezziPython/Node.js, ProxyHat, BeautifulSoup/Cheerio
Data StoreNegozi cronologia dei prezzi con timestampPostgreSQL, TimescaleDB, ClickHouse
Sistema di allarmeRileva le modifiche, invia le notificheWebhooks, Slack, Email, SMS

Strategia di programmazione

Non tutti i prodotti hanno bisogno della stessa frequenza di monitoraggio. Gli articoli ad alta priorità (tutti i migliori 100 SKU, i prodotti diretti concorrenti) potrebbero avere bisogno di controlli orari, mentre gli articoli a coda lunga possono essere controllati ogni giorno. Prioritare basato su:

  • volatilità dei prezzi: I prodotti che cambiano i prezzi hanno spesso bisogno di controlli più frequenti.
  • Impatto delle entrate: I vostri bestseller meritano una maggiore priorità di monitoraggio.
  • Densità competitiva: Categorie con molti concorrenti hanno bisogno di un monitoraggio più stretto.

Impostazione della rotazione del proxy per il monitoraggio

Il monitoraggio dei prezzi significa colpire ripetutamente gli stessi URL nei giorni, settimane e mesi. Questo modello è esattamente ciò che i sistemi anti-bot sono progettati per rilevare. I proxy residenziali con rotazione automatica sono essenziali.

Configurazione 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

Per il monitoraggio dei prezzi, la rotazione per richiesta funziona meglio perché ogni controllo dei prezzi è un'operazione indipendente. Uso Prossi geo-targeti quando si controllano le differenze regionali dei prezzi.

Attuazione di Python

Ecco un sistema completo di monitoraggio dei prezzi costruito con Python, utilizzando ProxyHat Python SDK.

Modulo del grattacielo di prezzo

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",
    },
}

Programma di monitoraggio

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()

Node.js Attuazione

Per le squadre che utilizzano Node.js, ecco una configurazione di monitoraggio equivalente utilizzando SDK del nodo di 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
);

Memorizzazione e analisi dei dati

I dati dei prezzi grezzi diventano preziosi quando è possibile analizzare le tendenze nel tempo.

Schema del database

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);

Quesiti di tendenza dei prezzi

-- 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;

Alerting e Notifiche

Gli avvisi automatizzati garantiscono di reagire rapidamente ai cambiamenti dei prezzi. I canali comuni di notifica includono:

  • Slack webhooks: Ideale per la visibilità in tutto il team. Invia messaggi strutturati con dettagli cambio prezzo.
  • Email digests: Riepilogo giornaliero o oraria di tutti i cambiamenti di prezzo sopra la soglia.
  • Webhook: Trigger il motore di ripetizione o altra automazione quando i prezzi cambiano.
  • Dashboard: Visualizzazione in tempo reale delle tendenze dei prezzi in tutti i prodotti monitorati.

Alert Thresholds

Configurare diverse soglie di allarme per diversi scenari:

ScenarioSogliaAzione
Riduzione del prezzo competitivo > 5%5%Slack notifica
Riduzione del prezzo competitivo > 15%15%Email a pricing team + auto-riprezzo
Prodotto esauritoVariazione delle scorteAvviso di opportunità
Prezzo sotto MAPSotto il valore MAPAvviso di conformità

Migliori pratiche proxy per il monitoraggio

Il monitoraggio continuo crea sfide uniche per la gestione dei proxy rispetto alla raschiatura di una volta.

  • Distribuire richieste nel tempo: Invece di controllare tutti i 10.000 prodotti a mezzanotte, diffondere i controlli attraverso l'intero intervallo. Questo crea un modello di richiesta stabile e a basso profilo.
  • Utilizzare i proxy residenziali: Processi residenziali sono essenziali per il monitoraggio a lungo termine perché gli stessi IP del datacenter che colpiscono gli stessi siti al giorno saranno vietati.
  • Corrispondenza geolocalizzazione: Durante il monitoraggio dei prezzi regionali, utilizzare i proxy dalla regione di destinazione. Un controllo IP degli Stati Uniti i prezzi tedeschi vedranno i dati errati o verranno reindirizzati.
  • Maniglia guasti con grazia: Se una richiesta fallisce, aspetta e riprova con backoff esponenziale piuttosto che immediatamente ri-richiesta. Monitorare il tasso di successo e ridurre la convalutazione se scende.
  • Cache e deduplica: Se un prezzo non è cambiato, non memorizzare un record duplicato. Questo mantiene il vostro database magra e rende l'analisi più veloce.
Asporto chiave: il monitoraggio dei prezzi è una maratona, non uno sprint. Progettare il sistema per modelli di richiesta costanti e sostenibili piuttosto che scoppiare rottami.

Scalare il sistema di monitoraggio

Man mano che il catalogo dei prodotti cresce, la scala diventa critica. Ecco i modelli che funzionano:

  • Vasca da lavoro: Utilizzare più lavoratori tirando da una coda di lavoro (Redis, RabbitMQ). Ogni lavoratore ha le proprie connessioni proxy e opera in modo indipendente.
  • Le code prioritarie: I prodotti ad alto valore vengono controllati prima e più frequentemente. Gli elementi a bassa priorità riempiono la capacità rimanente.
  • Programmazione adattiva: Se il prezzo di un prodotto non è cambiato in 7 giorni, ridurre automaticamente la frequenza di controllo. Se è cambiato due volte oggi, aumentare la frequenza.
  • Tasso di limitazione per sito: Rispetta i limiti di tasso di ogni sito di destinazione. Amazon, Walmart e nicchia negozi hanno tutte tolleranze diverse.

Per ulteriori informazioni sulle operazioni di raschiamento, controllare la nostra guida su migliori proxy per la raschiatura web nel 2026 ed esplorare Piani di prezzi di ProxyHat per il monitoraggio ad alto volume.

Asporto chiave

  • Il monitoraggio automatico dei prezzi richiede un'architettura robusta: gestore URL, motore di demolizione, data store e sistema di allarme.
  • I proxy residenziali con rotazione per-richiesta sono essenziali per un monitoraggio continuo senza blocchi.
  • Controlli di programma basati sulla priorità — non tutti i prodotti hanno bisogno di monitoraggio oraria.
  • Conservare la cronologia dei prezzi in uno schema a misura di tempo per l'analisi della tendenza.
  • Configurare le soglie di allarme tiered per bilanciare la reattività con la riduzione del rumore.
  • Distribuire richieste in modo uniforme nel tempo per un modello di raschiatura sostenibile e a basso profilo.

Pronto a costruire il sistema di monitoraggio dei prezzi? Inizia con I proxy residenziali di ProxyHat e leggere il nostro e-commerce scraping guida per la strategia completa. Per informazioni sull'implementazione tecnica, consulta le nostre guide usando i proxy in Python e usando i proxy in Node.js.

Pronto per iniziare?

Accedi a oltre 50M di IP residenziali in oltre 148 paesi con filtraggio AI.

Vedi i prezziProxy residenziali
← Torna al Blog