京东 item_get_app 接口深度分析及 Python 实现

京东的 item_get_app 接口是用于获取商品原始详情数据的核心接口,与普通的 item_get 接口相比,它返回的数据更贴近京东 APP 端展示的原始结构,包含更丰富的字段和细节信息。这些原始数据对于深度电商分析、竞品监控、价格追踪等场景具有重要价值。

一、接口核心特性分析

  1. 接口功能与定位
  • 核心功能:获取京东商品的原始详情数据,包括商品基础信息、价格体系、库存状态、规格参数、促销活动等完整字段

  • 数据特点

    • 与京东 APP 端数据结构一致,保留原始字段名和层级关系
    • 包含普通接口不返回的内部标识和计算参数
    • 实时性高,反映当前商品的最新状态
    • 字段丰富,包含算法推荐、权重参数等内部信息
  • 应用场景

    • 深度电商数据分析系统
    • 商品全生命周期监控
    • 价格变动实时追踪
    • 竞品全方位对比分析
    • 电商大数据挖掘与研究
  1. 认证机制

京东开放平台采用 appkey + access_token 的认证方式:

  • 开发者在京东开放平台注册应用,获取 appkeyappsecret
  • 通过 appkeyappsecret 获取 access_token(通常有效期为 24 小时)
  • 每次接口调用需在请求参数中携带有效 access_token
  • item_get_app 属于高级接口,需要单独申请权限
  1. 核心参数与响应结构

请求参数

参数名 类型 是否必填 说明
sku_id String 商品 SKU ID,京东商品的唯一标识
access_token String 访问令牌
platform String 平台类型,如 "android"、"ios",默认 "android"
fields String 需要返回的字段,默认返回全部字段
area String 地区编码,用于获取区域化价格和库存

响应核心字段

  • 商品基础信息:SKU ID、商品名称、品牌信息、分类信息等
  • 价格信息:基准价、促销价、会员价、活动价、价格计算规则等
  • 库存信息:实时库存、区域库存、库存状态、限购信息等
  • 规格参数:SKU 规格、属性组合、规格图片等
  • 促销信息:活动列表、优惠券、满减规则、赠品信息等
  • 服务信息:售后政策、配送服务、安装服务等
  • 多媒体信息:图片、视频、3D 模型等资源链接

二、Python 脚本实现

以下是调用京东 item_get_app 接口的完整 Python 实现,包含令牌获取、接口调用、数据解析等功能: import requests import time import json import logging import hashlib from typing import Dict, Optional, List from requests.exceptions import RequestException

配置日志

logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" )

class JDItemGetAppAPI: def init (self, appkey: str, appsecret: str): """ 初始化京东商品详情原数据API客户端 :param appkey: 京东开放平台appkey :param appsecret: 京东开放平台appsecret """ self.appkey = appkey self.appsecret = appsecret self.base_url = "api.jd.com" self.access_token = None self.token_expires_at = 0 # token过期时间戳 self.session = requests.Session() self.session.headers.update({ "Content-Type": "application/json", "User-Agent": "JDApp;android;9.5.4;android 10;scale/3.0" # 模拟京东APP请求头 })

python 复制代码
def _get_access_token(self) -> Optional[str]:
    """获取访问令牌"""
    # 检查token是否有效
    if self.access_token and self.token_expires_at > time.time() + 60:
        return self.access_token
        
    logging.info("获取新的access_token")
    url = f"{self.base_url}/oauth2/token"
    
    params = {
        "grant_type": "client_credentials",
        "appkey": self.appkey,
        "appsecret": self.appsecret
    }
    
    try:
        response = self.session.get(url, params=params, timeout=10)
        response.raise_for_status()
        result = response.json()
        
        if "access_token" in result:
            self.access_token = result["access_token"]
            self.token_expires_at = time.time() + result.get("expires_in", 86400)  # 默认为24小时
            return self.access_token
        else:
            logging.error(f"获取access_token失败: {result.get('error_description', '未知错误')}")
            return None
            
    except RequestException as e:
        logging.error(f"获取access_token请求异常: {str(e)}")
        return None

