苏宁多规格商品 API 解析实战:SKU 关联逻辑与属性值提取技巧

1 阅读14分钟

苏宁多规格商品 API 解析实战:SKU 关联逻辑与属性值提取技巧

苏宁多规格商品(如手机、家电、服饰等)的 API 返回数据中,SKU 与商品主信息的关联逻辑复杂,属性值格式不统一(如分隔符、命名规则差异),是数据解析的核心难点。本文基于苏宁开放平台suning.custom.product.get API 实战,拆解 SKU 与商品主数据的关联逻辑,提供通用的属性值提取、规格维度拆分技巧,并适配不同品类的格式差异,实现多规格商品数据的标准化解析。

一、核心背景:苏宁多规格商品 API 数据结构

苏宁多规格商品的 API 响应中,「商品主信息」与「SKU 子信息」是「1:N」的关联关系,核心结构如下:

json

{
  "code": "0000",
  "msg": "success",
  "body": {
    "productInfo": {  // 商品主信息(唯一)
      "productCode": "100032189765",  // 商品主ID
      "productName": "小米14 5G手机【多规格】"
    },
    "skuInfo": {  // SKU子信息(多个)
      "skuList": [
        {
          "skuCode": "10003218976512",  // SKU唯一ID
          "skuAttr": "黑色+12GB+256GB", // SKU属性组合
          "salePrice": 3999.0,          // SKU单独售价
          "stockCount": 200             // SKU单独库存
        },
        {
          "skuCode": "10003218976513",
          "skuAttr": "白色+12GB+512GB",
          "salePrice": 4299.0,
          "stockCount": 150
        }
      ]
    },
    "attributeInfo": {  // 商品静态属性(补充规格维度说明)
      "attributeList": [
        {"attrName": "机身颜色", "attrValue": "黑色;白色;蓝色"},
        {"attrName": "存储容量", "attrValue": "256GB;512GB;1TB"}
      ]
    }
  }
}

核心关联逻辑

  1. 主键关联productCode(商品主 ID)是所有 SKU 的父级标识,SKU 编码通常以商品主 ID 为前缀(如100032189765 + 12 = 10003218976512);
  2. 属性关联skuAttr(SKU 属性组合)对应attributeInfo中的静态属性维度(如颜色、存储、尺寸等);
  3. 价格 / 库存关联:SKU 级的价格 / 库存优先级高于商品主信息的价格 / 库存(部分 SKU 有单独定价)。

二、SKU 关联逻辑拆解与验证

1. 主键关联规则(通用)

苏宁 SKU 编码生成遵循「商品主 ID + 规格序号」的规则,不同品类的序号长度不同(1-3 位),验证逻辑如下:

python

运行

def verify_sku_product_relation(product_code: str, sku_code: str) -> bool:
    """
    验证SKU与商品主ID的关联关系
    :param product_code: 商品主ID
    :param sku_code: SKU编码
    :return: 是否关联
    """
    # 规则1:SKU编码以商品主ID为前缀
    if not sku_code.startswith(product_code):
        # 兼容部分品类SKU编码前缀省略末尾0的情况(如商品主ID=100032189760,SKU=1000321897612)
        if sku_code.startswith(product_code.rstrip("0")):
            return True
        return False
    # 规则2:前缀后至少1位规格序号
    seq_part = sku_code[len(product_code):]
    return len(seq_part) >= 1 and seq_part.isdigit()

# 测试验证
product_code = "100032189765"
sku_code_valid = "10003218976512"
sku_code_invalid = "10003218988812"
print(verify_sku_product_relation(product_code, sku_code_valid))  # True
print(verify_sku_product_relation(product_code, sku_code_invalid))  # False

2. 价格 / 库存关联优先级

SKU 级价格 / 库存是实际可售数据,解析时需优先使用 SKU 维度数据,规则如下:

数据维度优先级适用场景
SKU 售价最高下单定价、价格监控
商品主售价次高无 SKU 单独定价时兜底
SKU 库存最高库存预警、可售判断
商品主库存次高无 SKU 单独库存时兜底

python

运行

def get_sku_effective_price(sku_data: dict, product_price: float) -> float:
    """
    获取SKU有效售价(优先SKU售价,无则用商品主售价)
    :param sku_data: SKU单条数据
    :param product_price: 商品主售价
    :return: 有效售价
    """
    sku_price = float(sku_data.get("salePrice", 0.0))
    return sku_price if sku_price > 0 else product_price

