你需要的是乐天(Rakuten)商品详情 API 接口的完整调用示例与可直接运行的代码实现,核心覆盖「单商品详情查询、批量商品查询、异常处理、数据解析」四大核心场景,以下是适配新手的极简版 + 企业级稳健版代码,兼顾易用性与生产环境稳定性。
一、 前置准备(必做)
1. 核心凭证获取
- 关注博主,可创建应用并获取Application ID(32 位字符串,所有请求必填);
- 确认接口版本:推荐使用
IchibaItem/Item 20170426(商品详情)、IchibaItem/Search 20220601(批量搜索)。
2. 环境依赖安装
仅需 Python 基础库,执行以下命令安装:
bash
运行
pip install requests # 处理HTTP请求 pip install pandas # 可选,用于批量数据处理二、 极简版调用示例(快速上手)
适合新手快速验证 API 可用性,实现单商品详情查询的核心功能:
python
运行
import requests import json # -------------------------- 配置项(替换为你的信息) -------------------------- APP_ID = "你的32位Application ID" # 替换为真实ID ITEM_CODE = "shop001:item123456" # 替换为真实商品编码(乐天商品页URL中提取) # -------------------------- 核心调用逻辑 -------------------------- def get_rakuten_item_simple(): """极简版:调用乐天商品详情API并打印结果""" # 1. 构造请求URL和参数 api_url = "https://app.rakuten.co.jp/services/api/IchibaItem/Item/20170426" params = { "applicationId": APP_ID, "itemCode": ITEM_CODE, "format": "json", # 响应格式为JSON "formatVersion": 2 # 推荐版本,结构更清晰 } # 2. 发送请求 try: response = requests.get(api_url, params=params, timeout=15) response.raise_for_status() # 抛出HTTP错误(如404/429) item_data = response.json() # 3. 解析核心字段 print("=== 乐天商品详情(极简版)===") print(f"商品编码:{item_data.get('itemCode', '未知')}") print(f"商品名称:{item_data.get('itemName', '未知')}") print(f"商品价格:{item_data.get('itemPrice', 0)} 日元") print(f"库存状态:{'有货' if item_data.get('availability') == 1 else '无货'}") print(f"店铺名称:{item_data.get('shopName', '未知')}") return item_data except Exception as e: print(f"调用失败:{e}") return None # 执行调用 if __name__ == "__main__": get_rakuten_item_simple()运行说明
- 替换
APP_ID和ITEM_CODE为真实值; - 直接运行代码,即可打印商品核心信息;
- 若报错
401 Unauthorized,检查APP_ID是否有效;若报错404,检查ITEM_CODE是否正确。
三、 企业级稳健版代码(生产环境可用)
包含频率控制、异常重试、缓存、数据清洗、批量查询等生产级特性,适配海外仓 / 选品系统对接:
python
运行
import requests import json import time import redis import random from datetime import datetime from requests.exceptions import RequestException from functools import wraps # -------------------------- 全局配置 -------------------------- # 核心凭证 APP_ID = "你的32位Application ID" # API地址 ITEM_API_URL = "https://app.rakuten.co.jp/services/api/IchibaItem/Item/20170426" SEARCH_API_URL = "https://app.rakuten.co.jp/services/api/IchibaItem/Search/20220601" # 频率控制(免费版QPS≤10,预留冗余) REQUEST_INTERVAL = 0.12 # 120ms/次 # Redis缓存配置(可选,无需缓存可注释) REDIS_CLIENT = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True) CACHE_EXPIRE = 3600 # 缓存1小时 # 代理池(可选,规避IP风控) PROXY_POOL = [ # "http://ip1:port", # "http://ip2:port" ] # -------------------------- 工具函数 -------------------------- def get_random_proxy(): """随机获取代理IP""" return random.choice(PROXY_POOL) if PROXY_POOL else None def get_headers(): """构造模拟浏览器的请求头,避免风控""" return { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36", "Accept": "application/json, text/plain, */*", "Accept-Language": "ja-JP,ja;q=0.9,en-US;q=0.8", "Referer": "https://webservice.rakuten.co.jp/" } def cache_decorator(expire=CACHE_EXPIRE): """缓存装饰器:优先从Redis读取,减少API调用""" def wrapper(func): @wraps(func) def inner(item_code): cache_key = f"rakuten:item:{item_code}" # 1. 查缓存 cached_data = REDIS_CLIENT.get(cache_key) if cached_data: return json.loads(cached_data) # 2. 缓存未命中,调用函数 result = func(item_code) # 3. 写入缓存 if result: REDIS_CLIENT.setex(cache_key, expire, json.dumps(result)) return result return inner return wrapper def request_with_retry(url, params, max_retry=3): """指数退避重试:处理429限流/503服务不可用""" retry_count = 0 while retry_count < max_retry: try: # 频率控制 time.sleep(REQUEST_INTERVAL) # 构造请求 headers = get_headers() proxy = get_random_proxy() proxies = {"http": proxy, "https": proxy} if proxy else None # 发送请求 response = requests.get( url, params=params, headers=headers, proxies=proxies, timeout=15 ) # 处理限流 if response.status_code == 429: sleep_time = 2 ** retry_count # 指数退避:1s→2s→4s print(f"触发429限流,等待{sleep_time}秒重试...") time.sleep(sleep_time) retry_count += 1 continue # 校验响应 response.raise_for_status() # 打印剩余配额(可选) remaining_quota = response.headers.get("X-API-QUOTA-REMAINING", "未知") print(f"剩余API配额:{remaining_quota}次") return response.json() except RequestException as e: print(f"请求失败(重试{retry_count+1}/{max_retry}):{e}") retry_count += 1 time.sleep(1) print("多次重试失败,放弃请求") return None # -------------------------- 核心功能:单商品详情查询 -------------------------- @cache_decorator(expire=3600) # 缓存1小时 def get_rakuten_item_detail(item_code): """ 获取单商品详情(含数据清洗) :param item_code: 乐天商品编码(shop001:item123456) :return: 清洗后的商品字典 """ params = { "applicationId": APP_ID, "itemCode": item_code, "format": "json", "formatVersion": 2, # 按需筛选字段,减少数据量 "elements": "itemCode,itemName,itemPrice,availability,weight,size,shopName,itemUrl,reviewAverage,reviewCount" } # 调用API raw_data = request_with_retry(ITEM_API_URL, params) if not raw_data: return None # 数据清洗与标准化 cleaned_data = { "商品编码": raw_data.get("itemCode", ""), "商品名称": raw_data.get("itemName", "").strip(), "售价(日元)": int(raw_data.get("itemPrice", 0)), "库存状态": "有货" if raw_data.get("availability") == 1 else "无货", "重量(g)": int(raw_data.get("weight", 0)), "规格": raw_data.get("size", "无规格").strip(), "店铺名称": raw_data.get("shopName", "未知"), "商品链接": raw_data.get("itemUrl", ""), "评价平均分": round(float(raw_data.get("reviewAverage", 0.0)), 1), "评价总数": int(raw_data.get("reviewCount", 0)), "采集时间": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } return cleaned_data # -------------------------- 扩展功能:批量商品搜索 -------------------------- def search_rakuten_items(keyword, page=1, hits=20): """ 按关键词批量搜索商品(适合选品场景) :param keyword: 搜索关键词(日文,如"ワイヤレスイヤホン"=无线耳机) :param page: 页码(1-100) :param hits: 每页条数(1-100) :return: 批量商品列表 """ params = { "applicationId": APP_ID, "keyword": keyword, "page": page, "hits": hits, "sort": "-itemPrice", # 价格降序(+itemPrice=升序) "availability": 1, # 仅返回有货商品 "format": "json", "formatVersion": 2 } # 调用API raw_data = request_with_retry(SEARCH_API_URL, params) if not raw_data or "Items" not in raw_data: return [] # 解析批量数据 item_list = [] for item in raw_data["Items"]: item_info = item.get("Item", {}) item_list.append({ "商品编码": item_info.get("itemCode", ""), "商品名称": item_info.get("itemName", "").strip(), "售价(日元)": int(item_info.get("itemPrice", 0)), "评价平均分": round(float(item_info.get("reviewAverage", 0.0)), 1), "评价总数": int(item_info.get("reviewCount", 0)) }) print(f"搜索关键词「{keyword}」:共找到{raw_data.get('count', 0)}个商品,当前页{len(item_list)}个") return item_list # -------------------------- 测试调用 -------------------------- if __name__ == "__main__": # 1. 单商品详情查询 ITEM_CODE = "shop001:item123456" # 替换为真实编码 item_detail = get_rakuten_item_detail(ITEM_CODE) if item_detail: print("\n=== 单商品详情(清洗后)===") for key, value in item_detail.items(): print(f"{key}:{value}") # 2. 批量商品搜索 # KEYWORD = "ワイヤレスイヤホン" # 日文关键词:无线耳机 # batch_items = search_rakuten_items(KEYWORD, page=1, hits=10) # if batch_items: # print("\n=== 批量搜索结果 ===") # for idx, item in enumerate(batch_items, 1): # print(f"\n{idx}. {item['商品名称']} | 价格:{item['售价(日元)']} 日元")四、 关键代码说明
| 功能模块 | 核心作用 | 新手注意点 |
|---|---|---|
cache_decorator | 缓存高频查询的商品数据,减少 API 配额消耗 | 无需 Redis 可注释该装饰器,不影响核心功能 |
request_with_retry | 处理限流 / 网络异常,提升调用稳定性 | 指数退避重试是避免 429 错误的核心 |
get_headers | 模拟真实浏览器请求头,规避隐性风控 | 缺失 Referer/User-Agent 易触发 403 错误 |
| 数据清洗 | 标准化字段格式,避免 KeyError | 所有字段用get()获取,加默认值 |
五、 常见问题与解决方案
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
401 Unauthorized | Application ID 无效 / 未启用 | 核对 ID 是否正确,确认应用已开启「楽天市場 API」权限 |
429 Too Many Requests | 超出 QPS / 日配额 | 1. 增加REQUEST_INTERVAL;2. 启用缓存;3. 错峰调用 |
404 Not Found | 商品编码错误 / 商品下架 | 核对itemCode格式(店铺代码:商品 ID),过滤无效编码 |
JSON解析失败 | 响应格式错误 | 确认format=json参数,或接口版本是否正确 |
| 商品名称乱码 | 编码问题 | 打印时添加ensure_ascii=False,如print(json.dumps(data, ensure_ascii=False)) |
总结
乐天商品详情 API 调用的核心要点:
- 凭证核心:
Application ID是所有请求的必填参数,需确保有效; - 稳定性:通过「频率控制 + 指数退避重试 + 缓存」避免触发限流 / 风控;
- 数据处理:解析时做好容错(
get()方法)和标准化,适配业务场景; - 批量场景:优先用
IchibaItem/Search接口批量查询,减少请求次数。