def get_item_raw_data(self, 
                     sku_id: str, 
                     platform: str = "android",
                     area: str = "1_72_2799_0",  # 默认地区编码:北京
                     fields: Optional[str] = None) -> Optional[Dict]:
    """
    获取商品原始详情数据
    :param sku_id: 商品SKU ID
    :param platform: 平台类型
    :param area: 地区编码
    :param fields: 需要返回的字段
    :return: 商品原始数据
    """
    # 验证参数
    valid_platforms = ["android", "ios"]
    if platform not in valid_platforms:
        logging.error(f"无效的平台类型: {platform},支持: {valid_platforms}")
        return None
        
    # 获取有效的access_token
    if not self._get_access_token():
        return None
        
    url = f"{self.base_url}/item/get_app"
    
    # 构建请求参数
    params = {
        "sku_id": sku_id,
        "access_token": self.access_token,
        "platform": platform,
        "area": area,
        "timestamp": int(time.time() * 1000)  # 时间戳,毫秒级
    }
    
    # 添加字段筛选
    if fields:
        params["fields"] = fields
        
    # 生成签名(部分接口需要)
    params["sign"] = self._generate_sign(params)
        
    try:
        response = self.session.get(url, params=params, timeout=20)
        response.raise_for_status()
        result = response.json()
        
        # 检查响应状态
        if result.get("code") == 200:
            # 格式化原始数据
            return self._process_raw_data(result.get("data", {}))
        else:
            logging.error(f"获取商品数据失败: {result.get('message', '未知错误')} (错误码: {result.get('code')})")
            return Non          
    except RequestException as e:
        logging.error(f"获取商品数据请求异常: {str(e)}")
        return None
    except json.JSONDecodeError:
        logging.error(f"商品数据响应解析失败: {response.text[:200]}...")
        return None

def _generate_sign(self, params: Dict) -> str:
    """生成签名(部分京东接口需要)"""
    # 按参数名排序
    sorted_params = sorted(params.items(), key=lambda x: x[0])
    # 拼接参数
    sign_str = self.appsecret
    for k, v in sorted_params:
        if k != "sign":
            sign_str += f"{k}{v}"
    sign_str += self.appsecret
    # SHA256加密
    return hashlib.sha256(sign_str.encode()).hexdigest().upper()

def _process_raw_data(self, raw_data: Dict) -> Dict:
    """处理原始数据,提取关键信息并格式化"""
    # 基础信息提取
    base_info = {
        "sku_id": raw_data.get("skuId"),
        "spu_id": raw_data.get("spuId"),
        "item_id": raw_data.get("itemId"),
        "title": raw_data.get("skuName"),
        "sub_title": raw_data.get("skuSubName"),
        "brand": {
            "id": raw_data.get("brandId"),
            "name": raw_data.get("brandName")
        },
        "category": {
            "cid1": raw_data.get("cid1"),
            "cid2": raw_data.get("cid2"),
            "cid3": raw_data.get("cid3"),
            "name1": raw_data.get("cateName1"),
            "name2": raw_data.get("cateName2"),
            "name3": raw_data.get("cateName3")
        },
        "url": f"https://item.jd.com/{raw_data.get('skuId')}.html" if raw_data.get('skuId') else None
    }
    
    # 价格信息提取
    price_info = {
        "jd_price": self._safe_float(raw_data.get("jdPrice", {}).get("p")),  # 京东价
        "market_price": self._safe_float(raw_data.get("marketPrice", {}).get("p")),  # 市场价
        "vip_price": self._safe_float(raw_data.get("vipPrice", {}).get("p")),  # 会员价
        "plus_price": self._safe_float(raw_data.get("plusPrice", {}).get("p")),  # PLUS会员价
        "promotion_price": self._safe_float(raw_data.get("promotionPrice", {}).get("p")),  # 促销价
        "price_history": raw_data.get("priceHistory"),  # 价格历史
        "price_tags": raw_data.get("priceTags", [])  # 价格标签
    }
    
    # 库存信息提取
    stock_info = {
        "stock_num": self._safe_int(raw_data.get("stock", {}).get("stockNum")),  # 库存数量
        "stock_state": raw_data.get("stock", {}).get("stockState"),  # 库存状态
        "stock_state_name": raw_data.get("stock", {}).get("stockStateName"),  # 库存状态名称
        "limit_buy": self._safe_int(raw_data.get("limitBuy")),  # 限购数量
        "area_stock": raw_data.get("areaStock")  # 区域库存信息
    }
    
    # 规格信息提取
    sku_info = {
        "total_sku": self._safe_int(raw_data.get("totalSku")),  # 总规格数量
        "sku_list": self._format_sku_list(raw_data.get("skuList", [])),  # 规格列表
        "spec_list": self._format_spec_list(raw_data.get("specList", []))  # 规格参数
    }
    
    # 促销信息提取
    promotion_info = {
        "promotions": raw_data.get("promotion", {}).get("promotionList", []),  # 促销活动列表
        "coupons": raw_data.get("couponList", []),  # 优惠券列表
        "gift_list": raw_data.get("giftList", []),  # 赠品列表
        "seckill_info": raw_data.get("seckillInfo")  # 秒杀信息
    }
    
    # 图片信息提取
    image_info = {
        "main_images": self._extract_images(raw_data.get("mainImgList", [])),  # 主图列表
        "detail_images": self._extract_images(raw_data.get("detailImgList", [])),  # 详情图列表
        "video_url": raw_data.get("videoInfo", {}).get("videoUrl")  # 视频URL
    }
    
    # 服务信息提取
    service_info = {
        "after_sale_service": raw_data.get("afterSaleService"),  # 售后服务
        "delivery_service": raw_data.get("deliveryService"),  # 配送服务
        "install_service": raw_data.get("installService"),  # 安装服务
        "warranty": raw_data.get("warranty")  # 保修信息
    }
    
    return {
        "base_info": base_info,
        "price_info": price_info,
        "stock_info": stock_info,
        "sku_info": sku_info,
        "promotion_info": promotion_info,
        "image_info": image_info,
        "service_info": service_info,
        "raw_data": raw_data  # 保留原始数据
    }

