虾皮(Shopee)作为东南亚及台湾地区领先的电商平台,其开放平台提供了完善的 API 接口,支持商品管理、订单处理、价格查询等功能。以下基于官方 API 进行深度分析,并实现 Python 调用方案,重点获取商品价格及优惠信息(到手价)。
### 一、虾皮 API 核心特性分析
#### 1. 接口体系与功能域
虾皮开放平台 API 按功能分为以下核心域:
- **商品管理**:商品列表、商品详情、价格更新等;
- **促销管理**:折扣活动、优惠券;
- **订单管理**:订单列表、订单详情、物流信息等;
- **店铺管理**:店铺信息、运营数据统计等。
获取商品 “到手价”(含折扣、优惠券后的最终价格)主要依赖**商品详情接口**和**促销接口**的组合调用。
#### 2. 认证与请求规范
- **认证机制**:采用`partner_id + shopid + timestamp + signature`认证:
- `partner_id`:开发者 ID(从开放平台获取);
- `shopid`:店铺 ID(需绑定店铺授权);
- `timestamp`:请求时间戳(秒级,与服务器时间误差≤15 分钟);
- `signature`:签名(通过`partner_key`对请求参数加密生成)。
- **请求格式**:支持 GET/POST,参数以 JSON 或表单形式传递,响应为 JSON 格式;
- **区域差异**:不同站点(如新加坡、台湾、马来西亚)有独立 API 网关,例如:
- 新加坡站:
- 台湾站:
#### 3. 核心接口参数与响应(以商品详情为例)
- **接口名称**:`/api/v2/item/get`(获取商品详情)
- **请求参数**:
- `item_id`:商品 ID(必填);
- `partner_id`、`shopid`、`timestamp`、`signature`(认证参数)。
- **响应核心字段**:
- `price`:商品原价(单位:分,对应站点货币,如新台币、马来西亚令吉);
- `discount_price`:折扣价(如有活动);
- `promotion_id`:关联的促销活动 ID(用于查询详细优惠)。
### 二、Python 脚本实现:虾皮 API 调用框架
以下实现基于官方 API,支持商品详情查询及到手价计算,包含签名生成、接口调用及响应解析。
import requests
import json
import time
import hashlib
import logging
from typing import Dict, Optional, Tuple
from requests.exceptions import RequestException
# 配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
class ShopeeAPI:
def __init__(self, partner_id: int, partner_key: str, shopid: int, region: str = "sg"):
"""
初始化虾皮API客户端
:param partner_id: 开发者partner_id(从开放平台获取)
:param partner_key: 开发者partner_key(密钥)
:param shopid: 店铺ID(需提前授权)
:param region: 站点区域(sg:新加坡, tw:台湾, my:马来西亚等)
"""
self.partner_id = partner_id
self.partner_key = partner_key
self.shopid = shopid
self.region = region
# 不同区域的API网关
self.gateways = {
"sg": "https://partner.shopeemobile.com",
"tw": "https://partner.shopee.tw",
"my": "https://partner.shopee.com.my",
"th": "https://partner.shopee.co.th"
}
self.base_url = self.gateways.get(region, self.gateways["sg"])
self.session = requests.Session()
def _generate_signature(self, params: Dict) -> str:
"""
生成签名(虾皮API签名规则)
规则:将所有参数按key升序排序,拼接为key=value&key=value格式,
末尾拼接partner_key,通过SHA256加密
"""
# 1. 按参数名ASCII升序排序
sorted_params = sorted(params.items(), key=lambda x: x[0])
# 2. 拼接为key=value&key=value格式
sign_str = "&".join([f"{k}={v}" for k, v in sorted_params])
# 3. 拼接partner_key并SHA256加密
sign_str += self.partner_key
return hashlib.sha256(sign_str.encode("utf-8")).hexdigest()
def _get_timestamp(self) -> int:
"""生成秒级时间戳"""
return int(time.time())
def call_api(self, path: str, params: Dict) -> Optional[Dict]:
"""
通用API调用方法
:param path: 接口路径(如/api/v2/item/get)
:param params: 业务参数
:return: 接口响应数据
"""
# 1. 构建基础参数(认证信息)
base_params = {
"partner_id": self.partner_id,
"shopid": self.shopid,
"timestamp": self._get_timestamp()
}
# 2. 合并业务参数
all_params = {**base_params,** params}
# 3. 生成签名
signature = self._generate_signature(all_params)
all_params["signature"] = signature
# 4. 发送请求(虾皮API以GET为主,部分接口支持POST)
url = f"{self.base_url}{path}"
try:
response = self.session.get(
url,
params=all_params,
timeout=15
)
response.raise_for_status()
result = response.json()
# 5. 处理错误响应(虾皮API错误码在error字段)
if "error" in result and result["error"] != 0:
logging.error(f"API错误:{result.get('message')}(错误码:{result['error']})")
return None
logging.info(f"API调用成功:{path},响应长度:{len(json.dumps(result))}")
return result
except RequestException as e:
logging.error(f"请求异常:{str(e)},接口:{path}")
return None
except json.JSONDecodeError:
logging.error(f"响应格式错误:{response.text[:200]}...,接口:{path}")
return None
def get_item_detail(self, item_id: int) -> Optional[Dict]:
"""
获取商品详情(含价格、折扣信息)
:param item_id: 商品ID
:return: 商品详情字典
"""
path = "/api/v2/item/get"
params = {"item_id": item_id}
result = self.call_api(path, params)
if not result or "item" not in result:
return None
item = result["item"]
# 价格单位转换(分→元)
price = item.get("price") / 100 if item.get("price") else None
discount_price = item.get("discount_price") / 100 if item.get("discount_price") else None
# 提取促销ID(用于查询详细优惠规则)
promotion_id = item.get("promotion_id")
return {
"item_id": item_id,
"name": item.get("name"),
"price": price, # 原价
"discount_price": discount_price, # 折扣价(可能为到手价)
"currency": item.get("currency"), # 货币单位(如TWD、SGD)
"stock": item.get("stock"), # 库存
"promotion_id": promotion_id,
"image_url": item.get("image") # 主图URL
}
def get_promotion_detail(self, promotion_id: int) -> Optional[Dict]:
"""
获取促销活动详情(用于计算最终到手价)
:param promotion_id: 促销活动ID(从商品详情获取)
:return: 促销详情
"""
if not promotion_id:
return None
path = "/api/v2/promotion/discount/get"
params = {"promotion_id": promotion_id}
result = self.call_api(path, params)
if not result or "promotion" not in result:
return None
promotion = result["promotion"]
return {
"promotion_id": promotion_id,
"type": promotion.get("promotion_type"), # 促销类型(如限时折扣)
"discount_rate": promotion.get("discount_rate"), # 折扣率(百分比)
"start_time": promotion.get("start_time"),
"end_time": promotion.get("end_time")
}
def calculate_final_price(self, item_id: int) -> Tuple[Optional[float], Optional[Dict]]:
"""
计算商品到手价(综合原价、折扣、促销)
:param item_id: 商品ID
:return: 到手价 + 价格详情
"""
item_detail = self.get_item_detail(item_id)
if not item_detail:
return None, None
# 到手价优先取折扣价,若无则取原价
final_price = item_detail["discount_price"] or item_detail["price"]
promotion_detail = None
# 若有促销活动,进一步补充信息
if item_detail["promotion_id"]:
promotion_detail = self.get_promotion_detail(item_detail["promotion_id"])
# 部分促销可能叠加折扣(如额外9折)
if promotion_detail and promotion_detail.get("discount_rate"):
discount_rate = promotion_detail["discount_rate"] / 100 # 转换为小数
final_price = final_price * discount_rate
price_info = {
"original_price": item_detail["price"],
"discount_price": item_detail["discount_price"],
"final_price": round(final_price, 2),
"currency": item_detail["currency"],
"promotion": promotion_detail
}
return price_info["final_price"], price_info
# 示例调用
if __name__ == "__main__":
# 替换为实际参数(从虾皮开放平台获取)
PARTNER_ID = 123456 # 你的partner_id
PARTNER_KEY = "your_partner_key" # 你的partner_key
SHOPID = 789012 # 授权的店铺ID
REGION = "tw" # 台湾站
# 初始化客户端
shopee_api = ShopeeAPI(
partner_id=PARTNER_ID,
partner_key=PARTNER_KEY,
shopid=SHOPID,
region=REGION
)
# 示例商品ID(需替换为目标店铺的实际商品ID)
ITEM_ID = 123456789
# 获取商品到手价
final_price, price_info = shopee_api.calculate_final_price(ITEM_ID)
if price_info:
print(f"商品名称:{shopee_api.get_item_detail(ITEM_ID)['name']}")
print(f"原价:{price_info['original_price']} {price_info['currency']}")
print(f"折扣价:{price_info['discount_price'] or '无'} {price_info['currency']}")
print(f"到手价:{price_info['final_price']} {price_info['currency']}")
if price_info["promotion"]:
print(f"促销活动:{price_info['promotion']['type']}({price_info['promotion']['discount_rate']}折)")
print(f"活动时间:{price_info['promotion']['start_time']} 至 {price_info['promotion']['end_time']}")
### 三、关键技术点解析
#### 1. 签名生成逻辑
虾皮 API 签名是核心安全机制,实现步骤:
1. 收集所有请求参数(含`partner_id`、`shopid`、`timestamp`及业务参数);
1. 按参数名 ASCII 码升序排序;
1. 拼接为`key=value&key=value`格式;
1. 末尾拼接`partner_key`,通过 SHA256 加密生成签名;
1. 将签名作为`signature`参数加入请求。
#### 2. 价格计算逻辑
“到手价” 计算需综合以下因素:
- **原价(`price`)** :商品基础价格,单位为 “分”(需除以 100 转换为元);
- **折扣价(`discount_price`)** :商品参与基础折扣后的价格(如店铺日常折扣);
- **促销活动**:通过`promotion_id`查询详细促销(如限时折扣、满减),可能存在叠加折扣(如额外 9 折)
最终到手价 = 折扣价(或原价) × 促销折扣率(如有)。
#### 3. 区域与货币处理
- 虾皮各站点使用不同货币(如台湾站为新台币 TWD,新加坡站为新加坡元 SGD),响应中`currency`字段标识货币类型;
- API 网关需匹配对应区域(通过`region`参数指定),否则会导致请求失败。
### 四、使用注意事项
1. **权限申请**:需在注册开发者账号,创建应用并绑定店铺(获取`shopid`);
1. **接口限制**:
- 单 IP QPS 限制为 100(不同接口可能不同);
- 部分接口(如促销详情)需额外申请权限;
1. **时间同步**:`timestamp`需与虾皮服务器时间误差≤15 分钟,否则签名验证失败;
1. **错误处理**:常见错误码如`1001`(签名错误)、`1002`(参数缺失),需根据响应信息调试。
该实现基于官方 API,稳定性和合规性有保障,适用于跨境电商数据分析、店铺运营工具等场景。通过扩展可支持批量商品查询、价格监控等功能,实际使用需参考调整参数和接口。