京东商品价格波动怎么监控?Python+接口方案完整源码

简介: 本文提供一套开箱即用的京东商品价格监控方案:基于Python标准库,调用OneBound接口定时抓取价格,SQLite本地存档,支持降价/涨价/到目标价/下架等多规则告警,并推送至企微/钉钉/飞书群;附带离线价格曲线生成与工程级冷却去重,60行精简版即可跑通闭环。(239字)

京东商品价格波动怎么监控?Python+接口方案完整源码

盯竞品价格这件事,手动刷新撑不过半小时:你不知道它什么时候降价、降了多少、是不是历史新低,等你刷到的时候,库存可能已经没了。

这篇文章给一套能直接跑的方案:接口定时取价 → SQLite 存快照 → 规则判断波动 → 群机器人推送告警,外加一条离线价格曲线。全部只用 Python 标准库,pip install 一步省掉。


一、方案总览

┌────────────┐   轮询(30min)   ┌──────────────┐   规则判断   ┌────────────┐
│ 京东价格接口 │ ──────────────→ │ SQLite 快照库 │ ──────────→ │ 告警推送     │
│ item_price │                 │ snapshots    │             │ 企微/钉钉/飞书│
└────────────┘                 └──────────────┘             └────────────┘
        ↑                             │
   item_get 补详情                本地统计 + HTML 价格曲线
   item_history_price 查历史低价

核心思路只有四步:定时取价 → 存快照 → 和上一条/历史对比 → 触发规则就推送。难点全在细节里:取价用哪个接口、-1 怎么处理、怎么避免同一件事反复骚扰群。

三个接口怎么分工

接口 地址 返回什么 监控里的角色
jd.item_price https://api-gw.onebound.cn/jd/item_price/ 只有价格 + 标题,price = -1 表示下架/不存在 主力轮询,轻量省配额
jd.item_get https://api-gw.onebound.cn/jd/item_get/ 全量详情:标题/图/SKU/店铺/销量 低频补全,新商品入库时取一次
jd.item_history_price https://api-gw.onebound.cn/jd/item_history_price/ lower_price/lower_date/current_price + 每日价格数组 冷启动建基线,判断"真降"还是"回到原价"

item_price 是监控场景的最优解:单次调用只回三个字段,同样的套餐额度能盯更多商品;商品上下架、改价它都第一时间反映。

公共参数三个接口一致:key、secret(必须拼在 URL query 上)、cache(监控必须传 no,原因见后文坑 3)、result_type=json。item_get 额外支持 domain_type=jd(自营)/ gongye(工业)/ yiyao(医药)/ hk(全球购)。


二、精简版源码:60 行跑通闭环

先给一个最小可用版:轮询 + 快照 + 三条告警规则 + 群机器人推送。复制改两个 SKU 就能跑。

# -*- coding: utf-8 -*-
"""京东价格监控精简版:item_price 轮询 + SQLite 快照 + 阈值告警"""
import json
import os
import sqlite3
import time
import urllib.parse
import urllib.request
from datetime import datetime

API = "https://api-gw.onebound.cn/jd/item_price/"
KEY, SECRET = os.getenv("ONEBOUND_KEY", ""), os.getenv("ONEBOUND_SECRET", "")
WEBHOOK = os.getenv("PRICE_WEBHOOK", "")          # 企业微信/钉钉群机器人地址,可留空

WATCH = {
                                             # 监控清单:sku -> (名称, 目标价)
    "100012345678": ("竞品A·蓝牙耳机", 199),
    "100045678901": ("竞品B·机械键盘", None),
}
DROP_PCT = 5                                       # 单次波动告警阈值 %
INTERVAL = 1800                                    # 轮询间隔秒

conn = sqlite3.connect("price.db")
conn.execute("CREATE TABLE IF NOT EXISTS snap(sku TEXT, ts TEXT, price REAL, UNIQUE(sku, ts))")


def fetch(sku):
    """取当前价。接口约定:price = -1 表示商品下架或不存在。"""
    url = f"{API}?{urllib.parse.urlencode({'key': KEY, 'secret': SECRET, 'num_iid': sku, 'cache': 'no'})}"
    with urllib.request.urlopen(url, timeout=15) as r:
        item = json.loads(r.read().decode("utf-8")).get("item") or {
   }
    return float(item.get("price") or 0)