def _safe_float(self, value) -> float:
    """安全转换为float"""
    try:
        return float(value) if value is not None else 0.0
    except (ValueError, TypeError):
        return 0.0

def _safe_int(self, value) -> int:
    """安全转换为int"""
    try:
        return int(value) if value is not None else 0
    except (ValueError, TypeError):
        return 0

def _format_sku_list(self, sku_list: List[Dict]) -> List[Dict]:
    """格式化SKU列表"""
    formatted = []
    for sku in sku_list:
        formatted.append({
            "sku_id": sku.get("skuId"),
            "name": sku.get("name"),
            "price": self._safe_float(sku.get("jdPrice", {}).get("p")),
            "stock_num": self._safe_int(sku.get("stockNum")),
            "specs": sku.get("specs"),
            "image_url": sku.get("imgUrl"),
            "status": sku.get("status")
        })
    return formatted

def _format_spec_list(self, spec_list: List[Dict]) -> List[Dict]:
    """格式化规格参数列表"""
    formatted = []
    for spec in spec_list:
        formatted.append({
            "name": spec.get("name"),
            "values": [
                {
                    "name": val.get("name"),
                    "image_url": val.get("imgUrl"),
                    "selected": val.get("selected", False)
                } for val in spec.get("valueList", [])
            ]
        })
    return formatted

def _extract_images(self, image_list: List[Dict]) -> List[str]:
    """提取图片URL列表"""
    images = []
    for img in image_list:
        if isinstance(img, dict):
            url = img.get("url")
            if url:
                images.append(url)
        elif isinstance(img, str):
            images.append(img)
    return images

def compare_prices(self, current_data: Dict, previous_data: Dict) -> Dict:
    """比较两个时间点的价格差异"""
    if not current_data or not previous_data:
        return {}
        
    price_changes = {}
    price_types = ["jd_price", "market_price", "vip_price", "plus_price", "promotion_price"]
    
    for price_type in price_types:
        current = current_data["price_info"][price_type]
        previous = previous_data["price_info"][price_type]
        
        if current != previous:
            change = current - previous
            change_percent = (change / previous) * 100 if previous != 0 else 0
            price_changes[price_type] = {
                "current": current,
                "previous": previous,
                "change": round(change, 2),
                "change_percent": round(change_percent, 2)
            }
    
    return {
        "has_change": len(price_changes) > 0,
        "changes": price_changes,
        "compared_at": time.strftime("%Y-%m-%d %H:%M:%S")
    }

示例调用 if name == "main": # 替换为实际的appkey和appsecret(从京东开放平台获取) APPKEY = "your_appkey" APPSECRET = "your_appsecret" # 替换为目标商品SKU ID SKU_ID = "100012345678"

python 复制代码
# 初始化API客户端
api = JDItemGetAppAPI(APPKEY, APPSECRET)

# 获取商品原始数据
item_data = api.get_item_raw_data(
    sku_id=SKU_ID,
    platform="android",
    area="1_72_2799_0"  # 北京地区编码
    # fields="skuId,skuName,jdPrice,stock"  # 可选,指定需要的字段
)

