乐天(Letian)商品详情API接口的调用示例与代码实现

你需要的是乐天(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()

运行说明

  1. 替换 APP_IDITEM_CODE 为真实值;
  2. 直接运行代码,即可打印商品核心信息;
  3. 若报错 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 调用的核心要点:

  1. 凭证核心Application ID是所有请求的必填参数,需确保有效;
  2. 稳定性:通过「频率控制 + 指数退避重试 + 缓存」避免触发限流 / 风控;
  3. 数据处理 :解析时做好容错(get()方法)和标准化,适配业务场景;
  4. 批量场景 :优先用IchibaItem/Search接口批量查询,减少请求次数。
相关推荐
DARLING Zero two♡2 小时前
【计算机网络】简学深悟启示录:序列化&&反序列化
开发语言·计算机网络·php
南 阳2 小时前
Python从入门到精通day10
linux·windows·python
mftang2 小时前
Python 获取当前目录的多种方法
python
一位搞嵌入式的 genius2 小时前
深入理解 JavaScript 原型与继承:从基础到进阶
开发语言·前端·javascript
晨非辰2 小时前
C++波澜壮阔40年|类和对象篇:拷贝构造与赋值重载的演进与实现
运维·开发语言·c++·人工智能·后端·python·深度学习
多米Domi0112 小时前
0x3f 第36天 外卖8,9,树
数据结构·python·算法·leetcode
天才测试猿2 小时前
Chrome浏览器+Postman做接口测试
自动化测试·软件测试·python·测试工具·测试用例·接口测试·postman
zckui2 小时前
conda常用命令
python·conda
张3蜂2 小时前
Label-Studio图片标注初体验
python·开源