import requestsimport timeimport hashlibimport jsonimport osclass TaobaoOrderAPI:def __init__(self):# 从环境变量取密钥(生产环境必用这种方式)self.app_key = os.getenv("TAOBAO_APP_KEY") or "你的app_key"self.app_secret = os.getenv("TAOBAO_APP_SECRET") or "你的app_secret"self.redirect_uri = "https://你的域名.com/callback" # 必须和开放平台配置一致# Token相关参数初始化self.access_token = Noneself.refresh_token = Noneself.token_expire_time = 0 # 过期时间戳# 接口固定地址(2025年无变更)self.auth_url = "https://oauth.taobao.com/authorize"self.token_url = "https://oauth.taobao.com/token"self.api_url = "https://eco.taobao.com/router/rest"def get_authorize_url(self):"""生成授权链接,发给商家扫码"""params = {"response_type": "code","client_id": self.app_key,"redirect_uri": self.redirect_uri,"view": "web" # 电脑端用web,手机端换wap}query_str = '&'.join([f"{k}={v}" for k, v in params.items()])return f"{self.auth_url}?{query_str}"def get_access_token(self, code):"""用授权码换Token(有效期30天)"""params = {"grant_type": "authorization_code","client_id": self.app_key,"client_secret": self.app_secret,"code": code,"redirect_uri": self.redirect_uri}response = requests.post(self.token_url, data=params)result = response.json()if "access_token" in result:self.access_token = result["access_token"]self.refresh_token = result["refresh_token"] # 用于后续刷新self.token_expire_time = int(time.time()) + result["expires_in"]print("Token获取成功,30天内有效")return resultelse:raise Exception(f"授权失败:{result.get('error_description')}")def refresh_access_token(self):"""Token快过期时自动刷新"""if not self.refresh_token:raise Exception("请先完成授权获取refresh_token")# 提前10分钟(600秒)刷新,防止过期瞬间报错if time.time() + 600 > self.token_expire_time:params = {"grant_type": "refresh_token","client_id": self.app_key,"client_secret": self.app_secret,"refresh_token": self.refresh_token}result = requests.post(self.token_url, data=params).json()if "access_token" in result:self.access_token = result["access_token"]self.token_expire_time = int(time.time()) + result["expires_in"]return {"状态": "成功", "说明": "Token已刷新"}else:raise Exception(f"刷新失败:{result.get('error_description')}")return {"状态": "跳过", "说明": "Token未过期"}def generate_sign(self, params):"""生成签名(90%新手栽坑的地方)"""# 1. 参数按ASCII升序排序sorted_params = sorted(params.items(), key=lambda x: x[0])# 2. 拼接字符串(首尾加app_secret,跳过空值)sign_str = self.app_secretfor k, v in sorted_params:if k != "sign" and v is not None:sign_str += f"{k}{v}"sign_str += self.app_secret# 3. MD5加密转大写return hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()def get_orders(self, start_time, end_time, status="WAIT_SELLER_SEND_GOODS"):"""获取订单列表(2025年最新参数):param status: 订单状态,可选待支付(WAIT_BUYER_PAY)、已完成(TRADE_FINISHED)"""# 先检查Token状态self.refresh_access_token()# 公共参数(所有接口必传)public_params = {"method": "taobao.trades.sold.get","app_key": self.app_key,"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), # 格式必须严格"format": "json","v": "2.0","sign_method": "md5","session": self.access_token}# 业务参数(fields选必填字段,减少数据量)biz_params = {"fields": "tid,title,status,payment,created,receiver_name,receiver_mobile","start_created": start_time,"end_created": end_time,"status": status,"page_size": 50, # 最多100条/页"use_has_next": True # 分页标识,防止漏单}# 合并参数生成签名all_params = {**public_params, **biz_params}all_params["sign"] = self.generate_sign(all_params)# 发送请求response = requests.post(self.api_url, data=all_params)return response.json()if __name__ == "__main__":api = TaobaoOrderAPI()# 1. 生成授权链接(初始使用阶段)print("授权链接:", api.get_authorize_url())code = input("请输入授权码:") # 商家授权后获取api.get_access_token(code)# 2. 拉取指定时间的待发货订单orders = api.get_orders(start_time="2025-10-01 00:00:00",end_time="2025-10-15 23:59:59")# 3. 解析结果if "trades_sold_get_response" in orders:trade_list = orders["trades_sold_get_response"]["trades"]["trade"]print(f"成功获取{len(trade_list)}笔订单")for trade in trade_list:print(f"订单号:{trade['tid']} | 金额:{trade['payment']} | 收件人:{trade['receiver_name']}")else:print("获取失败:", orders.get("error_response"))|
问题类型 |
错误提示 |
解决方案 |
|
签名错误 |
40001: 签名错误 |
1. 检查参数是否升序排序;2. 中文参数用 UTF-8 编码;3. 空值参数直接删除 |
|
Token 失效 |
110: Invalid session |
1. 务必保存 refresh_token;2. 实现自动刷新(提前 10 分钟);3. 定期备份 Token |
|
查询范围超限 |
订单不存在或已过期 |
1. 仅查询最近 3 个月数据;2. 时间格式严格为YYYY-MM-DD HH:mm:ss |
|
权限不足 |
15: 权限不足 |
1. 确认应用已申请目标接口权限;2. 用企业账号申请高阶权限 |
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047598/viewspace-3097729/ ,如需转载,请注明出处,否则将追究法律责任。