if item_data:
    print(f"=== 京东商品详情 (SKU: {SKU_ID}) ===")
    print(f"商品名称: {item_data['base_info']['title']}")
    print(f"品牌: {item_data['base_info']['brand']['name']}")
    print(f"分类: {item_data['base_info']['category']['name1']} > {item_data['base_info']['category']['name2']} > {item_data['base_info']['category']['name3']}")
    print(f"京东价: {item_data['price_info']['jd_price']}元")
    
    if item_data['price_info']['promotion_price'] and item_data['price_info']['promotion_price'] < item_data['price_info']['jd_price']:
        print(f"促销价: {item_data['price_info']['promotion_price']}元")
        
    if item_data['price_info']['vip_price'] and item_data['price_info']['vip_price'] < item_data['price_info']['jd_price']:
        print(f"会员价: {item_data['price_info']['vip_price']}元")
        
    print(f"库存状态: {item_data['stock_info']['stock_state_name']}")
    print(f"规格数量: {item_data['sku_info']['total_sku']}")
    print(f"主图数量: {len(item_data['image_info']['main_images'])}")
    print(f"促销活动数量: {len(item_data['promotion_info']['promotions'])}")
    
    # 打印前3个规格信息
    if item_data['sku_info']['sku_list']:
        print("\n规格信息:")
        for i, sku in enumerate(item_data['sku_info']['sku_list'][:3], 1):
            print(f"  {i}. {sku['name']}: {sku['price']}元 (库存: {sku['stock_num']})")
    
    # 打印主要促销活动
    if item_data['promotion_info']['promotions']:
        print("\n促销活动:")
        for i, promo in enumerate(item_data['promotion_info']['promotions'][:3], 1):
            print(f"  {i}. {promo.get('title')}")

三、接口调用注意事项

  1. 调用限制与规范
  • 权限要求item_get_app 属于高级接口,需要向京东开放平台单独申请权限
  • QPS 限制:该接口 QPS 限制通常较低(1-5 次 / 秒),需严格控制调用频率
  • 数据缓存:建议缓存获取的数据(缓存时间 30-60 分钟),减少重复调用
  • 地区编码:不同地区可能有不同的价格和库存,需正确设置 area 参数
  • 字段筛选:不需要全部字段时,通过 fields 参数指定所需字段,提高响应速度
  1. 常见错误及解决方案
错误码 说明 解决方案
401 未授权或 token 无效 重新获取 access_token,检查权限是否正确
403 权限不足 申请item_get_app接口的访问权限
404 商品不存在 确认 sku_id 是否正确有效
429 调用频率超限 降低调用频率,实现请求限流
500 服务器内部错误 实现重试机制,最多 3 次,间隔指数退避
10002 参数错误 检查地区编码等参数是否正确
  1. 数据解析要点
  • 价格字段:价格相关字段可能以字符串形式返回,需转换为数值类型
  • 库存状态:库存状态有多种编码,需结合状态名称理解实际含义
  • 规格结构:规格数据结构复杂,需递归解析多层规格组合
  • 促销信息:促销活动有多种类型,需分别处理不同的促销规则
  • 图片 URL:部分图片 URL 需要拼接域名才能访问

四、应用场景与扩展建议

典型应用场景

  • 商品全信息监控系统:实时监控商品所有属性的变化
  • 价格趋势分析工具:追踪商品价格历史,预测价格变化
  • 竞品深度分析平台:全方位对比分析竞品的各项参数和策略
  • 库存预警系统:基于原始库存数据设置预警阈值
  • 电商大数据分析平台:挖掘商品数据中的关联关系和规律

扩展建议

  • 实现价格变化监控:定期获取数据,对比价格变化并记录
  • 开发库存趋势分析:跟踪库存数量变化,预测库存耗尽时间
  • 构建商品特征向量:将原始数据转换为特征向量,用于机器学习
  • 实现多地区数据对比:获取不同地区的价格和库存,分析区域差异
  • 开发数据导出功能:支持将原始数据和解析后的数据导出为 CSV/Excel
  • 构建商品相似度计算:基于原始属性计算商品间的相似度 通过合理使用京东 item_get_app 接口,开发者可以获取最全面的商品原始数据,为深度电商分析和决策支持提供有力保障。使用时需遵守京东开放平台的相关规定,确保数据的合法使用
相关推荐
兵临天下api4 小时前
京东 item_video 接口深度分析及 Python 实现
trae
用户4099322502125 小时前
如何在 FastAPI 中巧妙覆盖依赖注入并拦截第三方服务调用?
后端·ai编程·trae
倔强的石头1061 天前
Trae x 图片素描MCP一键将普通图片转换为多风格素描效果
低代码·mcp·trae·蓝耘
兵临天下api1 天前
淘宝 item_review 接口深度分析及 Python 实现
trae
兵临天下api1 天前
商品销量详情接口(item_get_sales)深度分析及 Python 实现
trae
用户4099322502121 天前
为什么你的单元测试需要Mock数据库才能飞起来?
后端·ai编程·trae
前端的日常2 天前
Trae实现的前端路线象限图
trae
兵临天下api2 天前
蘑菇街 item_get 接口深度分析及 Python 实现
trae
兵临天下api2 天前
唯品会 item_search_img 接口深度分析及 Python 实现
trae