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.
| Composante | Responsabilité | Technologies |
|---|---|---|
| Gestionnaire d'URL | Conserve les URL cibles, les métadonnées de planification et la fréquence de suppression | PostgreSQL, Redis |
| Moteur de scrapage | Fetches pages à travers les proxies, extrait les prix | Python/Node.js, ProxyHat, BelleSoupe/Cheerio |
| Magasin de données | Historique des prix des magasins avec horodatage | PostgreSQL, TimescaleDB, ClickHouse |
| Système d'alerte | Détecte les changements, envoie des notifications | Webhooks, 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:8080Pour 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:
| Scénario | Seuil | Dé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 stocks | Alerte d'opportunité |
| Prix en dessous du MAP | Valeur inférieure à la valeur MAP | Alerte 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.






