×

api 数据挖掘

告别人工盯品!借助 Open Claw 搭建电商商品自动化监控与数据分析系统(完整可运行源码)

admin admin 发表于2026-08-24 17:46:33 浏览2 评论0

抢沙发发表评论

前言

做电商运营或者竞品调研,相信很多人都有这样的痛点:想要持续跟踪多款商品的价格变动、库存、规格信息,每天手动打开网页复制粘贴数据到 Excel 表格。不仅重复劳动耗时间,大促节点的临时降价、库存清仓往往转瞬即逝,人工很难第一时间捕捉变化。

如果自己手写页面解析脚本,又会遇到页面动态渲染、网页改版导致解析失效、访问频次受限等一系列棘手问题,调试维护成本居高不下。

最近在项目实践中使用了 Open Claw 工具,它可以直接输出结构化的商品信息,不用再折腾网页源码解析,我们可以把精力全部放在业务逻辑上,快速搭建一套本地商品监控与数据分析程序。

本篇教程会完整演示整套流程:包含本地数据持久化存储、价格库存异动提醒、历史时序数据分析、批量商品巡检,所有代码可以直接复制运行,Windows、Mac、Linux 都支持,部署到服务器就可以实现 7×24 小时不间断监控。

整体实现思路

  1. 获取商品结构化原始信息:商品标题、当前售价、原始标价、库存、多规格信息、店铺名称等完整内容;

  2. 使用 SQLite 本地数据库保存每一次采集记录,沉淀历史时序数据;

  3. 设置定时巡检任务,对比前后两次数据,识别降价、库存变动,输出告警提示;

  4. 读取本地历史记录做数据分析,统计历史最高、最低、平均售价,分析价格波动幅度;

  5. 支持批量加入多款商品,扩展可对接钉钉、企业微信实现消息推送。

环境准备

Python 版本建议 3.7 以上,安装需要的依赖包

pip install requests apscheduler
  • requests:负责网络交互

  • apscheduler:实现定时巡检任务

  • sqlite3:Python 内置轻量数据库,无需额外安装,用来存储监控历史记录

提前准备好 Open Claw 后台生成的两组身份凭证,用于程序访问。

完整代码实现

新建文件 goods_monitor.py,复制下面全部代码,修改配置区域的凭证、监控商品编号、告警阈值就可以直接运行。

import requests
import json
import sqlite3
import time
from datetime import datetime
from apscheduler.schedulers.background import BackgroundScheduler

# ===================== 【配置区域,请自行修改】 =====================
CLAW_KEY = "填入你的凭证key"
CLAW_SECRET = "填入你的凭证secret"
# 需要监控的商品编号,可以填入多个实现批量监控
MONITOR_GOODS = ["10335871600", "10057467958584"]
POLL_INTERVAL = 300  # 巡检间隔,单位秒,普通商品建议300秒,爆款可缩短
PRICE_ALERT_RATIO = 0.15  # 降价超过15%就触发告警
DB_FILE = "goods_monitor.db"
# =================================================================

