×

api开发 电商平台 数据挖掘

「代码实战」如何优雅地调用淘宝 API?封装一个可复用的商品信息获取类

admin admin 发表于2025-10-14 10:47:31 浏览36 评论0

抢沙发发表评论

在电商开发场景中,调用淘宝 API 获取商品信息是常见需求,但直接编写原生请求代码易出现冗余、维护难等问题。本文将通过 Python 语言,实战演示如何封装一个可复用的商品信息获取类,实现参数统一管理、请求异常处理、数据格式标准化,让 API 调用更优雅、更高效。

一、前期准备:淘宝 API 接入基础

在封装类之前,需完成淘宝 API 的接入准备,确保调用权限和参数正确。

1. 核心前置条件

  • 申请 API 权限:获取ApiKeyApiSecret

  • 了解接口规范:明确目标接口的请求方式(如 GET/POST)、必填参数(如商品 IDnum_iid)、返回格式(通常为 JSON),参考淘宝开放平台官方接口文档。

  • 安装依赖库:使用requests库发送 HTTP 请求,pycryptodome库处理 API 签名(淘宝 API 需签名验证),执行以下命令安装:

pip install requests pycryptodome

二、核心思路:可复用类的设计原则

为确保类的复用性和可维护性,设计时遵循以下 3 个原则:

  1. 参数分离:将固定配置(如App Key、接口地址)与动态参数(如商品 ID)分离,通过初始化方法传入固定配置,查询方法传入动态参数。

  2. 异常统一处理:捕获网络错误、参数缺失、API 返回错误等常见异常,返回标准化的结果(成功 / 失败标识 + 数据 / 错误信息),避免上层调用崩溃。

  3. 单一职责:类仅负责 “淘宝商品信息获取” 相关逻辑,不掺杂数据存储、业务计算等其他功能,便于后续扩展(如新增库存查询方法)。

三、代码实战:封装淘宝商品信息获取类

1. 完整代码实现

import requests
import time
import hashlib
from urllib.parse import urlencode
from typing import Dict, Optional, Tuple


class TaobaoProductApi:
    """淘宝商品信息获取工具类,支持获取商品详情、价格等信息"""
    
    def __init__(self, app_key: str, app_secret: str):
        """
        初始化淘宝API配置
        :param app_key: 淘宝开放平台申请的App Key
        :param app_secret: 淘宝开放平台申请的App Secret
        """
        # 固定配置:接口基础地址、请求超时时间
        self.app_key = app_key
        self.app_secret = app_secret
        self.base_url = "https://eco.taobao.com/router/rest"  # 淘宝API公共网关
        self.timeout = 10  # 请求超时时间(秒)

    def _generate_sign(self, params: Dict) -> str:
        """
        生成淘宝API所需的签名(签名规则:参数按key排序→拼接→加secret→MD5加密→转大写)
        :param params: 待签名的请求参数
        :return: 签名字符串
        """
        # 1. 按参数key的ASCII码升序排序
        sorted_params = sorted(params.items(), key=lambda x: x[0])
        # 2. 拼接为"key=value&key=value"格式
        param_str = urlencode(sorted_params)
        # 3. 拼接App Secret,生成签名
        sign_str = self.app_secret + param_str + self.app_secret
        # 4. MD5加密并转为大写
        sign = hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()
        return sign

    def _create_common_params(self, method: str) -> Dict:
        """
        创建淘宝API的公共请求参数(所有接口均需携带)
        :param method: 接口名称(如"taobao.item.get"表示获取商品详情)
        :return: 公共参数字典
        """
        return {
            "app_key": self.app_key,
            "method": method,
            "format": "json",  # 返回格式
            "v": "2.0",  # API版本
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),  # 当前时间
            "sign_method": "md5"  # 签名方式
        }

    def get_product_detail(self, num_iid: str) -> Tuple[bool, Optional[Dict]]:
        """
        获取商品详情信息(调用taobao.item.get接口)
        :param num_iid: 商品ID(淘宝商品的唯一标识)
        :return: (是否成功, 数据/错误信息):成功时返回(True, 商品详情字典),失败时返回(False, 错误描述)
        """
        try:
            # 1. 检查必填参数
            if not num_iid.strip():
                return False, "商品ID(num_iid)不能为空"
            
            # 2. 构建请求参数(公共参数+接口私有参数)
            method = "taobao.item.get"
            common_params = self._create_common_params(method)
            private_params = {
                "num_iid": num_iid,
                "fields": "num_iid,title,price,pic_url,detail_url,stock"  # 需要返回的字段
            }
            all_params = {**common_params, **private_params}
            
            # 3. 生成签名并添加到参数中
            all_params["sign"] = self._generate_sign(all_params)
            
            # 4. 发送GET请求
            response = requests.get(
                url=self.base_url,
                params=all_params,
                timeout=self.timeout
            )
            response.raise_for_status()  # 若状态码非200,抛出HTTPError
            
            # 5. 解析返回结果
            result = response.json()
            # 淘宝API成功时返回"item_get_response",失败时返回"error_response"
            if "error_response" in result:
                error_msg = result["error_response"]["msg"]
                return False, f"API返回错误:{error_msg}"
            product_data = result["item_get_response"]["item"]
            return True, product_data
        
        except requests.exceptions.RequestException as e:
            # 捕获网络异常(超时、连接失败等)
            return False, f"网络请求错误:{str(e)}"
        except Exception as e:
            # 捕获其他未知异常
            return False, f"未知错误:{str(e)}"


