京东的 `item_history_price` 接口是电商价格分析中最实用的 API 之一。它返回商品的历史价格序列、最低价、当前价等结构化数据,是构建价格监控系统的核心数据源。以下从接口接入、代码实现、监控系统搭建到实践注意事项,提供一套完整的技术方案。
## 一、接口概述与接入准备
`item_history_price` 属于京东开放平台商品类接口,功能是**根据商品 ID 获取该商品的历史价格信息**,包括最低价、当前价以及价格变动记录。
调用前需要完成三步准备:
**注册与创建应用**:访问京东开放平台,注册开发者账号,在开发者中心创建应用,获取 **App Key** 和 **App Secret**,这是身份验证的基础凭证。
**申请接口权限**:在应用的“API 权限申请”模块中,搜索并勾选与商品价格相关的接口权限。历史价格查询通常需要单独申请,建议申请时明确说明“价格监控/比价”等合规用途。
**获取访问凭证**:部分接口需要额外获取 Access Token,需妥善保管,避免泄露。
## 二、公共参数与请求参数
接口采用标准 HTTP GET 请求,公共参数如下:
| 参数 | 类型 | 必须 | 说明 |
|---|---|---|---|
| `key` | String | 是 | 调用 key,拼接在 URL 中 |
| `secret` | String | 是 | 调用密钥 |
| `api_name` | String | 是 | 接口名称,此处为 `item_history_price` |
| `cache` | String | 否 | `yes`/`no`,默认 `yes`,启用缓存可加速响应 |
| `result_type` | String | 否 | 返回格式,默认 `json`;`jsonu` 可让中文直接可读 |
| `lang` | String | 否 | 语言,默认 `cn` |
| `version` | String | 否 | API 版本 |
**请求参数**只有一个核心字段:
| 参数 | 类型 | 必须 | 说明 |
|---|---|---|---|
| `num_iid` | Bigint | 是 | 京东商品 ID(SKU ID) |
商品 ID 即京东商品链接中 `item.jd.com/` 后的数字,例如 `584458528092`。注意接口使用的参数名是 `num_iid`,而非 `skuId` 或 `wareId`,这是容易踩坑的地方。
## 三、Python 调用实现
以下是完整的 Python 调用代码,包含参数构造、请求发送和基础错误处理:
```python
import requests
import pandas as pd
from datetime import datetime
# 配置 API 凭证与目标商品
API_URL = "https://api-gw.onebound.cn/jd/item_history_price/"
APP_KEY = "your_app_key" # 替换为实际值
APP_SECRET = "your_app_secret" # 替换为实际值
SKU_ID = "584458528092" # 替换为目标商品 ID
def fetch_price_history(sku_id):
params = {
"key": APP_KEY,
"secret": APP_SECRET,
"num_iid": sku_id,
"cache": "no", # 价格监控场景建议关闭缓存
"result_type": "json",
"lang": "cn",
}
try:
resp = requests.get(API_URL, params=params, timeout=15)
resp.raise_for_status()
data = resp.json()
return data
except requests.RequestException as e:
print(f"请求失败: {e}")
return None
def parse_history(data):
"""将返回数据解析为 DataFrame"""
if not data or "item" not in data:
return None
item = data["item"]
records = []
for entry in item.get("price_list", []):
records.append({
"date": entry.get("date"),
"price": entry.get("price"),
"discount": entry.get("discount", ""),
})
df = pd.DataFrame(records)
if not df.empty:
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values("date").set_index("date")
return df
if __name__ == "__main__":
raw = fetch_price_history(SKU_ID)
df = parse_history(raw)
if df is not None:
print(df.head())
df.to_csv(f"jd_{SKU_ID}_history.csv", encoding="utf-8")
```
如果使用京东官方开放平台(而非第三方聚合接口),签名生成方式有所不同,需要将所有请求参数按 ASCII 码升序排列后拼接,再与 App Secret 结合生成 MD5 或 HMAC-SHA256 签名。以下是签名生成函数:
```python
import hashlib
def generate_jd_sign(params, app_secret):
"""京东开放平台签名生成"""
sorted_items = sorted(params.items(), key=lambda x: x[0])
sign_str = app_secret
for k, v in sorted_items:
sign_str += f"{k}{v}"
sign_str += app_secret
return hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()
```
## 四、返回值字段解析
接口返回 JSON 格式数据,核心字段如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| `num_iid` | Bigint | 商品 ID |
| `title` | String | 商品标题 |
| `detail_url` | String | 商品链接 |
| `pic_url` | String | 商品主图 |
| `lower_price` | Float | **历史最低价** |
| `lower_date` | String | 最低价出现日期 |
| `current_price` | Float | **当前价** |
| `change_price_remark` | Mix | 价格变动信息,含日期、价格、折扣 |
其中 `change_price_remark` 是一个嵌套结构,典型值为 `{"date": "2020-06-25", "price": "39.00", "discount": ""}`,记录了每一次价格变动的时间点和价格。
在价格监控场景中,最核心的三个字段是 `lower_price`(判断当前是否处于历史低位)、`current_price`(实时决策依据)和 `change_price_remark`(识别异常波动)。
## 五、构建价格监控系统
基于该接口可以搭建一套轻量级价格监控系统,核心架构为:**定时采集 → 时序存储 → 波动分析 → 阈值告警**。
**定时采集**:使用 `schedule` 库或系统的 Cron 任务,按固定间隔(建议不低于 300 秒)轮询调用接口。对于多商品监控,可将 SKU ID 列表存入配置文件或数据库,循环采集。
**数据存储**:推荐使用 SQLite(轻量)或 MongoDB(灵活),核心表结构只保留 `sku_id`、`price`、`timestamp` 三个字段即可,日积月累形成专属历史价格库。
**波动检测与告警**:计算当前价与历史最低价的差值,当 `current_price` 接近或低于 `lower_price` 的 95% 时触发通知;也可以监测单次价格变动幅度,超过预设阈值(如降价 5%)即推送告警。告警渠道可用邮件、钉钉机器人或微信推送。
一个简化的监控循环示例:
```python
import schedule
import time
WATCH_LIST = ["584458528092", "10335871600"]
def check_prices():
for sku in WATCH_LIST:
data = fetch_price_history(sku)
if not data:
continue
item = data.get("item", {})
current = float(item.get("current_price", 0))
lowest = float(item.get("lower_price", 0))
if lowest > 0 and current <= lowest * 1.05:
send_alert(sku, item.get("title"), current, lowest)
schedule.every(30).minutes.do(check_prices)
while True:
schedule.run_pending()
time.sleep(1)
```
## 六、实践注意事项
**缓存策略要谨慎**:接口默认启用缓存(`cache=yes`),虽然响应更快,但价格监控场景下可能拿到过期数据。建议监控场景设为 `cache=no`,或者在轮询时主动传入时间戳参数以绕过缓存。
**频率限制**:京东 API 对请求频率有明确限制,价格监控建议轮询间隔不低于 300 秒,避免触发限流。
**权限合规**:历史价格查询权限通常需要单独申请,且明确禁止用于竞品数据采集等场景。个人开发者申请时用途应聚焦于消费者比价或自用采购分析。
**异常重试**:网络请求可能超时,建议使用重试机制(如 `@retry(max_attempts=3)` 装饰器)提高采集成功率。
**返回格式选择**:调试阶段使用 `result_type=jsonu`,中文可直接阅读,便于确认字段结构;生产环境使用默认的 `json` 即可。

