Cas d'Usage

Surveillance des stocks de détail avec gestion CAPTCHA

Les plateformes de commerce électronique protègent les pages de produits et les données d'inventaire avec des CAPTCHA pour empêcher le scraping des concurrents et l'achat de robots. CaptchaAI permet une surveillance automatisée des stocks, un suivi des prix et des alertes de disponibilité.


CAPTCHA sur les plateformes de commerce électronique

Plateforme Type de CAPTCHA Déclencheur Données
Amazone reCAPTCHA v2 Accès à gros volumes Prix, stock, avis
Walmart reCAPTCHA v3 + Cloudflare Détection de robots Inventaire, prix
Meilleur achat reCAPTCHA v2 Vérification de l'ajout au panier Stock, prix
Cible Cloudflare Turnstile Accès automatisé Disponibilité
Boutiques Shopify Cloudflare Turnstile Limitation du débit Données produit
eBay reCAPTCHA v2 Recherche + accès aux listings Annonces, prix

Moniteur de produit

import requests
import time
import re
import json
from datetime import datetime
from bs4 import BeautifulSoup

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"


def solve_captcha(method, sitekey, pageurl, **kwargs):
    data = {
        "key": CAPTCHAAI_KEY, "method": method,
        "googlekey": sitekey, "pageurl": pageurl, "json": 1,
    }
    data.update(kwargs)
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
    task_id = resp.json()["request"]
    for _ in range(60):
        time.sleep(5)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        r = result.json()
        if r["request"] != "CAPCHA_NOT_READY":
            return r["request"]
    raise TimeoutError("Timeout")


class RetailMonitor:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {"http": proxy, "https": proxy}
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
            "Accept": "text/html,application/xhtml+xml,*/*;q=0.8",
            "Accept-Language": "en-US,en;q=0.9",
        })

    def check_product(self, url):
        """Check single product's price and availability."""
        resp = self.session.get(url, timeout=30)

        # Handle CAPTCHA
        if self._has_captcha(resp.text):
            resp = self._solve_and_retry(resp.text, url)

        soup = BeautifulSoup(resp.text, "html.parser")
        return {
            "url": url,
            "title": self._text(soup, "h1, .product-title, #productTitle"),
            "price": self._text(soup, ".price, .a-price .a-offscreen, .prod-price"),
            "availability": self._text(soup, "#availability, .stock-status, .fulfillment"),
            "in_stock": self._check_stock(soup),
            "timestamp": datetime.now().isoformat(),
        }

    def monitor_products(self, product_urls, interval_sec=1800):
        """Continuously monitor products for changes."""
        history = {}

        while True:
            for url in product_urls:
                try:
                    current = self.check_product(url)

                    # Check for changes
                    prev = history.get(url)
                    if prev:
                        changes = self._detect_changes(prev, current)
                        if changes:
                            self._alert(current["title"], changes)

                    history[url] = current
                    time.sleep(3)

                except Exception as e:
                    print(f"Error checking {url}: {e}")

            print(f"Cycle complete: {len(product_urls)} products checked")
            time.sleep(interval_sec)

    def track_prices(self, product_urls, output_file="prices.json"):
        """Single price check across all products."""
        results = []
        for url in product_urls:
            try:
                data = self.check_product(url)
                results.append(data)
                time.sleep(3)
            except Exception as e:
                results.append({"url": url, "error": str(e)})

        with open(output_file, "w") as f:
            json.dump(results, f, indent=2)
        print(f"Tracked {len(results)} products → {output_file}")
        return results

    def _has_captcha(self, html):
        return any(tag in html.lower() for tag in [
            'data-sitekey', 'g-recaptcha', 'cf-turnstile', 'captcha',
        ])

    def _solve_and_retry(self, html, url):
        match = re.search(r'data-sitekey="([^"]+)"', html)
        if not match:
            return self.session.get(url)

        sitekey = match.group(1)
        if 'cf-turnstile' in html:
            token = solve_captcha("turnstile", sitekey, url)
            return self.session.post(url, data={"cf-turnstile-response": token})
        else:
            token = solve_captcha("userrecaptcha", sitekey, url)
            return self.session.post(url, data={"g-recaptcha-response": token})

    def _text(self, soup, selector):
        el = soup.select_one(selector)
        return el.get_text(strip=True) if el else ""

    def _check_stock(self, soup):
        stock_el = soup.select_one("#availability, .stock-status")
        if stock_el:
            text = stock_el.get_text(strip=True).lower()
            return "in stock" in text or "available" in text
        return None

    def _detect_changes(self, prev, current):
        changes = []
        if prev["price"] != current["price"]:
            changes.append(f"Price: {prev['price']} → {current['price']}")
        if prev["in_stock"] != current["in_stock"]:
            status = "In Stock" if current["in_stock"] else "Out of Stock"
            changes.append(f"Stock: → {status}")
        return changes

    def _alert(self, title, changes):
        print(f"ALERT [{title}]: {', '.join(changes)}")


