价格跟踪

使用抓取 API 构建实时 Amazon 价格监控系统

使用 Pangolin 电商 API 创建自动化 Amazon 价格跟踪系统的分步指南

2025年12月12日 22 分钟阅读 Pangol Info Team

在快节奏的 Amazon 电商生态系统中,价格每天波动数百万次。对于认真的卖家来说,“一劳永逸”的定价策略是通往默默无闻的单程票。为了保持竞争力,维持 Buy Box(黄金购物车),并保护您的利润率,您需要一个强大的实时价格监控系统。本指南提供了使用 Python 和 Pangolin Scraping API 从头开始构建您自己的自动化价格跟踪器的完整技术演示。

与昂贵且不灵活的现成工具不同,自定义解决方案让您可以完全控制数据粒度、更新频率以及与后端系统的集成。无论您是保护品牌价值的自有品牌卖家,还是争夺 Buy Box 的经销商,我们今天构建的系统都将成为您定价情报运营的支柱。

为什么实时价格监控不可妥协

动态定价是 Amazon 的命脉。静态价格标签的日子早已一去不复返,取而代之的是根据需求、竞争和库存水平调整价格的复杂算法。如果您不实时监控这些变化,那您就是在盲目飞行。

Buy Box 之战: Amazon Buy Box(“立即购买”按钮)推动了超过 82% 的销售额。Amazon 的算法根据价格竞争力严重倾向于授予 Buy Box。仅仅几美分的差异就能决定您是赢得还是失去销售。自动化监控确保您确切地知道何时失去 Buy Box 以及原因,从而允许立即采取纠正措施。

竞争对手策略解码: 您的竞争对手正在不断测试策略。他们在晚上降低价格吗?他们在周末进行限时抢购吗?通过收集连续的价格数据点,您可以逆向工程他们的策略。例如,您可能会发现某个主要竞争对手在每个星期二系统性地将价格降低 5%——这些知识使您可以先发制人地调整您的策略。

利润最大化 vs. 收入: 并不总是关于最低价格。有时,竞争对手会缺货或提高价格。在这些时刻,智能系统会检测到提高您的价格同时仍保持 Buy Box 的机会,从而显着提高您的利润率。我们看到卖家仅仅通过捕捉这些手动检查会错过的“高价”窗口,就将净利润提高了 15-20%。

数据洞察

根据最近的市场分析,利用基于实时数据的自动重新定价策略的卖家,在头三个月内的平均销售增长比使用手动或静态定价的卖家高出 42%。

价格监控基础

在编写代码之前,我们必须了解构成 Amazon “价格”的数据点。它不仅仅是一个数字。要构建有效的跟踪器,您需要为每个快照捕获以下属性:

  • 当前 Buy Box 价格: 客户点击“立即购买”时支付的价格。这是您最关键的指标。
  • 标价 (List Price): 划线价格,对于计算折扣很重要。
  • 运费: 通常是隐藏的,但是总落地价格的一部分。
  • 卖家 ID: 谁赢得了 Buy Box?是 Amazon (Sold by Amazon) 还是第三方?
  • 可用性: 产品有货吗?延期交货?
  • 报价数量: 此列表中还有多少其他卖家?

跟踪策略与频率

通过多频繁地检查价格?过度检查浪费 API 额度;检查不足会错过关键变动。

高周转产品

每 15-30 分钟检查一次。这些商品(BSR 前 1%)有持续运行的激进重新定价器。

长尾产品

每 6-12 小时检查一次。价格较具粘性,变化不那么频繁。

构建核心跟踪系统

现在,让我们构建引擎。我们将使用 Python 和 requests 库与 Pangolin Scrape API 进行交互,并使用 sqlite3 作为轻量级无服务器数据库来存储我们的价格历史记录。

下面的 PriceTracker 类处理三个主要功能:

  1. 数据库初始化: 设置表以存储价格历史记录。
  2. 数据抓取: 向 API 发送请求以获取最新产品数据。
  3. 数据持久化: 将解析后的数据保存到我们的数据库中。

import requests
import sqlite3
import json
from datetime import datetime
from typing import Dict, Optional