def get_sku_effective_stock(sku_data: dict, product_stock: int) -> int:
    """
    获取SKU有效库存(优先SKU库存,无则用商品主库存)
    :param sku_data: SKU单条数据
    :param product_stock: 商品主库存
    :return: 有效库存
    """
    sku_stock = sku_data.get("stockCount", 0)
    # 处理苏宁库存格式(如"200+"→200,"无货"→0)
    if isinstance(sku_stock, str):
        if "+" in sku_stock:
            sku_stock = int(sku_stock.replace("+", ""))
        elif sku_stock in ["无货", "缺货"]:
            sku_stock = 0
        else:
            sku_stock = int(sku_stock) if sku_stock.isdigit() else 0
    return sku_stock if sku_stock >= 0 else product_stock

三、属性值提取核心技巧(适配多格式)

苏宁不同品类的skuAttr格式差异极大,是解析的核心痛点,以下是通用提取技巧:

1. 多分隔符适配(解决格式不统一)

skuAttr常见分隔符包括+/|、空格等,需适配所有分隔符拆分属性:

python

运行

import re

def split_sku_attr(sku_attr: str) -> list:
    """
    拆分SKU属性字符串(适配多分隔符)
    :param sku_attr: SKU属性字符串(如"黑色+12GB+256GB"、"白色/512GB")
    :return: 拆分后的属性值列表
    """
    if not sku_attr:
        return []
    # 正则匹配所有常见分隔符,统一替换为+后拆分
    attr_str = re.sub(r"[/|;\s]", "+", sku_attr)
    # 去重空值、去重重复属性
    attr_list = [attr.strip() for attr in attr_str.split("+") if attr.strip()]
    return list(set(attr_list))

# 测试多格式拆分
test_attrs = [
    "黑色+12GB+256GB",
    "白色/512GB",
    "蓝色 | 8GB | 128GB",
    "红色;256GB"
]
for attr in test_attrs:
    print(f"原始:{attr} → 拆分:{split_sku_attr(attr)}")
# 输出:
# 原始:黑色+12GB+256GB → 拆分:['黑色', '12GB', '256GB']
# 原始:白色/512GB → 拆分:['白色', '512GB']
# 原始:蓝色 | 8GB | 128GB → 拆分:['蓝色', '8GB', '128GB']
# 原始:红色;256GB → 拆分:['红色', '256GB']

2. 规格维度自动匹配(核心技巧)

拆分后的属性值需匹配到具体维度(如颜色、内存、存储、尺寸等),需结合attributeInfo中的静态属性维度实现自动匹配:

python

运行

def match_sku_attr_dimension(sku_attr_list: list, product_attr_list: list) -> dict:
    """
    将SKU属性值匹配到具体维度(如颜色、存储)
    :param sku_attr_list: 拆分后的SKU属性值列表
    :param product_attr_list: 商品静态属性列表(来自attributeInfo)
    :return: 维度→属性值的字典
    """
    # 步骤1:提取商品静态属性的维度(如机身颜色、存储容量)
    attr_dimensions = {}
    for attr in product_attr_list:
        attr_name = attr.get("attrName", "").strip()
        attr_value = attr.get("attrValue", "").strip()
        if not attr_name or not attr_value:
            continue
        # 标准化维度名称(统一关键词)
        std_dim = ""
        if "颜色" in attr_name:
            std_dim = "颜色"
        elif "内存" in attr_name or "运行内存" in attr_name:
            std_dim = "内存"
        elif "存储" in attr_name or "容量" in attr_name and "GB" in attr_value:
            std_dim = "存储"
        elif "尺寸" in attr_name or "尺码" in attr_name:
            std_dim = "尺寸"
        elif "功率" in attr_name:
            std_dim = "功率"
        if std_dim:
            # 提取该维度的所有可选值(如黑色;白色;蓝色→["黑色","白色","蓝色"])
            attr_dimensions[std_dim] = [v.strip() for v in attr_value.split(";")]
    
    # 步骤2:将SKU属性值匹配到标准化维度
    sku_attr_dict = {}
    for attr_value in sku_attr_list:
        matched = False
        for dim, dim_values in attr_dimensions.items():
            if attr_value in dim_values:
                sku_attr_dict[dim] = attr_value
                matched = True
                break
        # 未匹配到预设维度时,自动识别(如含GB的是存储/内存,颜色关键词)
        if not matched:
            if "GB" in attr_value:
                if attr_value in ["8GB", "12GB", "16GB"]:
                    sku_attr_dict["内存"] = attr_value
                else:
                    sku_attr_dict["存储"] = attr_value
            elif any(color in attr_value for color in ["黑色", "白色", "红色", "蓝色", "绿色"]):
                sku_attr_dict["颜色"] = attr_value
            else:
                sku_attr_dict["其他规格"] = attr_value
    return sku_attr_dict