# Usage
monitor = RetailMonitor(
    proxy="http://user:pass@residential.proxy.com:5000"
)

products = [
    "https://store.example.com/product/abc123",
    "https://store.example.com/product/def456",
    "https://store.example.com/product/ghi789",
]

# One-time price check
results = monitor.track_prices(products)

# Or continuous monitoring (every 30 min)
# monitor.monitor_products(products, interval_sec=1800)

Analyse des stocks à l'échelle de la catégorie

def scan_category(base_url, category, max_pages=20):
    """Scan an entire product category for stock status."""
    monitor = RetailMonitor(
        proxy="http://user:pass@residential.proxy.com:5000"
    )

    all_products = []
    for page in range(1, max_pages + 1):
        url = f"{base_url}/{category}?page={page}"
        resp = monitor.session.get(url, timeout=30)

        if monitor._has_captcha(resp.text):
            resp = monitor._solve_and_retry(resp.text, url)

        soup = BeautifulSoup(resp.text, "html.parser")
        items = soup.select(".product-card, .s-result-item")

        if not items:
            break

        for item in items:
            all_products.append({
                "name": monitor._text(item, ".product-name, .a-text-normal"),
                "price": monitor._text(item, ".price, .a-price"),
                "stock": monitor._text(item, ".stock, .a-color-success"),
                "url": item.select_one("a")["href"] if item.select_one("a") else "",
            })

        time.sleep(3)

    return all_products

Comparaison des prix des concurrents

def compare_product_across_stores(product_name, stores):
    """Compare prices across retailers for the same product."""
    results = []

    for store in stores:
        monitor = RetailMonitor(proxy=store.get("proxy"))
        search_url = f"{store['base_url']}/search?q={product_name}"

        try:
            resp = monitor.session.get(search_url, timeout=30)
            if monitor._has_captcha(resp.text):
                resp = monitor._solve_and_retry(resp.text, search_url)

            soup = BeautifulSoup(resp.text, "html.parser")
            first_result = soup.select_one(".product-card, .s-result-item")

            if first_result:
                results.append({
                    "store": store["name"],
                    "price": monitor._text(first_result, ".price"),
                    "in_stock": "in stock" in first_result.get_text().lower(),
                })
        except Exception as e:
            results.append({"store": store["name"], "error": str(e)})

        time.sleep(5)

    results.sort(key=lambda x: x.get("price", "zzzz"))
    return results

Calendrier de surveillance

Type de produit Vérifier la fréquence Type de mandataire
Électronique Toutes les 30 minutes Résidentiel tournant
Épicerie Toutes les 4 heures Résidentiel tournant
Mode Toutes les 2 heures Résidentiel
Sorties limitées Toutes les 1 minutes Mandataire mobile
Articles pour la maison Toutes les 6 heures Résidentiel
Biens de base Toutes les 12 heures Datacenter (souvent suffisant)

Dépannage

Problème Parce que Corriger
CAPTCHA sur chaque page produit IP signalée ou débit dépassé Augmenter le délai, faire pivoter les proxys
Prix incorrect gratté Tarification dynamique rendue par JS Utilisez plutôt Selenium/Puppeteer
Page "Contrôle du robot" Détection de robots à la manière d'Amazon Utilisez des en-têtes réalistes + un proxy résidentiel
Le stock indique "indisponible" Disponibilité géo-restreinte Faire correspondre le proxy à la région cible
Données produit manquantes La structure des pages a été modifiée Mettre à jour les sélecteurs CSS

FAQ

À quelle fréquence puis-je consulter les pages produits ?

Toutes les 30 à 60 minutes par produit sont sans danger pour la plupart des détaillants. La surveillance à plus haute fréquence (1 à 5 minutes) fonctionne mais nécessite davantage de proxys et déclenche des CAPTCHA.

Dois-je utiliser des sessions rotatives ou collantes ?

Rotation : chaque page de produit est une demande indépendante. Les sessions persistantes ne sont nécessaires que si la vérification des détails du produit nécessite une navigation.

Puis-je surveiller des milliers de produits ?

Oui. Répartissez les requêtes sur plusieurs adresses IP proxy et échelonnez les contrôles. Pour 1 000 produits avec des délais de 3 secondes, un cycle complet prend environ 50 minutes.


Guides connexes

  • Rotation des procurations résidentielles
  • Sessions collantes ou rotatives
  • Surveillance de la chaîne d'approvisionnement

Suivez l'inventaire de vente au détail en temps réel -récupérez votre clé CaptchaAIpour la gestion automatisée des CAPTCHA.

Les commentaires sont désactivés pour cet article.