class PriceTracker:
    """
    通过 Pangolin API 跟踪 Amazon 产品价格的核心引擎。
    处理数据提取和持久化到 SQLite。
    """
    
    def __init__(self, api_key: str, db_path: str = "price_history.db"):
        self.api_key = api_key
        self.api_endpoint = "https://scrapeapi.pangolinfo.com/api/v1/scrape"
        self.db_path = db_path
        self._init_db()

    def _init_db(self):
        """初始化 SQLite 数据库模式。"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS prices (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                asin TEXT NOT NULL,
                timestamp DATETIME NOT NULL,
                price REAL,
                currency TEXT,
                seller_name TEXT,
                is_amazon_sold BOOLEAN,
                availability TEXT,
                rating REAL,
                reviews_count INTEGER
            )
        ''')
        # 创建索引以加快后续查询
        cursor.execute('CREATE INDEX IF NOT EXISTS idx_asin ON prices(asin)')
        cursor.execute('CREATE INDEX IF NOT EXISTS idx_time ON prices(timestamp)')
        conn.commit()
        conn.close()

    def get_product_data(self, asin: str) -> Optional[Dict]:
        """
        通过 API 从 Amazon 获取实时产品数据。
        
        参数:
            asin: Amazon 标准识别号
            
        返回:
            包含已解析产品详情的字典,如果失败则返回 None。
        """
        payload = {
            "url": f"https://www.amazon.com/dp/{asin}",
            "parserName": "amzDetail",  # 使用专用详情页解析器
            "format": "json",
            "bizContext": {
                "zipcode": "10001"  # 检查纽约交付的价格
            }
        }
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }

        try:
            response = requests.post(self.api_endpoint, json=payload, headers=headers)
            
            if response.status_code == 200:
                result = response.json()
                # 浏览 API 响应结构
                if result.get("code") == 0 and result.get("data"):
                    return result["data"]["json"][0]["data"]
            
            print(f"Failed to fetch data for {asin}: {response.text}")
            return None
            
        except Exception as e:
            print(f"Error requesting {asin}: {str(e)}")
            return None

    def store_price_point(self, asin: str, data: Dict):
        """将单个价格快照保存到数据库。"""
        if not data:
            return

        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 安全提取数字价格
        raw_price = data.get("price", 0)
        
        cursor.execute('''
            INSERT INTO prices (
                asin, timestamp, price, currency, seller_name, 
                is_amazon_sold, availability, rating, reviews_count
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        ''', (
            asin,
            datetime.now().isoformat(),
            raw_price,
            data.get("currency", "USD"),
            data.get("seller_name", "Unknown"),
            data.get("seller_name", "").lower() == "amazon.com",
            data.get("availability", "Unknown"),
            data.get("star", 0.0),
            data.get("rating_count", 0)
        ))
        
        conn.commit()
        conn.close()
        print(f"✅ Stored price for {asin}: ${raw_price}")

    def run_check(self, asins: list):
        """批量处理 ASIN 列表。"""
        print(f"Starting price check for {len(asins)} products...")
        for asin in asins:
            data = self.get_product_data(asin)
            if data:
                self.store_price_point(asin, data)
        print("Batch check complete.")

# 使用示例
if __name__ == "__main__":
    tracker = PriceTracker(api_key="YOUR_API_KEY_HERE")
    my_products = ["B08N5WRWNW", "B09G9F5T3R"] # 示例 ASIN
    tracker.run_check(my_products)

这个 PriceTracker 之所以强大,是因为它处理了网络数据的可变性。它不仅存储价格,还存储上下文——谁在销售(Amazon 自营?)以及可用性。如果竞争对手的价格降至 0.01 美元,但他们“当前不可用”,您的系统不应惊慌。上下文是关键。

高级价格分析

没有解读的原始数据是无用的。20 美元的价格是好是坏?这取决于历史记录。 PriceAnalyzer 类查询我们的 SQLite 数据库以查找趋势、波动性和竞争定位。

import pandas as pd
import sqlite3
import numpy as np

class PriceAnalyzer:
    """
    分析历史价格数据以发现趋势并计算统计数据。
    使用 pandas 进行高效的数据操作。
    """
    
    def __init__(self, db_path: str = "price_history.db"):
        self.db_path = db_path

    def get_price_history_df(self, asin: str, days: int = 30) -> pd.DataFrame:
        """将 ASIN 的价格历史加载到 pandas DataFrame 中。"""
        conn = sqlite3.connect(self.db_path)
        query = f"""
            SELECT timestamp, price, seller_name, is_amazon_sold 
            FROM prices 
            WHERE asin = '{asin}' 
            AND timestamp >= datetime('now', '-{days} days')
            ORDER BY timestamp ASC
        """
        df = pd.read_sql_query(query, conn)
        conn.close()
        
        if not df.empty:
            df['timestamp'] = pd.to_datetime(df['timestamp'])
            df.set_index('timestamp', inplace=True)
        return df

    def analyze_volatility(self, asin: str) -> dict:
        """
        计算价格波动率指标。
        高标准差意味着价格频繁波动。
        """
        df = self.get_price_history_df(asin)
        if df.empty:
            return {}

        current_price = df['price'].iloc[-1]
        mean_price = df['price'].mean()
        min_price = df['price'].min()
        max_price = df['price'].max()
        std_dev = df['price'].std()
        
        # 计算价格动量 (简单移动平均线交叉)
        short_ma = df['price'].rolling(window=3).mean().iloc[-1]
        long_ma = df['price'].rolling(window=10).mean().iloc[-1]
        trend = "UP" if short_ma > long_ma else "DOWN"

        return {
            "asin": asin,
            "current_price": current_price,
            "mean_price": round(mean_price, 2),
            "volatility_index": round(std_dev, 2),
            "price_range": (min_price, max_price),
            "trend": trend,
            "is_amazon_dominating": self._check_amazon_dominance(df)
        }

    def _check_amazon_dominance(self, df: pd.DataFrame) -> bool:
        """检查 Amazon 是否占 Buy Box 历史记录的 50% 以上。"""
        amazon_wins = df[df['is_amazon_sold'] == 1].shape[0]
        total_checks = df.shape[0]
        return (amazon_wins / total_checks) > 0.5 if total_checks > 0 else False

    def compare_competitors(self, my_asin: str, competitor_asins: list) -> dict:
        """比较我的产品价格与一篮子竞争对手的价格。"""
        my_stats = self.analyze_volatility(my_asin)
        if not my_stats:
            return {"error": "No data for my ASIN"}

        my_price = my_stats['current_price']
        competitor_prices = []

        for comp_asin in competitor_asins:
            comp_stats = self.analyze_volatility(comp_asin)
            if comp_stats:
                competitor_prices.append(comp_stats['current_price'])

        if not competitor_prices:
            return {"position": "UNKNOWN"}
            
        # ... logic to determine position
        return {"position": "ANALYZED"}

掌控您的定价

通过实施此系统,您不仅仅是在被动地做出反应,而是在基于情报进行预测和操作。

  • 注册 Pangolin:在 tool.pangolinfo.com 免费获取您的 API Key
  • GitHub 仓库:查看完整源代码

准备自动化您的定价策略了吗?

几分钟内构建您的自定义价格跟踪器。停止手动检查,开始自动化利润增长。

免费获取 API Key