# 测试维度匹配
product_attr_list = [
    {"attrName": "机身颜色", "attrValue": "黑色;白色;蓝色"},
    {"attrName": "存储容量", "attrValue": "256GB;512GB;1TB"},
    {"attrName": "运行内存", "attrValue": "8GB;12GB;16GB"}
]
sku_attr_list = ["黑色", "12GB", "256GB"]
print(match_sku_attr_dimension(sku_attr_list, product_attr_list))
# 输出:{'颜色': '黑色', '内存': '12GB', '存储': '256GB'}

3. 特殊品类适配(服饰 / 家电)

3.1 服饰类(尺码 / 颜色为主)

服饰类skuAttr常为「颜色 - 尺码」格式(如 "黑色 - L 码"),需适配尺码维度识别:

python

运行

def adapt_clothing_sku_attr(sku_attr_list: list) -> dict:
    """适配服饰类SKU属性解析"""
    size_keywords = ["XS", "S", "M", "L", "XL", "XXL", "XXXL", "码", "号"]
    color_keywords = ["黑", "白", "红", "蓝", "绿", "粉", "黄", "紫"]
    
    sku_attr_dict = {}
    for attr in sku_attr_list:
        if any(kw in attr for kw in size_keywords):
            sku_attr_dict["尺码"] = attr
        elif any(kw in attr for kw in color_keywords):
            sku_attr_dict["颜色"] = attr
        else:
            sku_attr_dict["版型"] = attr  # 如宽松、修身
    return sku_attr_dict

# 测试服饰适配
clothing_attr_list = ["黑色", "XL码"]
print(adapt_clothing_sku_attr(clothing_attr_list))  # {'颜色': '黑色', '尺码': 'XL码'}
3.2 家电类(功率 / 尺寸为主)

家电类skuAttr含功率、尺寸等数值型属性,需标准化单位:

python

运行

def adapt_appliance_sku_attr(sku_attr_list: list) -> dict:
    """适配家电类SKU属性解析"""
    sku_attr_dict = {}
    for attr in sku_attr_list:
        if "W" in attr or "千瓦" in attr:
            # 统一单位为W(如"1.5千瓦"→"1500W")
            if "千瓦" in attr:
                kw = float(attr.replace("千瓦", "").strip())
                attr = f"{int(kw*1000)}W"
            sku_attr_dict["功率"] = attr
        elif "mm" in attr or "cm" in attr:
            # 统一单位为mm(如"60cm"→"600mm")
            if "cm" in attr:
                cm = float(attr.replace("cm", "").strip())
                attr = f"{int(cm*10)}mm"
            sku_attr_dict["尺寸"] = attr
        elif "升" in attr:
            sku_attr_dict["容量"] = attr
    return sku_attr_dict

# 测试家电适配
appliance_attr_list = ["1.5千瓦", "60cm"]
print(adapt_appliance_sku_attr(appliance_attr_list))  # {'功率': '1500W', '尺寸': '600mm'}

四、完整解析实战(多规格商品)

1. 全流程解析函数

python

运行

import json
from typing import Dict, List

def safe_extract_field(data: Dict, field_path: str, default: any = None) -> any:
    """安全提取嵌套字段"""
    keys = field_path.split(".")
    value = data
    for key in keys:
        if isinstance(value, dict) and key in value:
            value = value[key]
        else:
            return default
    return value