# ------------------- 类的使用示例 -------------------
if __name__ == "__main__":
    # 1. 替换为自己的App Key和App Secret
    APP_KEY = "你的淘宝App Key"
    APP_SECRET = "你的淘宝App Secret"
    
    # 2. 初始化API工具类
    taobao_api = TaobaoProductApi(app_key=APP_KEY, app_secret=APP_SECRET)
    
    # 3. 获取指定商品详情(示例商品ID:自行替换为真实有效ID)
    product_id = "612345678901"  # 注意:需使用有权限访问的商品ID
    success, data = taobao_api.get_product_detail(num_iid=product_id)
    
    # 4. 处理结果
    if success:
        print("商品详情获取成功:")
        print(f"商品标题:{data['title']}")
        print(f"商品价格:{data['price']}元")
        print(f"商品图片:{data['pic_url']}")
        print(f"商品库存:{data['stock']}件")
    else:
        print(f"商品详情获取失败:{data}")

2. 代码核心模块解析

(1)签名生成方法_generate_sign

淘宝 API 要求所有请求参数需经过签名验证,防止参数被篡改。该方法按以下步骤生成签名:

  1. 对请求参数按key的 ASCII 码升序排序;

  2. 拼接为key=value&key=value格式;

  3. 在拼接字符串前后添加App Secret

  4. 通过 MD5 加密并转为大写,得到最终签名。

(2)公共参数方法_create_common_params

所有淘宝 API 接口均需携带公共参数(如app_keytimestamp),该方法统一生成这些参数,避免重复编写。

(3)商品详情查询方法get_product_detail

该方法是类的核心业务方法,流程如下:

  1. 校验必填参数(商品 ID);

  2. 合并公共参数与接口私有参数;

  3. 生成签名并发送请求;

  4. 捕获异常并解析返回结果,返回标准化的成功 / 失败信息。

四、类的扩展与优化建议

  1. 新增接口方法:若需获取商品价格、销量等其他信息,可参考get_product_detail方法,新增get_product_priceget_product_sales等方法,只需修改method(接口名称)和private_params(私有参数)。

  2. 添加请求重试机制:在网络不稳定场景下,可引入tenacity库,为请求添加重试逻辑(如重试 3 次,每次间隔 2 秒)。

  3. 参数缓存:对高频查询的商品 ID,可添加本地缓存(如使用lru_cache装饰器),减少重复 API 调用,降低接口费用。

  4. 日志记录:引入logging库,将请求日志、错误日志记录到文件,便于问题排查。

五、注意事项

  1. API 权限与配额:淘宝开放平台对 API 调用有配额限制(如免费应用每日调用次数有限),需合理规划调用频率,避免超限。

  2. 参数安全App Secret属于敏感信息,请勿硬编码到代码中,建议通过环境变量或配置文件读取。

  3. 接口版本:本文使用淘宝 API 2.0 版本,若后续接口版本更新,需同步调整v参数和返回结果解析逻辑。


少长咸集

群贤毕至

访客