Trường Hợp Sử Dụng

Giám sát hàng tồn kho bán lẻ bằng cách xử lý CAPTCHA

Các nền tảng thương mại điện tử bảo vệ các trang sản phẩm và dữ liệu hàng tồn kho bằng CAPTCHA để ngăn chặn việc mua hàng bằng bot và đối thủ cạnh tranh. CaptchaAI cho phép giám sát kho hàng tự động, theo dõi giá cả và cảnh báo tình trạng còn hàng.


CAPTCHA trên nền tảng thương mại điện tử

Nền tảng Loại CAPTCHA Trình kích hoạt dữ liệu
Amazon reCAPTCHA v2 Truy cập khối lượng lớn Giá, hàng tồn kho, đánh giá
Walmart reCAPTCHA v3 + Cloudflare Phát hiện bot Hàng tồn kho, giá cả
Mua tốt nhất reCAPTCHA v2 Kiểm tra thêm vào giỏ hàng Kho hàng, giá cả
Mục tiêu Cloudflare Turnstile Truy cập tự động sẵn có
Cửa hàng Shopify Cloudflare Turnstile Giới hạn tỷ lệ Dữ liệu sản phẩm
eBay reCAPTCHA v2 Truy cập tìm kiếm + danh sách Danh sách, giá cả

Giám sát sản phẩm

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)

Quét kho toàn danh mục

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

So sánh giá của đối thủ cạnh tranh

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

Lịch giám sát

Loại sản phẩm Kiểm tra tần suất Loại proxy
Điện tử Cứ sau 30 phút Khu dân cư xoay vòng
Cửa hàng tạp hóa Cứ sau 4 giờ Khu dân cư xoay vòng
thời trang Cứ sau 2 giờ Khu dân cư
Phiên bản giới hạn Cứ sau 1 phút đa dạng nguồn yêu cầu
Hàng gia dụng Cứ sau 6 giờ Khu dân cư
Hàng hóa Cứ sau 12 giờ Trung tâm dữ liệu (thường là đủ)

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
CAPTCHA trên mỗi trang sản phẩm IP bị gắn cờ hoặc vượt quá tốc độ Tăng độ trễ, xoay proxy
Giá bị loại bỏ không chính xác Định giá động được hiển thị bởi JS Thay vào đó hãy sử dụng Selenium/Puppeteer
Trang "kiểm tra robot" Phát hiện bot kiểu Amazon Sử dụng tiêu đề thực tế + đa dạng nguồn yêu cầu
Chứng khoán hiển thị "không có sẵn" Tính sẵn có bị giới hạn về mặt địa lý So khớp proxy với khu vực mục tiêu
Thiếu dữ liệu sản phẩm Cấu trúc trang đã thay đổi Cập nhật bộ chọn CSS

Câu hỏi thường gặp

Tôi có thể kiểm tra trang sản phẩm với tần suất như thế nào?

Cứ sau 30-60 phút cho mỗi sản phẩm là an toàn đối với hầu hết các nhà bán lẻ. Giám sát tần số cao hơn (1-5 phút) hoạt động nhưng yêu cầu nhiều proxy hơn và kích hoạt CAPTCHA.

Tôi nên sử dụng phiên xoay hay phiên cố định?

Xoay vòng - mỗi trang sản phẩm là một yêu cầu độc lập. Phiên cố định chỉ cần thiết nếu việc kiểm tra chi tiết sản phẩm yêu cầu điều hướng.

Tôi có thể theo dõi hàng ngàn sản phẩm không?

Vâng. Trải rộng các yêu cầu trên nhiều IP proxy và kiểm tra xen kẽ. Với 1.000 sản phẩm có độ trễ 3 giây, một chu kỳ đầy đủ sẽ mất khoảng 50 phút.


Hướng dẫn liên quan

  • Ủy quyền dân cư luân phiên
  • Phiên cố định và phiên luân phiên
  • Giám sát chuỗi cung ứng

Theo dõi hàng tồn kho bán lẻ trong thời gian thực —lấy khóa CaptchaAI của bạnđể xử lý CAPTCHA tự động.

Os comentários estão desativados para este artigo.