×

api 数据挖掘

告别手工盯品!Open Claw 快速搭建电商商品监控与数据分析系统(完整可运行源码)

admin admin 发表于2026-08-19 18:01:22 浏览8 评论0

抢沙发发表评论

适用场景:竞品盯价、自有商品库存巡检、大促价格异动捕捉、历史价格统计分析;Python 实现,开箱即用,适合电商运营、数据分析、后端开发同学参考。

前言

做电商或者做比价分析,很多人都有这样的痛点: 需要持续关注几十款商品的价格、库存、规格变动。如果靠人工打开网页,复制粘贴到 Excel,不仅耗费大量时间,还很容易错过大促的降价、库存告急等关键信号。

自己写页面解析脚本,又会遇到平台反访问限制、页面改版解析失效、动态数据渲染等一堆麻烦,调试成本很高。

最近体验了 Open Claw 这套工具,能够稳定拿到商品完整结构化信息,不需要处理网页解析,我们可以专注业务逻辑,快速实现一套监控 + 数据分析的本地程序。本文完整带你从零实现,包含数据持久化、异动告警、历史数据统计分析全部代码。

说明:本文仅采集电商公开展示的商品公开信息,请勿高频频繁轮询,遵守平台相关规范。

整体实现思路

  1. 获取商品结构化原始数据(标题、售价、原价、库存、规格 SKU、店铺信息等)

  2. SQLite 本地存储每一次采集记录,留存历史时序数据

  3. 定时轮询对比新旧数据,识别价格下跌、库存变化,控制台输出告警提示(可扩展钉钉 / 企业微信推送)

  4. 读取本地历史库,做数据分析:历史最高价、最低价、平均售价、价格波动情况

  5. 支持批量监控多款商品

环境准备

需要安装依赖库

pip install requests apscheduler
  • requests:网络请求

  • apscheduler:定时任务调度

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

拿到 Open Claw 的两组凭证,填入代码配置区即可。

完整代码实现

import requests
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_DROP_ALERT_RATIO = 0.15  # 降价幅度超过15%触发告警
# =====================================================================