def parse_suning_multi_sku_product(raw_api_data: Dict) -> Dict:
    """
    全流程解析苏宁多规格商品API数据
    :param raw_api_data: API原始响应数据
    :return: 标准化的多规格商品数据
    """
    # 1. 提取基础信息
    product_code = safe_extract_field(raw_api_data, "body.productInfo.productCode", "")
    product_name = safe_extract_field(raw_api_data, "body.productInfo.productName", "")
    product_price = float(safe_extract_field(raw_api_data, "body.priceInfo.salePrice", 0.0))
    product_stock = safe_extract_field(raw_api_data, "body.stockInfo.stockCount", 0)
    # 处理商品主库存格式
    if isinstance(product_stock, str):
        product_stock = int(product_stock.replace("+", "")) if "+" in product_stock else 0

    # 2. 提取商品静态属性列表
    product_attr_list = safe_extract_field(raw_api_data, "body.attributeInfo.attributeList", [])

    # 3. 提取SKU列表并解析
    sku_list = safe_extract_field(raw_api_data, "body.skuInfo.skuList", [])
    parsed_skus = []
    for sku in sku_list:
        sku_code = sku.get("skuCode", "")
        sku_attr_str = sku.get("skuAttr", "")
        
        # 验证SKU与商品主ID的关联
        is_related = verify_sku_product_relation(product_code, sku_code)
        if not is_related:
            print(f"SKU {sku_code} 与商品 {product_code} 无关联,跳过")
            continue
        
        # 拆分SKU属性
        sku_attr_list = split_sku_attr(sku_attr_str)
        
        # 匹配属性维度(优先用商品静态属性,无则自动识别)
        sku_attr_dict = match_sku_attr_dimension(sku_attr_list, product_attr_list)
        # 适配特殊品类(可根据商品类目选择适配函数)
        category_name = safe_extract_field(raw_api_data, "body.productInfo.categoryName", "")
        if "服饰" in category_name:
            sku_attr_dict = adapt_clothing_sku_attr(sku_attr_list)
        elif "家电" in category_name or "电器" in category_name:
            sku_attr_dict = adapt_appliance_sku_attr(sku_attr_list)
        
        # 获取SKU有效价格和库存
        sku_effective_price = get_sku_effective_price(sku, product_price)
        sku_effective_stock = get_sku_effective_stock(sku, product_stock)
        
        # 组装SKU解析结果
        parsed_sku = {
            "SKU编码": sku_code,
            "关联商品主ID": product_code,
            "属性维度": sku_attr_dict,
            "原始属性字符串": sku_attr_str,
            "有效售价(元)": round(sku_effective_price, 2),
            "有效库存数": sku_effective_stock,
            "SKU状态": "可售" if sku.get("skuStatus") == "1" else "不可售"
        }
        parsed_skus.append(parsed_sku)

    # 4. 组装最终结果
    final_result = {
        "商品主信息": {
            "商品主ID": product_code,
            "商品名称": product_name,
            "商品主售价(元)": round(product_price, 2),
            "商品主库存数": product_stock,
            "是否多规格": len(parsed_skus) > 1
        },
        "SKU列表": parsed_skus,
        "静态属性列表": product_attr_list
    }
    return final_result

# 2. 测试实战(模拟苏宁API返回数据)
if __name__ == "__main__":
    # 模拟多规格手机商品API响应
    mock_raw_data = {
        "code": "0000",
        "msg": "success",
        "body": {
            "productInfo": {
                "productCode": "100032189765",
                "productName": "小米14 5G手机【多规格】",
                "categoryName": "数码家电-手机通讯-5G手机"
            },
            "priceInfo": {
                "salePrice": 3999.0
            },
            "stockInfo": {
                "stockCount": "500+"
            },
            "skuInfo": {
                "skuList": [
                    {
                        "skuCode": "10003218976512",
                        "skuAttr": "黑色+12GB+256GB",
                        "salePrice": 3999.0,
                        "stockCount": "200+",
                        "skuStatus": "1"
                    },
                    {
                        "skuCode": "10003218976513",
                        "skuAttr": "白色/12GB/512GB",
                        "salePrice": 4299.0,
                        "stockCount": 150,
                        "skuStatus": "1"
                    },
                    {
                        "skuCode": "10003218988814",  # 无效SKU(无关联)
                        "skuAttr": "蓝色+16GB+1TB",
                        "salePrice": 4999.0,
                        "stockCount": 100,
                        "skuStatus": "1"
                    }
                ]
            },
            "attributeInfo": {
                "attributeList": [
                    {"attrName": "机身颜色", "attrValue": "黑色;白色;蓝色"},
                    {"attrName": "运行内存", "attrValue": "8GB;12GB;16GB"},
                    {"attrName": "存储容量", "attrValue": "256GB;512GB;1TB"}
                ]
            }
        }
    }

    # 全流程解析
    parsed_result = parse_suning_multi_sku_product(mock_raw_data)
    # 格式化输出
    print(json.dumps(parsed_result, ensure_ascii=False, indent=2))

