×

python采集淘宝关键词搜索API接口系列,json数据返回

知名用户18007905473 知名用户18007905473 发表于2025-12-16 11:28:50 浏览16 评论0

抢沙发发表评论

以下是一套完整的 Python 代码方案,用于采集淘宝关键词搜索 API 接口并处理返回的 JSON 数据,包含接口调用、数据解析、异常处理、批量采集、数据存储全流程,适配稳定性和可靠性要求:

一、核心依赖安装

bash
运行
pip install requests  # 发起HTTP请求pip install redis     # 可选,用于缓存pip install tenacity  # 重试机制

二、完整采集代码

python
运行
import requestsimport hashlibimport timeimport jsonimport loggingfrom tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_typeimport redis  # 可选,缓存用# ==================== 配置项 ====================# 1. 淘宝开放平台信息(替换为自己的)APP_KEY = "你的App Key"APP_SECRET = "你的App Secret"API_URL = "https://eco.taobao.com/router/rest"# 2. 日志配置(记录调用过程和异常)logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[logging.FileHandler("taobao_api.log"), logging.StreamHandler()])logger = logging.getLogger(__name__)# 3. 缓存配置(可选,减少重复调用)REDIS_CLIENT = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)CACHE_EXPIRE = 30 * 60  # 缓存有效期30分钟# ==================== 核心工具函数 ====================def generate_sign(params: dict) -> str:
    """生成淘宝API签名(核心步骤,严格遵循规则)"""
    try:
        # 1. 按参数名ASCII升序排序,过滤空值
        sorted_params = sorted([(k, v) for k, v in params.items() if v is not None and v != ""], key=lambda x: x[0])
        # 2. 拼接参数字符串
        sign_str = "".join([f"{k}{v}" for k, v in sorted_params])
        # 3. 首尾拼接App Secret,MD5加密转大写
        sign_str = APP_SECRET + sign_str + APP_SECRET
        sign = hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()
        return sign    except Exception as e:
        logger.error(f"生成签名失败:{str(e)}")
        raise@retry(
    stop=stop_after_attempt(3),  # 最多重试3次
    wait=wait_exponential(multiplier=1, min=2, max=5),  # 重试间隔:2s→4s→8s(最大5s)
    retry=retry_if_exception_type((requests.exceptions.Timeout, requests.exceptions.ConnectionError)),
    reraise=True  # 重试失败后抛出异常)def call_taobao_api(params: dict) -> dict:
    """调用淘宝API,包含重试机制"""
    try:
        # 添加签名
        params["sign"] = generate_sign(params)
        # 发起GET请求
        response = requests.get(
            API_URL,
            params=params,
            timeout=10,  # 超时时间10秒
            headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
        )
        response.encoding = "utf-8"
        result = response.json()
        logger.info(f"API调用返回:{json.dumps(result, ensure_ascii=False)[:200]}")  # 日志只打印前200字符
        
        # 检查调用是否成功
        if result.get("code") != 0:
            error = result["resp_data"]["error_response"]
            error_msg = f"API调用失败:{error['msg']}(错误码:{error['sub_code']})"
            logger.error(error_msg)
            raise Exception(error_msg)
        return result    except requests.exceptions.Timeout:
        logger.error("API调用超时,将重试")
        raise
    except requests.exceptions.ConnectionError:
        logger.error("API连接失败,将重试")
        raise
    except Exception as e:
        logger.error(f"API调用异常:{str(e)}")
        raisedef get_cache(key: str) -> dict | None:
    """从Redis获取缓存"""
    try:
        cache_data = REDIS_CLIENT.get(key)
        if cache_data:
            return json.loads(cache_data)
        return None
    except Exception as e:
        logger.warning(f"读取缓存失败:{str(e)}")
        return Nonedef set_cache(key: str, data: dict):
    """设置Redis缓存"""
    try:
        REDIS_CLIENT.setex(key, CACHE_EXPIRE, json.dumps(data, ensure_ascii=False))
    except Exception as e:
        logger.warning(f"设置缓存失败:{str(e)}")# ==================== 核心采集函数 ====================def collect_taobao_keyword(keyword: str, page_no: int = 1, page_size: int = 20, use_cache: bool = True) -> tuple[dict, list]:
    """
    采集淘宝关键词搜索数据
    :param keyword: 搜索关键词
    :param page_no: 页码
    :param page_size: 每页条数(最大100)
    :param use_cache: 是否使用缓存
    :return: (搜索元信息, 商品列表)
    """
    # 1. 构建缓存key
    cache_key = f"taobao_search:{keyword}:{page_no}:{page_size}"
    if use_cache:
        cache_data = get_cache(cache_key)
        if cache_data:
            logger.info(f"命中缓存:{cache_key}")
            return cache_data["meta"], cache_data["goods"]
    
    # 2. 构造API参数
    params = {
        "method": "taobao.tbk.item.search",
        "app_key": APP_KEY,
        "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
        "format": "json",
        "v": "2.0",
        "sign_method": "md5",
        "q": keyword,
        "page_no": page_no,
        "page_size": page_size,
        "sort": "sales_desc"  # 按销量降序
    }
    
    # 3. 调用API
    result = call_taobao_api(params)
    
    # 4. 解析JSON数据
    resp_data = result["resp_data"]["tbk_item_search_response"]
    # 4.1 解析元信息
    meta = {
        "总商品数": resp_data.get("total_results", 0),
        "当前页码": resp_data.get("page_no", 1),
        "每页条数": resp_data.get("page_size", 20),
        "总页数": resp_data.get("max_page", 0)
    }
    # 4.2 解析商品列表
    goods_list = []
    for item in resp_data.get("results", []):
        goods_info = {
            "商品ID": item.get("num_iid"),
            "标题": item.get("title"),
            "主图链接": item.get("pict_url"),
            "券后价": float(item.get("zk_final_price", 0)),
            "原价": float(item.get("reserve_price", 0)),
            "销量": item.get("sales", 0),
            "店铺名称": item.get("shop_title"),
            "是否天猫": item.get("is_tmall", False),
            "佣金比例": float(item.get("tk_rate", 0)) / 100,
            "发货地": item.get("provcity"),
            "商品链接": item.get("item_url")
        }
        goods_list.append(goods_info)
    
    # 5. 设置缓存
    if use_cache:
        set_cache(cache_key, {"meta": meta, "goods": goods_list})
    
    logger.info(f"采集完成:关键词[{keyword}] 页码[{page_no}] 共{len(goods_list)}条商品")
    return meta, goods_listdef batch_collect(keyword: str, max_page: int = 5, page_size: int = 20):
    """批量采集多页数据"""
    all_goods = []
    try:
        # 先获取第一页,拿到总页数
        meta, first_page_goods = collect_taobao_keyword(keyword, page_no=1, page_size=page_size)
        all_goods.extend(first_page_goods)
        total_page = min(meta["总页数"], max_page)  # 最多采集max_page页
        
        # 采集后续页码
        for page in range(2, total_page + 1):
            time.sleep(1)  # 休眠1秒,避免限流
            _, goods = collect_taobao_keyword(keyword, page_no=page, page_size=page_size)
            all_goods.extend(goods)
        
        # 保存到本地JSON文件
        with open(f"taobao_{keyword}_data.json", "w", encoding="utf-8") as f:
            json.dump({
                "关键词": keyword,
                "采集时间": time.strftime("%Y-%m-%d %H:%M:%S"),
                "总条数": len(all_goods),
                "商品列表": all_goods            }, f, ensure_ascii=False, indent=2)
        logger.info(f"批量采集完成:共{len(all_goods)}条商品,已保存到文件")
        return all_goods    except Exception as e:
        logger.error(f"批量采集失败:{str(e)}")
        return []# ==================== 调用示例 ====================if __name__ == "__main__":
    # 单页采集
    # meta, goods = collect_taobao_keyword("夏季纯棉T恤", page_no=1, page_size=20)
    # print("元信息:", json.dumps(meta, ensure_ascii=False, indent=2))
    # print("商品列表(前2条):", json.dumps(goods[:2], ensure_ascii=False, indent=2))
    
    # 批量采集(最多5页)
    batch_collect("夏季纯棉T恤", max_page=5, page_size=20)

三、关键功能说明

1. JSON 数据解析核心逻辑

  • API 返回的 JSON 数据结构分层:顶层code → resp_data → tbk_item_search_response → results(商品列表);

  • 解析时先判断code=0确认调用成功,再提取元信息(总商品数、页码)和商品明细;

  • 对价格、佣金等字符串类型字段转为float,方便后续计算。

2. 稳定性保障

  • 签名生成:严格按淘宝规则排序参数、过滤空值、MD5 加密,避免签名错误;

  • 重试机制:网络超时 / 连接失败时自动重试 3 次,间隔指数级递增;

  • 限流控制:批量采集时每页休眠 1 秒,适配淘宝 API 的 QPS 限制;

  • 缓存机制:Redis 缓存 30 分钟,减少重复调用,提升采集效率。

3. 数据存储

  • 单页采集:返回结构化的元信息和商品列表;

  • 批量采集:自动保存到本地 JSON 文件,包含采集时间、关键词、总条数等元数据。

四、返回 JSON 数据示例(本地文件)

json
{
  "关键词": "夏季纯棉T恤",
  "采集时间": "2025-12-16 15:30:00",
  "总条数": 89,
  "商品列表": [
    {
      "商品ID": "689712345678",
      "标题": "2025夏季纯棉宽松T恤男 透气百搭休闲短袖",
      "主图链接": "https://img.alicdn.com/xxx.jpg",
      "券后价": 59.9,
      "原价": 99.0,
      "销量": 12500,
      "店铺名称": "XX男装旗舰店",
      "是否天猫": true,
      "佣金比例": 0.2,
      "发货地": "浙江杭州",
      "商品链接": "https://detail.tmall.com/item.htm?id=689712345678"
    }
  ]}

五、使用注意事项

  1. 替换APP_KEYAPP_SECRET为自己在淘宝开放平台申请的信息;

  2. 若不需要缓存,可注释掉 Redis 相关代码,将use_cache设为False

  3. 批量采集max_page建议不超过 10 页,避免触发平台限流;

  4. 日志文件taobao_api.log会记录所有调用过程,便于排查异常;

  5. 商品图片链接有效期约 30 天,如需长期存储需下载到本地。

六、常见问题排查

异常类型原因解决方案
签名错误参数排序错误 / 空值参与签名 / App Secret 错误检查签名生成逻辑,过滤空参数,核对 App Secret
限流错误调用频率过高增加休眠时间,减少每页条数,使用缓存
权限错误未申请接口权限 / 权限审核未通过登录开放平台确认taobao.tbk.item.search权限状态
数据为空页码超过总页数 / 关键词无结果先判断总页数,再循环采集


群贤毕至

访客