一、接口概述
抖音商品详情接口是抖音开放平台/电商生态中用于获取商品详细信息的核心 API,广泛应用于商品展示、比价系统、数据分析、选品工具等场景。通过该接口,开发者可以获取商品的标题、价格、图片、规格、销量、评价等完整信息。
二、接口基本信息
2.1 接口端点
GET /api/product/detail
# 或
GET /open/api/v1/product/info
注:具体端点需根据抖音开放平台最新文档确认,不同业务线(抖店、精选联盟、抖音电商等)接口路径可能不同。
2.2 请求方式
- HTTP Method: GET / POST
- Content-Type: application/json 或 application/x-www-form-urlencoded
- 协议: HTTPS(强制)
三、请求参数详解
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
app_key | string | 是 | 应用唯一标识 |
timestamp | int | 是 | 当前时间戳(秒级) |
sign | string | 是 | 请求签名(防篡改) |
product_id | string | 条件 | 商品ID(与 sku_id 二选一) |
sku_id | string | 条件 | SKU ID |
fields | string | 否 | 指定返回字段,逗号分隔 |
3.1 签名生成算法
import hashlib
import time
def generate_sign(params: dict, app_secret: str) -> str:
"""
抖音接口签名生成(通用 HMAC-SHA256 或 MD5 方式)
"""
# 1. 过滤空值,按 key 升序排序
sorted_params = sorted(
[(k, v) for k, v in params.items() if v is not None and k != 'sign']
)
# 2. 拼接字符串:key1value1key2value2...
param_str = ''.join([f"{k}{v}" for k, v in sorted_params])
# 3. 首尾拼接 app_secret
sign_str = f"{app_secret}{param_str}{app_secret}"
# 4. MD5 加密并转大写
sign = hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper()
return sign
# 使用示例
params = {
"app_key": "your_app_key",
"timestamp": int(time.time()),
"product_id": "1234567890"
}
sign = generate_sign(params, "your_app_secret")
params["sign"] = sign
四、响应数据结构
4.1 成功响应示例
{
"code": 0,
"message": "success",
"data": {
"product_id": "1234567890",
"product_name": "【官方正品】某某品牌无线蓝牙耳机 降噪长续航",
"category": {
"cat_id": 1234,
"cat_name": "数码配件",
"parent_id": 100
},
"price_info": {
"original_price": 29900,
"sale_price": 19900,
"currency": "CNY",
"price_unit": "分"
},
"inventory": {
"total_stock": 5000,
"available_stock": 3200
},
"images": [
{
"url": "https://p3.douyinpic.com/img/xxx~noop.webp",
"width": 800,
"height": 800
}
],
"sku_list": [
{
"sku_id": "sku_001",
"sku_name": "白色-标准版",
"price": 19900,
"stock": 1500,
"properties": [
{"prop_name": "颜色", "value": "白色"},
{"prop_name": "版本", "value": "标准版"}
]
}
],
"sales_info": {
"total_sales": 150000,
"month_sales": 25000,
"unit": "件"
},
"shop_info": {
"shop_id": "shop_123",
"shop_name": "某某旗舰店",
"shop_score": 4.8
},
"logistics": {
"template_id": "tpl_001",
"free_shipping": true,
"dispatch_city": "深圳市"
},
"status": 1,
"create_time": "2024-01-15T10:30:00Z",
"update_time": "2026-04-21T08:00:00Z"
}
}
4.2 错误码对照表
| 错误码 | 说明 | 处理建议 |
|---|---|---|
0 | 成功 | - |
10001 | 参数错误 | 检查必填参数及格式 |
10002 | 签名错误 | 核对签名算法及密钥 |
10003 | 商品不存在或已下架 | 确认商品 ID 有效性 |
10004 | 接口调用频次超限 | 降低请求频率,申请提额 |
10005 | 权限不足 | 检查应用权限范围 |
10006 | 服务内部错误 | 稍后重试或联系客服 |
五、实战代码示例
5.1 Python 完整调用示例
import requests
import json
import time
import hashlib
from urllib.parse import urlencode
class DouyinProductAPI:
BASE_URL = "https://open.douyin.com"
def __init__(self, app_key: str, app_secret: str):
self.app_key = app_key
self.app_secret = app_secret
def _generate_sign(self, params: dict) -> str:
sorted_params = sorted(
[(k, v) for k, v in params.items() if v is not None and k != 'sign']
)
param_str = ''.join([f"{k}{v}" for k, v in sorted_params])
sign_str = f"{self.app_secret}{param_str}{self.app_secret}"
return hashlib.md5(sign_str.encode()).hexdigest().upper()
def get_product_detail(self, product_id: str, fields: str = None) -> dict:
"""
获取商品详情
"""
params = {
"app_key": self.app_key,
"timestamp": int(time.time()),
"product_id": product_id,
}
if fields:
params["fields"] = fields
params["sign"] = self._generate_sign(params)
url = f"{self.BASE_URL}/api/product/detail"
try:
response = requests.get(
url,
params=params,
timeout=10,
headers={"Accept": "application/json"}
)
response.raise_for_status()
result = response.json()
if result.get("code") != 0:
raise Exception(f"API Error: {result.get('message')}")
return result["data"]
except requests.exceptions.RequestException as e:
raise Exception(f"Request failed: {str(e)}")
# 使用示例
if __name__ == "__main__":
api = DouyinProductAPI(
app_key="your_app_key",
app_secret="your_app_secret"
)
try:
product = api.get_product_detail(
product_id="1234567890",
fields="product_name,price_info,images,sales_info"
)
print(json.dumps(product, indent=2, ensure_ascii=False))
except Exception as e:
print(f"Error: {e}")
5.2 批量获取与并发控制
import asyncio
import aiohttp
from typing import List, Dict
class DouyinProductBatchAPI(DouyinProductAPI):
async def get_product_detail_async(
self,
session: aiohttp.ClientSession,
product_id: str
) -> Dict:
params = {
"app_key": self.app_key,
"timestamp": int(time.time()),
"product_id": product_id,
}
params["sign"] = self._generate_sign(params)
async with session.get(
f"{self.BASE_URL}/api/product/detail",
params=params,
timeout=aiohttp.ClientTimeout(total=10)
) as response:
result = await response.json()
return result.get("data", {})
async def batch_get_products(
self,
product_ids: List[str],
max_concurrent: int = 10
) -> List[Dict]:
"""
批量获取商品详情,带并发控制
"""
semaphore = asyncio.Semaphore(max_concurrent)
async def fetch_with_limit(session, pid):
async with semaphore:
return await self.get_product_detail_async(session, pid)
async with aiohttp.ClientSession() as session:
tasks = [fetch_with_limit(session, pid) for pid in product_ids]
return await asyncio.gather(*tasks)
# 批量调用示例
async def main():
api = DouyinProductBatchAPI("app_key", "app_secret")
product_ids = ["111", "222", "333", "444", "555"]
results = await api.batch_get_products(product_ids, max_concurrent=5)
print(f"成功获取 {len(results)} 个商品信息")
# asyncio.run(main())
六、关键注意事项
6.1 频率限制与限流策略
| 限制类型 | 默认值 | 说明 |
|---|---|---|
| QPS 限制 | 10-100 | 根据应用等级调整 |
| 日调用量 | 1万-100万 | 需申请提升额度 |
| 并发限制 | 视接口而定 | 建议设置熔断降级 最佳实践: |
- 使用令牌桶/漏桶算法进行客户端限流
- 实现指数退避重试机制
- 缓存热点商品数据(Redis,TTL 5-15分钟)
6.2 数据安全与合规
- 用户隐私:不得存储、传播用户敏感信息
- 数据用途:仅限授权范围内的业务使用
- 签名保护:app_secret 严禁前端暴露或硬编码
- HTTPS 强制:所有请求必须使用 TLS 1.2+
6.3 价格单位处理
抖音接口中价格通常以分为单位返回,使用时需转换:
def format_price(price_in_fen: int) -> str:
"""将分转换为元,保留两位小数"""
return f"¥{price_in_fen / 100:.2f}"
# 示例
print(format_price(19900)) # 输出: ¥199.00
七、典型应用场景
| 场景 | 实现思路 |
|---|---|
| 商品比价系统 | 定时同步多平台商品信息,建立价格监控 |
| 选品分析工具 | 抓取销量、评价数据,生成选品报告 |
| 直播带货助手 | 实时获取商品库存、价格,自动切换讲解 |
| 电商 ERP 对接 | 同步订单、库存信息,实现统一管理 |
| 数据分析平台 | 聚合商品数据,进行市场趋势分析 |
八、常见问题排查
Q1: 返回 "签名错误" 怎么办?
- 检查参数是否按 ASCII 排序
- 确认 app_secret 正确且无多余空格
- 注意 timestamp 与服务器时间差不超过 5 分钟
- Q2: 商品图片无法访问?
- 抖音图片 URL 通常带防盗链,需通过合法渠道获取
- 部分图片有有效期,建议下载后转存至自有 CDN
- Q3: 如何获取历史价格?
- 标准接口通常只返回当前价格,历史价格需自行记录
- 可结合定时任务建立价格变动数据库