# 初始化数据库,创建数据表
def init_db():
    conn = sqlite3.connect("goods_monitor.db")
    cur = conn.cursor()
    cur.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,
        crawl_time TEXT
    )
    ''')
    conn.commit()
    conn.close()

# 获取商品详情原始结构化数据
def get_goods_data(goods_id: str):
    params = {
        "key": CLAW_KEY,
        "secret": CLAW_SECRET,
        "num_iid": goods_id,
        "result_type": "json",
        "cache": "yes"
    }
    try:
        resp = requests.get("https://api-gw.onebound.cn/jd/item_get_pro", params=params, timeout=15)
        res_json = resp.json()
        if res_json.get("error_code") != "0000":
            print(f"商品 {goods_id} 获取数据异常:{res_json.get('reason','未知错误')}")
            return None
        item = res_json.get("item")
        if not item:
            print(f"商品 {goods_id} 返回数据为空")
            return None
        data = {
            "goods_id": goods_id,
            "title": item.get("title", ""),
            "price": float(item.get("price", 0)) if item.get("price") else 0,
            "original_price": float(item.get("orginal_price",0)) if item.get("orginal_price") else 0,
            "stock": int(item.get("num", 0)) if item.get("num") else 0,
            "shop_name": item.get("seller_info", {}).get("shop_name", ""),
            "crawl_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        return data
    except Exception as e:
        print(f"网络请求异常 goods_id:{goods_id}, 异常信息:{str(e)}")
        return None

# 将本次采集结果存入数据库
def save_to_db(data):
    conn = sqlite3.connect("goods_monitor.db")
    cur = conn.cursor()
    cur.execute('''
    INSERT INTO goods_record(goods_id,title,price,original_price,stock,shop_name,crawl_time)
    VALUES (?,?,?,?,?,?,?)
    ''',(
        data["goods_id"],
        data["title"],
        data["price"],
        data["original_price"],
        data["stock"],
        data["shop_name"],
        data["crawl_time"]
    ))
    conn.commit()
    conn.close()

# 获取这个商品上一次采集的记录,用于对比异动
def get_last_record(goods_id):
    conn = sqlite3.connect("goods_monitor.db")
    cur = conn.cursor()
    cur.execute('''
    SELECT price,stock FROM goods_record WHERE goods_id = ? ORDER BY id DESC LIMIT 1
    ''',(goods_id,))
    row = cur.fetchone()
    conn.close()
    if row:
        return {"last_price": row[0], "last_stock": row[1]}
    return None

# 监控单款商品,检测价格、库存变动告警
def monitor_one_goods(goods_id):
    print(f"\n===== 开始采集商品:{goods_id} =====")
    curr_data = get_goods_data(goods_id)
    if curr_data is None:
        return
    save_to_db(curr_data)
    last_info = get_last_record(goods_id)
    print(f"【{curr_data['title']}】 当前售价:{curr_data['price']},库存:{curr_data['stock']}")
    # 第一次采集,没有历史记录,只存储不告警
    if last_info is None:
        print("首次采集,无历史对比数据")
        return
    last_price = last_info["last_price"]
    last_stock = last_info["last_stock"]
    # 价格下降告警
    if curr_data["price"] < last_price:
        drop_rate = (last_price - curr_data["price"]) / last_price
        if drop_rate >= PRICE_DROP_ALERT_RATIO:
            print(f"🔔【价格大幅下降告警】原价格{last_price} → 当前{curr_data['price']},降幅{round(drop_rate*100,2)}%")
    # 库存清零告警
    if curr_data["stock"] == 0 and last_stock > 0:
        print(f"⚠️【库存告急告警】商品已经售罄!上一轮库存:{last_stock}")
    # 补货提醒
    if curr_data["stock"] > 0 and last_stock == 0:
        print(f"✅【补货通知】商品恢复库存,当前库存 {curr_data['stock']}")

# 历史数据分析:读取数据库,输出商品价格统计
def analysis_goods_history(goods_id):
    """输出商品历史价格统计:最高、最低、平均价格"""
    conn = sqlite3.connect("goods_monitor.db")
    cur = conn.cursor()
    cur.execute('''
    SELECT price,crawl_time FROM goods_record WHERE goods_id = ? ORDER BY crawl_time ASC
    ''', (goods_id,))
    rows = cur.fetchall()
    conn.close()
    if len(rows) < 2:
        print(f"\n商品{goods_id}历史数据不足,暂时无法分析,多跑几次采集后再来")
        return
    price_list = [r[0] for r in rows]
    max_p = max(price_list)
    min_p = min(price_list)
    avg_p = round(sum(price_list)/len(price_list),2)
    first_time = rows[0][1]
    last_time = rows[-1][1]
    print("\n====================历史数据分析报告====================")
    print(f"商品编号:{goods_id}")
    print(f"统计时间区间:{first_time} ~ {last_time}")
    print(f"历史最高售价:{max_p}")
    print(f"历史最低售价:{min_p}")
    print(f"历史平均售价:{avg_p}")
    print("========================================================")

# 定时任务执行入口
def monitor_task():
    for gid in MONITOR_GOODS:
        monitor_one_goods(gid)
    # 可选:每轮监控完成后,对第一个商品输出统计报告
    analysis_goods_history(MONITOR_GOODS[0])

if __name__ == "__main__":
    init_db()
    scheduler = BackgroundScheduler()
    scheduler.add_job(monitor_task, "interval", seconds=POLL_INTERVAL)
    print(f"监控程序已启动,监控商品列表:{MONITOR_GOODS},轮询间隔 {POLL_INTERVAL} 秒")
    print("Ctrl+C 停止程序\n")
    scheduler.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        scheduler.shutdown()
        print("\n程序正常退出")

代码功能拆解

1、数据库初始化 init_db

创建本地 sqlite 文件,存储每一次采集的:商品 ID、标题、价格、原价、库存、店铺、采集时间。程序重启不会丢失历史记录。

2、get_goods_data 获取结构化商品信息

调用工具拿到完整商品信息,做简单字段提取,把我们关心的价格、库存、店铺信息整理出来。如果返回异常会打印日志。

3、monitor_one_goods 单商品监控逻辑

  1. 获取最新数据存入数据库

  2. 查询上一轮采集记录,做对比

  3. 识别降价、售罄、补货事件,控制台输出告警提示。

拓展思路:你可以把告警部分改成调用钉钉、企业微信 webhook,实现消息推送。

4、analysis_goods_history 历史数据分析

读取本地存储的时序数据,计算最高价、最低价、平均价格,帮我们判断当前价位是否适合入手,也可以用来分析竞品大促的定价规律。

5、定时调度

使用 APScheduler 后台定时任务,每隔设定的时间自动跑一轮全部商品监控。

使用注意事项

  1. 轮询间隔不要设置过小,建议最少 300 秒(5 分钟)以上,避免频繁请求。

  2. 凭证需要自行替换,没有凭证无法运行。

  3. 价格字段存在一定波动偏差,适合做趋势监控,不要当做 100% 精确交易价格。

  4. 程序运行后会生成 goods_monitor.db 文件,这就是你的本地数据库,不要随意删除。

  5. 如果需要导出 Excel,可以基于读取数据库后的结果,用 pandas 输出 csv 文件。

进阶拓展方向

  1. 消息推送:告警逻辑对接钉钉机器人、企业微信,价格变动直接手机收到通知。

  2. SKU 维度监控:代码中可以扩展解析不同规格的价格,监控不同颜色尺码的价格变化。

  3. 可视化图表:把历史数据读出来,用 matplotlib 绘制价格趋势折线图。

  4. Web 后台:结合 Flask/FastAPI,做简单网页,查看监控列表、历史图表。

  5. 部署到服务器:把脚本部署在云服务器,7×24 小时不间断监控。

小结

借助 Open Claw,我们不需要耗费大量精力去处理网页解析、反访问限制,直接拿到规整的商品数据,把精力聚焦业务逻辑。几十行代码,就实现了一套完整的商品监控 + 数据分析工具,对于电商运营、个人比价都很实用。


少长咸集

群贤毕至

访客