def notify(text):
    print(text)
    if WEBHOOK:                                    # 企业微信/钉钉机器人都是这个格式
        req = urllib.request.Request(WEBHOOK, data=json.dumps(
            {
   "msgtype": "text", "text": {
   "content": text}}).encode(),
            headers={
   "Content-Type": "application/json"})
        urllib.request.urlopen(req, timeout=8).read()


def check(sku, name, target):
    price = fetch(sku)
    now = datetime.now().strftime("%Y-%m-%d %H:%M")
    prev = conn.execute("SELECT price FROM snap WHERE sku=? ORDER BY ts DESC LIMIT 1",
                        (sku,)).fetchone()
    conn.execute("INSERT OR REPLACE INTO snap VALUES(?,?,?)", (sku, now, price))
    conn.commit()
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
    if price == -1:
        notify(f"[下架] {name}({sku}) 接口返回 -1,商品下架或不存在")
        return
    if prev:
        pct = (price - prev[0]) / prev[0] * 100
        if abs(pct) >= DROP_PCT:
            word = "降价" if pct < 0 else "涨价"
            notify(f"[{word} {abs(pct):.1f}%] {name}({sku}) ¥{prev[0]:.2f} → ¥{price:.2f}")
    if target and price <= target:
        notify(f"[到目标价] {name}({sku}) 现价 ¥{price:.2f} ≤ 目标 ¥{target}")


if __name__ == "__main__":
    while True:
        for sku, (name, target) in WATCH.items():
            try:
                check(sku, name, target)
            except Exception as e:
                print(f"[{sku}] 取价失败:{e}")
            time.sleep(1)                          # 商品间隔,避免瞬间并发超限
        time.sleep(INTERVAL)

实测触发效果(用模拟价格序列验证):

[降价 6.8%] 竞品A·蓝牙耳机(100012345678) ¥220.00 → ¥205.00
[降价 7.8%] 竞品A·蓝牙耳机(100012345678) ¥205.00 → ¥189.00
[到目标价] 竞品A·蓝牙耳机(100012345678) 现价 ¥189.00 ≤ 目标 ¥199
[下架] 竞品A·蓝牙耳机(100012345678) 接口返回 -1,商品下架或不存在

注意两个写法细节:

  1. 先查上一条,再落库。顺序反了的话,同一分钟内重跑会把自己当成"上一条",涨跌幅永远算不出来。
  2. price = -1 是合法状态,不是错误。接口文档明确:当值为 -1 时商品 ID 视为下架或不存在。把它当 0 处理,你的报表里会出现"暴跌 100%"。

三、工程版:多商品 + 告警冷却 + 价格曲线

精简版跑几天你就会遇到两个新问题:商品一多告警刷屏;想看趋势只能查库。文末附的 jd_price_monitor.py 在精简版之上补齐了这些:

取数层  item_price(轻量轮询) / item_get --full(详情)   指数退避重试
判断层  四条规则:降价≥5% / 涨价≥5% / 到目标价 / 历史新低 / 下架
        同规则 6 小时冷却,降价已报则不再重复报历史新低
存储层  SQLite 三张表:watchlist / snapshots / alert_log
报表层  report 命令(最低/最高/涨跌/采样数)+ chart 命令生成离线 HTML 曲线
命令 作用
add <sku或链接> --name --target 加入监控(直接贴 item.jd.com 链接也行)
once 立刻抓一轮,判断告警
run --interval 1800 常驻循环,每 30 分钟一轮
report --days 30 命令行输出区间最低/最高/涨跌幅
chart --days 30 --out price.html 生成离线价格曲线(自带 SVG,无依赖)
seed <sku> --days 30 造模拟历史数据,没有 key 也能先跑通全流程

用 seed 造 30 天数据后,chart 的输出长这样(演示数据):

京东价格监控演示

曲线自动标注区间最高/最低点和目标价虚线,发群里比截图数据库直观得多。


四、六个真实会踩的坑

1. price 字段"会对不上"是文档明说的

item_get 的返回说明里有一句原注:当前商品 id 价格【价格会对不上】。多 SKU 商品的主价格只是默认 SKU 的价格。监控到单品粒度,用 item_price 传对应 SKU 的 ID,或者解析 skus.sku[]。

2. -1、0、空值要分三种情况处理

-1 = 下架/不存在;0 或空 = 字段异常,视为本次取价失败,不要落库——否则历史最低价会被污染,"历史新低"规则从此失灵。

3. 监控必须 cache=no

接口默认走缓存(速度快),但监控要的是变化,缓存期内价格根本没更新。日常查询用缓存省配额,监控轮询一律关。

