×

苏宁关键词商品列表接口实践:分页迭代与商品数据降噪方案

Ace Ace 发表于2026-10-16 14:17:52 浏览15 评论0

抢沙发发表评论

前言

苏宁开放平台关键词搜索接口,多用于比价、商品库批量拉取场景。和普通搜索接口不一样,它存在两个典型痛点:分页到末尾时不会直接返回空数组,而是返回少量重复商品;同时促销价、划线价混杂在返回字段中,直接入库容易造成价格错乱。本文不只是简单调用接口,重点实现分页循环终止判断、价格字段分离、商品基础信息扁平化封装,适合批量商品检索业务。

前置准备

Python3,依赖 requests 库。需要在苏宁云台申请 AppKey、AppSecret,接口采用 MD5 签名鉴权。接口存在 QPS 限制,批量循环分页必须增加请求间隔,否则会触发接口限流返回业务错误码。

点击获取key和secret

完整代码示例

import requests
import time
import hashlib

class SuningSearchClient:
    def __init__(self, app_key, app_secret):
        self.app_key = app_key
        self.app_secret = app_secret
        self.session = requests.Session()
        self.retry_count = 2
        self.sleep_interval = 1.2

    def build_sign(self, params):
        # 参数按key升序拼接,生成MD5大写签名
        sorted_items = sorted(params.items(), key=lambda x: x[0])
        raw_str = ''.join(f"{k}{v}" for k, v in sorted_items) + self.app_secret
        return hashlib.md5(raw_str.encode('utf-8')).hexdigest().upper()

    def search_item_list(self, keyword, page_index=1, page_size=10):
        api_url = "https://open.suning.com/api/http/sopRequest"
        req_params = {
            "appKey": self.app_key,
            "keyword": keyword,
            "pageIndex": str(page_index),
            "pageSize": str(page_size)
        }
        req_params["sign"] = self.build_sign(req_params)
        for attempt in range(self.retry_count):
            try:
                resp = self.session.post(api_url, json=req_params, timeout=10)
                time.sleep(self.sleep_interval)
                if resp.status_code != 200:
                    return {"code": -2, "data": [], "msg": "HTTP请求异常"}
                res_json = resp.json()
                if res_json.get("sn_error"):
                    err = res_json["sn_error"]
                    return {"code": -1, "data": [], "msg": f"{err['error_code']}:{err['error_msg']}"}
                list_raw = res_json.get("sn_body", {}).get("searchCommodity", [])
                result_list = []
                for item in list_raw:
                    item_data = {
                        "sku_id": item.get("skuId"),
                        "title": item.get("commodityName", "").strip(),
                        "price": item.get("salePrice"),
                        "market_price": item.get("marketPrice"),
                        "pic_url": item.get("commodityPic", ""),
                        "brand_name": item.get("brandName", ""),
                        "is_sale": int(item.get("status", 0)) == 1
                    }
                    result_list.append(item_data)
                return {"code":0, "data":result_list, "msg":"success"}
            except Exception as e:
                if attempt < self.retry_count -1:
                    time.sleep(2)
                    continue
                return {"code": -3, "data": [], "msg": str(e)}

    def get_all_by_keyword(self, keyword, max_page=5):
        """自动分页拉取,通过sku去重,防止末尾重复数据"""
        all_items = []
        seen_skus = set()
        for page in range(1, max_page+1):
            res = self.search_item_list(keyword, page_index=page)
            if res["code"] !=0:
                print(f"第{page}页查询失败:{res['msg']}")
                break
            batch = res["data"]
            if not batch:
                break
            new_items = []
            for goods in batch:
                if goods["sku_id"] and goods["sku_id"] not in seen_skus:
                    seen_skus.add(goods["sku_id"])
                    new_items.append(goods)
            if not new_items:
                # 没有新增商品,终止分页
                break
            all_items.extend(new_items)
        return all_items

if __name__ == "__main__":
    client = SuningSearchClient(app_key="your_appkey", app_secret="your_appsecret")
    goods_list = client.get_all_by_keyword("蓝牙耳机", max_page=3)
    for goods in goods_list:
        print(goods["sku_id"], goods["title"], goods["price"])

核心逻辑解析


  1. 签名生成:参数按 ASCII 排序后拼接密钥生成 MD5 大写签名,严格匹配平台鉴权规则。

  2. 自动分页 + SKU 去重:自定义分页终止逻辑,用 sku 集合做去重,解决接口尾页返回重复商品的问题。

  3. 价格字段分离:区分售价与市场价,避免促销活动期间价格字段混淆。

  4. 分层异常处理:区分网络异常、业务接口报错,网络抖动自动重试。


线上踩坑要点


  1. 关键词编码:中文关键词直接传入,内部不需要额外 url 编码,编码错误会返回空列表。

  2. 分页上限:接口有最大返回页数限制,超过后不会报错,只会重复返回前面数据,必须做 SKU 去重判断。

  3. 商品状态过滤:下架商品依旧出现在搜索列表,入库前需要 status 字段过滤在售商品。

  4. 批量请求控制:多关键词循环查询时,建议使用队列,控制并发,高频调用会触发权限拦截。

群贤毕至

访客