2. 解析结果输出

json

{
  "商品主信息": {
    "商品主ID": "100032189765",
    "商品名称": "小米14 5G手机【多规格】",
    "商品主售价(元)": 3999.0,
    "商品主库存数": 500,
    "是否多规格": true
  },
  "SKU列表": [
    {
      "SKU编码": "10003218976512",
      "关联商品主ID": "100032189765",
      "属性维度": {
        "颜色": "黑色",
        "内存": "12GB",
        "存储": "256GB"
      },
      "原始属性字符串": "黑色+12GB+256GB",
      "有效售价(元)": 3999.0,
      "有效库存数": 200,
      "SKU状态": "可售"
    },
    {
      "SKU编码": "10003218976513",
      "关联商品主ID": "100032189765",
      "属性维度": {
        "颜色": "白色",
        "内存": "12GB",
        "存储": "512GB"
      },
      "原始属性字符串": "白色/12GB/512GB",
      "有效售价(元)": 4299.0,
      "有效库存数": 150,
      "SKU状态": "可售"
    }
  ],
  "静态属性列表": [
    {"attrName": "机身颜色", "attrValue": "黑色;白色;蓝色"},
    {"attrName": "运行内存", "attrValue": "8GB;12GB;16GB"},
    {"attrName": "存储容量", "attrValue": "256GB;512GB;1TB"}
  ]
}

五、避坑指南与优化建议

1. 常见解析问题及解决方案

问题类型表现形式解决方案
SKU 编码无关联SKU 编码不以商品主 ID 为前缀过滤无效 SKU,记录异常 SKU 编码用于核查
属性值匹配失败拆分后的属性值无对应维度新增「其他规格」维度兜底,避免字段缺失
单位格式混乱功率有 "W"、"千瓦",尺寸有 "cm"、"mm"统一单位(如功率→W,尺寸→mm)
部分 SKU 无价格 / 库存SKU 售价为 0 或库存为空用商品主价格 / 库存兜底,并标记「数据异常」
特殊字符干扰SKU 属性含 emoji、特殊符号(如🔥)正则过滤非中文 / 数字 / 字母字符:re.sub(r'[^\u4e00-\u9fa50-9A-Za-zGBW]+', '', attr)

2. 性能优化建议

  • 缓存维度映射:将商品类目→规格维度的映射关系缓存(如手机→[颜色、内存、存储]),避免重复解析;
  • 批量解析:批量处理多商品时,先提取所有 SKU 属性格式,统一适配分隔符,提升解析效率;
  • 异步解析:使用aiohttp异步调用 API,结合多进程解析 SKU 属性,适配万级商品批量解析。

3. 合规与稳定性建议

  • 异常日志:记录解析失败的 SKU 编码、属性字符串,便于后续排查;
  • 版本兼容:苏宁 API 版本更新时,优先适配skuAttrattributeInfo字段的格式变化;
  • 数据校验:解析后校验 SKU 数量、价格范围(如售价不能为负),过滤无效数据。

六、总结

苏宁多规格商品 API 解析的核心是「关联验证 + 多格式适配 + 维度标准化」:

  1. 关联验证:通过 SKU 编码前缀规则验证 SKU 与商品主 ID 的关联,过滤无效数据;
  2. 多格式适配:兼容不同分隔符、不同品类的属性格式,解决解析碎片化问题;
  3. 维度标准化:将属性值匹配到统一维度(颜色、内存、存储等),并标准化单位,适配下游业务场景。

本文的解析方案可直接应用于商品展示、价格监控、库存管理、SKU 下单等核心业务场景,兼顾通用性与品类适配性,确保多规格商品数据的准确解析。