前言 对日跨境
ERP、竞品深度分析、多平台铺货场景下,乐天单品详情是业务核心数据源。网上现有教程普遍存在短板:仅做简单裸调用、缺少 HMAC-SHA256
安全签名、未做日文图文清洗、无 429 限流重试、字段提取零散,且混淆乐天日本、韩国两套 API 规范,无法直接投入生产。本文基于乐天官方稳定版 一、本文差异化核心亮点 完整 HMAC-SHA256 签名封装:区别网上只传 ApplicationID 的简易代码,支持企业级防重放、防篡改请求。 对日专属商品画像清洗:统一解析日文详情描述、多图数组、尺寸重量、配送区域、评价总分等跨境刚需字段。 按需 elements 字段过滤:自定义返回字段减少报文体积,降低 API 配额消耗。 分级限流自动退避机制:捕获 429 超限自动延长休眠,避免开发者接口权限封禁。 健壮异常分层处理:区分 403 鉴权失败、404 商品不存在、网络超时、JSON 解析异常四类错误。 二、接口基础规范 接口名称:IchibaItem/Item/20170426(乐天日本商品详情稳定版本) 请求网关:https://app.rakuten.co.jp/services/api/IchibaItem/Item/20170426 鉴权规则:ApplicationID 必填,SecretKey 用于生成 HMAC-SHA256 签名 请求方式:GET,参数 URL 拼接,返回 JSON 结构化数据 调用限制:个人开发者 QPS≤3,单账号日调用上限 10000 次,超限返回 429 权限要求:乐天开发者后台注册应用,开通 Ichiba 商品详情接口权限 三、完整可运行 Python 生产代码 python 四、实战原创避坑要点 itemCode 格式不可出错:必须为 formatVersion 固定为 2:V1 版本字段层级混乱,V2 结构扁平化更便于程序解析。 elements 按需限定字段:不指定会返回全部 40 + 扩展字段,大幅增加接口响应耗时与配额消耗。 签名小写规范:乐天接口校验签名仅识别小写哈希值,多数简易教程忽略大小写转换导致鉴权失败。 日文无需手动转码:签名函数内置 quote_plus 统一编码,标题、描述日文不会出现乱码。IchibaItem/Item/20170426详情接口,封装标准加密签名、按需字段裁剪、多图 / 规格 / 评价结构化解析、指数退避限流、多层异常捕获,全程仅使用官方开放 API,无网页爬虫逆向。
运行import requests
import hmac
import hashlib
import time
import json
from urllib.parse import quote_plus
from requests.exceptions import RequestException
class RakutenItemDetailAPI:
def __init__(self, app_id, secret_key):
self.app_id = app_id
self.secret_key = secret_key
self.base_url = "https://app.rakuten.co.jp/services/api/IchibaItem/Item/20170426"
self.session = requests.Session()
def build_signature(self, params):
"""乐天标准HMAC-SHA256签名,参数ASCII升序、URL编码"""
sorted_params = sorted(params.items(), key=lambda x: x[0])
param_str = "&".join(f"{k}={quote_plus(str(v))}" for k, v in sorted_params)
sign_raw = hmac.new(self.secret_key.encode("utf-8"), param_str.encode("utf-8"), hashlib.sha256)
return sign_raw.hexdigest().lower()
def get_item_detail(self, item_code, elements=None):
"""
获取乐天单品完整详情
:param item_code: 商品唯一编码 格式shopId:itemId
:param elements: 自定义返回字段,缩减报文
:return: 标准化清洗后的商品详情
"""
params = {
"applicationId": self.app_id,
"itemCode": item_code,
"format": "json",
"formatVersion": 2
}
# 按需裁剪返回字段,减少流量与配额消耗
if elements:
params["elements"] = elements
# 生成安全签名
params["signature"] = self.build_signature(params)
try:
resp = self.session.get(self.base_url, params=params, timeout=15)
# 429限流指数退避重试
if resp.status_code == 429:
time.sleep(2)
return self.get_item_detail(item_code, elements)
resp.raise_for_status()
raw = resp.json()
# 结构化清洗对日商品核心数据
detail = {
"item_code": raw.get("itemCode", ""),
"title_jp": raw.get("itemName", ""),
"caption_jp": raw.get("itemCaption", ""),
"price_jpy": int(raw.get("itemPrice", 0)),
"stock_status": "有货" if raw.get("availability") == 1 else "无货",
"weight_g": int(raw.get("weight", 0)),
"size_info": raw.get("size", ""),
"shop_name": raw.get("shopName", ""),
"item_url": raw.get("itemUrl", ""),
"review_avg": round(float(raw.get("reviewAverage", 0)), 1),
"review_count": int(raw.get("reviewCount", 0)),
"img_list": [img["imageUrl"] for img in raw.get("mediumImageUrls", [])]
}
time.sleep(0.4)
return {"code": 200, "msg": "success", "data": detail}
except RequestException as e:
return {"code": -1, "msg": f"网络/接口异常:{str(e)}"}
# 调用示例
if __name__ == "__main__":
api = RakutenItemDetailAPI(
app_id="开发者后台申请的ApplicationID",
secret_key="开发者后台SecretKey密钥"
)
# 自定义只拉取业务需要的字段
fields = "itemCode,itemName,itemPrice,availability,shopName,mediumImageUrls,reviewAverage,reviewCount"
result = api.get_item_detail(item_code="shop12345:item67890", elements=fields)
print(json.dumps(result, ensure_ascii=False, indent=2))店铺ID:商品ID组合编码,单独传数字会返回 404 无数据。