4. 判断成功别只看 HTTP 200

接口出错也返回 200,必须判 error_code == "0000"。高频错误码:

错误码 含义 监控程序该做什么
2000 无结果 商品下架/ID 错,标记告警,不重试
4005 鉴权失败 检查 key/secret 是否拼在 URL 上
4008 并发超限 指数退避重试,拉大商品间隔
4013 / 4016 次数超限 / 余额问题 停止轮询并通知负责人,重试只是烧日志
4017 / 4001 / 4002 超时、网络、目标站异常 退避重试即可

5. 告警不做冷却,群会被你炸掉

降价 5% 和历史新低经常是同一件事,两条都发就是刷屏。工程版做了两层去重:同规则 6 小时冷却(alert_log 表),降价已触发就不再报历史新低。大促期间可以调小冷却,平时宁可少打扰。

6. 轮询节奏要跟着价格波动规律走

京东改价集中在 0 点、早 10 点、大促节点。均匀 30 分钟一轮,90% 的请求都浪费在没变化的深夜。更划算的做法是分级轮询:

平时(0:00-8:00)    60 分钟一轮
白天(8:00-22:00)   30 分钟一轮
大促/预热期          5 分钟一轮(单独起一个高优先级清单)

额度是否扛得住看响应里的 api_info 字段(形如 today:28 max:10000),每天先读一次做预算,快打满就自动降频。


五、部署:一台最小机器就够

数据量不大时,一台最低配云主机 + SQLite + crontab 就能稳定跑,不需要 MySQL 和消息队列:

# crontab:每 30 分钟抓一轮,日志按天切
*/30 * * * * cd /opt/jd-monitor && /usr/bin/python3 jd_price_monitor.py once >> logs/run.log 2>&1
# 每天 8 点推送报表链接
0 8 * * * cd /opt/jd-monitor && python3 jd_price_monitor.py report --days 1 && python3 jd_price_monitor.py chart --days 7

Windows 下用任务计划程序建两个基本相同的任务即可。想升级再说:Redis 缓存、MySQL、按类目批量监控,都是在 fetch() 和存储层上加东西,主流程不动。

合规提醒:走数据接口获取的是公开商品信息,注意控制频率、遵守服务商与平台的使用条款;监控数据用于自身选品和比价决策,不要转售原始数据或爬取用户个人信息。


结语

价格监控的技术含量不在"取到价格",而在三件事:把 -1、空值、缓存这些边角处理干净;告警规则宁缺毋滥;数据攒起来之后能变成趋势图。

先跑通精简版确认数据对得上,再换工程版把冷却、报表、曲线补齐,一条稳定的盯价管道就成型了。之后要做比价站、降价订阅、价格弹性分析,都是在这条管道上加业务而已。

相关文章
|
14天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
6196 45
|
2天前
|
云安全 人工智能 安全
|
15天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
5129 60
|
9天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
2482 6
|
2天前
|
JSON 前端开发 API
阿里云最新Qwen4-Max大模型介绍:模型定位、特征、能力、适用场景解析
2026 年 11 月 11 日,阿里发布第四代旗舰模型Qwen4-Max预览版,首发千问 AI 平台 Token Plan,并同步接入千问办公、Qoder 等入口。该版本聚焦知识理解、世界感知、编程与 Agentic 四项升级,主打复杂编程、专业办公、前端设计与专业软件操作。预览期至 11 月 25 日 24:00,到期后模型标识下线;限时 2 折、新用户再享 5 折,最低 1 折可体验。
|
7天前
|
人工智能 安全 API
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(dsh)是DeepSeek AI于2026年开源的轻量级Agent运行框架,基于Cordis内核,践行“一切皆插件”理念。支持Web/桌面双端,开箱即用;内置多模型接入、丰富插件生态(超3.5万),适配编程、办公、创作等场景。(239字)
1562 1
|
2天前
|
人工智能 前端开发 API
阿里云Qwen4-Max 大模型详解:定位、特征、能力、适用场景与相对Qwen3-Max差异解析
2026年11月11日,阿里发布第四代旗舰模型Qwen4-Max预览版,首发千问AI平台Token Plan并接入千问办公、Qoder等入口。该版本聚焦知识理解、世界感知、编程与Agentic四项升级,主打复杂编程、专业办公、前端设计与专业软件操作等真实任务。预览期为11月11日10:00至11月25日24:00,仅支持Token Plan调用,到期后模型标识下线;限时2折、新用户再享5折,最低1折可体验。

热门文章

最新文章