def init_db():
    """初始化本地数据库,创建数据表"""
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS goods_record (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        goods_id TEXT NOT NULL,
        title TEXT,
        price REAL,
        original_price REAL,
        stock INTEGER,
        shop_name TEXT,
        record_time TIMESTAMP
    )
    ''')
    conn.commit()
    conn.close()


def get_goods_info(goods_id: str):
    """
    获取商品结构化数据
    :param goods_id: 商品数字编号
    :return: 字典格式商品信息,失败返回None
    """
    params = {
        "key": CLAW_KEY,
        "secret": CLAW_SECRET,
        "num_iid": goods_id,
        "cache": "no",
        "result_type": "json"
    }
    retry = 3
    while retry > 0:
        try:
            resp = requests.get(
                "https://api-gw.onebound.cn/jd/item_get_pro",
                params=params,
                timeout=15
            )
            data = resp.json()
            if data.get("error_code") != "0000":
                print(f"获取商品{goods_id}异常:{data.get('reason','未知错误')}")
                return None
            item_data = data.get("item", {})
            result = {
                "goods_id": goods_id,
                "title": item_data.get("title", ""),
                "price": float(item_data.get("price", 0)) if item_data.get("price") else 0,
                "original_price": float(item_data.get("orginal_price", 0)) if item_data.get("orginal_price") else 0,
                "stock": int(item_data.get("num", 0)) if item_data.get("num") else 0,
                "shop_name": item_data.get("seller_info", {}).get("shop_name", "")
            }
            return result
        except Exception as e:
            retry -= 1
            print(f"网络异常,剩余重试次数 {retry}, 错误:{str(e)}")
            time.sleep(2)
    return None


def save_to_db(goods_data):
    """将采集到的数据存入本地数据库"""
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('''
    INSERT INTO goods_record
    (goods_id, title, price, original_price, stock, shop_name, record_time)
    VALUES (?, ?, ?, ?, ?, ?, ?)
    ''', (
        goods_data["goods_id"],
        goods_data["title"],
        goods_data["price"],
        goods_data["original_price"],
        goods_data["stock"],
        goods_data["shop_name"],
        datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    ))
    conn.commit()
    conn.close()


def get_last_record(goods_id):
    """读取该商品上一次记录,用于对比变动"""
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('''
    SELECT price, stock FROM goods_record WHERE goods_id=?
    ORDER BY record_time DESC LIMIT 1
    ''', (goods_id,))
    row = cursor.fetchone()
    conn.close()
    if row:
        return {"price": row[0], "stock": row[1]}
    return None


def monitor_task():
    """定时执行的监控任务"""
    print(f"\n==== 巡检开始 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ====")
    for gid in MONITOR_GOODS:
        info = get_goods_info(gid)
        if not info:
            continue
        save_to_db(info)
        last = get_last_record(gid)
        print(f"商品【{info['title']}】 当前价格:{info['price']} 库存:{info['stock']}")
        if last:
            # 降价告警判断
            if last["price"] > 0 and info["price"] < last["price"]:
                drop_rate = (last["price"] - info["price"]) / last["price"]
                if drop_rate >= PRICE_ALERT_RATIO:
                    print(f"【⚠️价格告警】商品{gid}发生大幅降价!上次:{last['price']} 本次:{info['price']} 降幅{drop_rate:.1%}")
            # 库存变动提醒
            if info["stock"] != last["stock"]:
                print(f"【ℹ库存变动】商品{gid}库存变更,上一次:{last['stock']},当前:{info['stock']}")
        time.sleep(1)


def analysis_goods(goods_id):
    """针对单个商品做历史数据分析"""
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('''
    SELECT price, record_time FROM goods_record WHERE goods_id=? ORDER BY record_time
    ''', (goods_id,))
    rows = cursor.fetchall()
    conn.close()
    if not rows:
        print("暂无历史数据,请先运行监控采集数据!")
        return
    price_list = [r[0] for r in rows]
    max_p = max(price_list)
    min_p = min(price_list)
    avg_p = sum(price_list)/len(price_list)
    print("\n========商品历史数据分析========")
    print(f"历史最高售价:{max_p:.2f}")
    print(f"历史最低售价:{min_p:.2f}")
    print(f"历史平均售价:{avg_p:.2f}")
    print(f"数据记录总条数:{len(price_list)}")


if __name__ == "__main__":
    init_db()
    scheduler = BackgroundScheduler()
    scheduler.add_job(monitor_task, "interval", seconds=POLL_INTERVAL)
    scheduler.start()
    print("监控程序已经启动,按 Ctrl+C 终止程序")
    try:
        while True:
            cmd = input("\n输入指令:\n1:执行一次巡检  2:分析商品历史  q:退出\n>")
            if cmd == "1":
                monitor_task()
            elif cmd == "2":
                gid = input("输入要分析的商品编号:")
                analysis_goods(gid)
            elif cmd.lower() == "q":
                break
    except KeyboardInterrupt:
        pass
    finally:
        scheduler.shutdown()
        print("程序已退出")

程序使用说明

  1. 修改代码顶部配置,填入自己的两组凭证,把需要跟踪的商品编号写进MONITOR_GOODS列表;

  2. 直接运行脚本 python goods_monitor.py,程序自动初始化数据库,开启后台定时巡检;

  3. 控制台交互指令:

    • 输入1立刻手动执行一轮巡检,不用等待定时周期;

    • 输入2,填入商品编号,程序会统计该商品全部历史记录,输出最高价、最低价、平均价格;

    • 输入q关闭程序。

采集的全部历史会保存在goods_monitor.db文件,你可以使用数据库工具打开,导出为 Excel 表格做进一步处理。

功能拓展方向

  1. 消息推送:出现降价、库存变动告警的时候,可以增加钉钉机器人、企业微信 webhook,把告警信息推送到工作群,不用守着控制台;

  2. 多规格 SKU 分析:源码中只提取了基础价格,还可以读取多规格的数据,跟踪不同规格的价格、库存变化;

  3. 数据可视化:结合 matplotlib 绘制价格变化曲线图,直观观察一段时间的价格走势;

  4. 导出报表:定时把每日数据导出 csv 文件,方便周报复盘;

  5. 部署服务器:Linux 服务器后台运行,实现全天候无人值守监控。

实际业务场景

  • 竞品跟踪:电商运营持续盯对手商品调价、库存情况,把握促销时机;

  • 选品比价:跟踪多款目标商品,等待合适价位再入手;

  • 店铺自检:跟踪自家店铺多款商品,监控异常改价、库存异常;

  • 大促备战:618、双 11 大促期间高频巡检,捕捉短期促销活动。

写在最后

这套方案避开了复杂的页面解析工作,把重点放在业务逻辑开发,新手也可以快速落地。实际使用的时候注意控制巡检间隔,不要设置过于频繁,避免超出额度。如果后续需要更大规模的批量任务,可以在这个基础上做任务队列优化。


少长咸集

群贤毕至

访客