淘宝 item_review_show 接口深度分析 接口功能与定位

[item_review_show] 接口是淘宝开放平台提供的用于获取商品买家秀内容的接口。买家秀作为消费者购物决策的重要参考,包含了丰富的用户生成内容,如晒图、视频、评价文字等,对于电商分析、商品优化、用户体验提升等场景具有重要价值。 该接口返回的数据特点:

  • 包含真实买家上传的商品实拍图和视频
  • 带有详细的使用体验描述和评价
  • 包含购买规格、使用场景等信息
  • 部分数据带有其他用户的互动(点赞、评论)信息

接口核心参数与响应结构

请求参数

参数名 类型 是否必填 说明
item_id String 商品 ID
page Integer 页码,默认 1
page_size Integer 每页条数,默认 20,最大 50
sort String 排序方式:newest (最新)、hot (最热)
has_image Boolean 是否只看有图评价,默认 false
has_video Boolean 是否只看有视频评价,默认 false
appkey String 应用密钥
session String 用户会话

响应核心字段

  • 分页信息:总条数、总页数、当前页码

  • 买家秀列表:每条包含

    • 基础信息:评价 ID、用户昵称、用户等级
    • 内容信息:评价文字、评分、发布时间
    • 多媒体:图片 URL 列表、视频 URL
    • 商品信息:购买规格、使用感受
    • 互动数据:点赞数、评论数

Python 实现 import requests import time import json import logging import re import os from typing import Dict, Optional, List from requests.exceptions import RequestException from PIL import Image from io import BytesIO import matplotlib.pyplot as plt import numpy as np from collections import defaultdict

配置日志 logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" )

class TaobaoItemReviewShowAPI: def init (self, appkey: str, session: str): """ 初始化淘宝买家秀API客户端 :param appkey: 淘宝开放平台appkey :param session: 用户会话 """ self.appkey = appkey self.session = session self.base_url = "eco.taobao.com/router/rest" self.session = requests.Session() self.session.headers.update({ "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" })

python 复制代码
def get_item_reviews(self, 
                    item_id: str, 
                    page: int = 1, 
                    page_size: int = 20,
                    sort: str = "newest",
                    has_image: bool = False,
                    has_video: bool = False) -> Optional[Dict]:
    """
    获取商品买家秀
    :param item_id: 商品ID
    :param page: 页码
    :param page_size: 每页条数
    :param sort: 排序方式
    :param has_image: 是否只看有图评价
    :param has_video: 是否只看有视频评价
    :return: 买家秀数据
    """
    # 验证参数
    valid_sorts = ["newest", "hot"]
    if sort not in valid_sorts:
        logging.error(f"无效的排序方式: {sort},支持: {valid_sorts}")
        return None
        
    if page_size < 1 or page_size > 50:
        logging.error(f"每页条数必须在1-50之间,当前为: {page_size}")
        return None
        
    # 构建参数
    params = {
        "method": "taobao.item.review.show",
        "app_key": self.appkey,
        "session": self.session,
        "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
        "format": "json",
        "v": "2.0",
        "item_id": item_id,
        "page": page,
        "page_size": page_size,
        "sort": sort,
        "has_image": "true" if has_image else "false",
        "has_video": "true" if has_video else "false"
    }
    
    try:
        response = self.session.post(self.base_url, data=params, timeout=15)
        response.raise_for_status()
        result = response.json()
        
        if "error_response" in result:
            logging.error(f"获取买家秀失败: {result['error_response']['msg']} (错误码: {result['error_response']['code']})")
            return None
            
        reviews_data = result.get("item_review_show_response", {}).get("reviews", {})
        
        if not reviews_data:
            logging.warning("未获取到买家秀数据")
            return None
            
        # 格式化买家秀数据
        return self._format_review_data(reviews_data)
        
    except RequestException as e:
        logging.error(f"获取买家秀请求异常: {str(e)}")
        return None
    except json.JSONDecodeError:
        logging.error(f"买家秀响应解析失败: {response.text[:200]}...")
        return None

def _format_review_data(self, review_data: Dict) -> Dict:
    """格式化买家秀数据"""
    # 分页信息
    pagination = {
        "total_count": int(review_data.get("total", 0)),
        "total_pages": (int(review_data.get("total", 0)) + int(review_data.get("page_size", 20)) - 1) // int(review_data.get("page_size", 20)),
        "current_page": int(review_data.get("page", 1)),
        "page_size": int(review_data.get("page_size", 20))
    }
    
    # 格式化买家秀列表
    reviews = []
    for review in review_data.get("review_list", []):
        # 处理评价内容
        content = self._clean_text(review.get("content", ""))
        
        # 处理图片
        images = []
        if review.get("pics"):
            images = [pic.get("url") for pic in review.get("pics") if pic.get("url")]
        
        # 处理视频
        video = None
        if review.get("video"):
            video = {
                "url": review["video"].get("url"),
                "duration": review["video"].get("duration"),
                "cover_url": review["video"].get("cover_url")
            }
        
        # 处理规格信息
        sku_info = {}
        if review.get("sku"):
            sku_info = {
                "properties": review.get("sku", ""),
                "property_names": review.get("sku_info", "")
            }
        
        reviews.append({
            "review_id": review.get("review_id"),
            "user": {
                "nickname": review.get("nick"),
                "avatar": review.get("avatar"),
                "level": review.get("user_level")
            },
            "content": content,
            "rating": int(review.get("rate", 0)),  # 评分 1-5
            "created_time": review.get("created"),
            "images": images,
            "video": video,
            "sku_info": sku_info,
            "likes": int(review.get("like_count", 0)),
            "comments": int(review.get("comment_count", 0)),
            "useful": int(review.get("useful", 0)),
            "days_used": review.get("days", "")  # 使用多少天后评价
        })
    
    return {
        "pagination": pagination,
        "reviews": reviews,
        "raw_data": review_data  # 保留原始数据
    }

def get_all_reviews(self, item_id: str, max_pages: int = 10, **kwargs) -> List[Dict]:
    """
    获取多页买家秀
    :param item_id: 商品ID
    :param max_pages: 最大页数限制
    :return: 所有买家秀列表
    """
    all_reviews = []
    page = 1
    
    while page <= max_pages:
        logging.info(f"获取第 {page} 页买家秀")
        result = self.get_item_reviews(
            item_id=item_id,
            page=page,
            page_size=50,  # 使用最大页大小
           ** kwargs
        )
        
        if not result or not result["reviews"]:
            break
            
        all_reviews.extend(result["reviews"])
        
        # 检查是否已到最后一页
        if page >= result["pagination"]["total_pages"]:
            break
            
        page += 1
        # 控制请求频率
        time.sleep(2)
        
    logging.info(f"共获取到 {len(all_reviews)} 条买家秀")
    return all_reviews

def _clean_text(self, text: str) -> str:
    """清理文本内容"""
    if not text:
        return ""
    # 去除HTML标签
    clean = re.sub(r'<.*?>', ' ', text)
    # 去除多余空格和换行
    clean = re.sub(r'\s+', ' ', clean).strip()
    return clean

def download_image(self, url: str, save_path: str) -> bool:
    """下载买家秀图片"""
    try:
        response = self.session.get(url, timeout=10)
        response.raise_for_status()
        
        # 保存图片
        with open(save_path, 'wb') as f:
            f.write(response.content)
        return True
    except Exception as e:
        logging.error(f"下载图片失败 {url}: {str(e)}")
        return False

def analyze_reviews(self, reviews: List[Dict]) -> Dict:
    """分析买家秀数据"""
    if not reviews:
        return {}
        
    total = len(reviews)
    
    # 评分分析
    rating_analysis = self._analyze_ratings(reviews)
    
    # 多媒体分析
    media_analysis = self._analyze_media(reviews)
    
    # 关键词分析
    keyword_analysis = self._analyze_keywords(reviews)
    
    # 规格分析
    sku_analysis = self._analyze_skus(reviews)
    
    # 热门买家秀
    top_reviews = sorted(reviews, key=lambda x: x["likes"], reverse=True)[:10]
    
    return {
        "total_reviews": total,
        "rating_analysis": rating_analysis,
        "media_analysis": media_analysis,
        "keyword_analysis": keyword_analysis,
        "sku_analysis": sku_analysis,
        "top_reviews": top_reviews
    }

def _analyze_ratings(self, reviews: List[Dict]) -> Dict:
    """分析评分分布"""
    rating_counts = defaultdict(int)
    total_rating = 0
    rated_count = 0
    
    for review in reviews:
        rating = review["rating"]
        if rating > 0:
            rating_counts[rating] += 1
            total_rating += rating
            rated_count += 1
    
    avg_rating = round(total_rating / rated_count, 1) if rated_count > 0 else 0
    
    return {
        "counts": dict(rating_counts),
        "average": avg_rating,
        "distribution": {k: round(v/rated_count*100, 1) for k, v in rating_counts.items()} if rated_count > 0 else {}
    }

def _analyze_media(self, reviews: List[Dict]) -> Dict:
    """分析多媒体内容"""
    has_image_count = 0
    has_video_count = 0
    total_images = 0
    
    for review in reviews:
        if review["images"]:
            has_image_count += 1
            total_images += len(review["images"])
        if review["video"]:
            has_video_count += 1
    
    return {
        "has_image_ratio": round(has_image_count / len(reviews) * 100, 1),
        "has_video_ratio": round(has_video_count / len(reviews) * 100, 1),
        "avg_images_per_review": round(total_images / len(reviews), 1) if len(reviews) > 0 else 0
    }

def _analyze_keywords(self, reviews: List[Dict]) -> Dict:
    """分析评价关键词"""
    # 简单关键词提取,实际应用中可使用更复杂的NLP方法
    keywords = {
        "质量": ["质量", "材质", "做工", "品质"],
        "外观": ["外观", "颜色", "款式", "样子", "好看"],
        "尺寸": ["尺寸", "大小", "尺码", "合适", "合身"],
        "性价比": ["性价比", "价格", "值", "划算"],
        "物流": ["物流", "快递", "速度", "快", "慢"],
        "服务": ["服务", "客服", "态度", "耐心"]
    }
    
    keyword_counts = defaultdict(int)
    
    for review in reviews:
        content = review["content"].lower()
        for category, kws in keywords.items():
            for kw in kws:
                if kw in content:
                    keyword_counts[category] += 1
                    break  # 每个类别只计数一次
    
    # 按出现次数排序
    sorted_keywords = sorted(keyword_counts.items(), key=lambda x: x[1], reverse=True)
    
    return {
        "counts": dict(keyword_counts),
        "sorted": sorted_keywords,
        "total_mentioned": sum(keyword_counts.values())
    }

def _analyze_skus(self, reviews: List[Dict]) -> Dict:
    """分析规格购买分布"""
    sku_counts = defaultdict(int)
    
    for review in reviews:
        if review["sku_info"]["property_names"]:
            sku_name = review["sku_info"]["property_names"]
            sku_counts[sku_name] += 1
    
    # 按购买次数排序
    sorted_skus = sorted(sku_counts.items(), key=lambda x: x[1], reverse=True)
    
    return {
        "counts": dict(sku_counts),
        "sorted": sorted_skus[:10],  # 前10个热门规格
        "total_sku_types": len(sku_counts)
    }

def visualize_analysis(self, analysis: Dict, output_dir: str = "review_analysis") -> None:
    """可视化分析结果"""
    # 创建输出目录
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
        
    # 设置中文显示
    plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
    plt.rcParams["axes.unicode_minus"] = False
    
    # 1. 评分分布饼图
    plt.figure(figsize=(10, 6))
    ratings = analysis["rating_analysis"]["counts"]
    if ratings:
        labels = [f"{k}星" for k in ratings.keys()]
        sizes = list(ratings.values())
        plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
        plt.title(f"买家秀评分分布 (平均评分: {analysis['rating_analysis']['average']})")
        plt.axis('equal')
        plt.tight_layout()
        plt.savefig(f"{output_dir}/rating_distribution.png")
        plt.close()
    
    # 2. 多媒体内容占比图
    plt.figure(figsize=(10, 6))
    media_labels = ['有图评价', '有视频评价']
    media_values = [
        analysis["media_analysis"]["has_image_ratio"],
        analysis["media_analysis"]["has_video_ratio"]
    ]
    x = np.arange(len(media_labels))
    plt.bar(x, media_values, width=0.5, color=['#4CAF50', '#2196F3'])
    plt.xticks(x, media_labels)
    plt.ylabel('占比 (%)')
    plt.title('买家秀多媒体内容占比')
    plt.ylim(0, 100)
    for i, v in enumerate(media_values):
        plt.text(i, v + 1, f'{v}%', ha='center')
    plt.tight_layout()
    plt.savefig(f"{output_dir}/media_ratio.png")
    plt.close()
    
    # 3. 关键词分布条形图
    plt.figure(figsize=(12, 6))
    keywords = analysis["keyword_analysis"]["sorted"]
    if keywords:
        labels = [k[0] for k in keywords]
        values = [k[1] for k in keywords]
        x = np.arange(len(labels))
        plt.bar(x, values, color='#ff9800')
        plt.xticks(x, labels)
        plt.ylabel('出现次数')
        plt.title('买家秀关键词分布')
        plt.tight_layout()
        plt.savefig(f"{output_dir}/keyword_distribution.png")
        plt.close()
    
    # 4. 热门规格分布条形图
    plt.figure(figsize=(12, 6))
    skus = analysis["sku_analysis"]["sorted"]
    if skus:
        # 处理长标签
        labels = [k[0][:15] + '...' if len(k[0]) > 15 else k[0] for k in skus]
        values = [k[1] for k in skus]
        x = np.arange(len(labels))
        plt.bar(x, values, color='#f44336')
        plt.xticks(x, labels, rotation=45)
        plt.ylabel('购买次数')
        plt.title('热门规格购买分布')
        plt.tight_layout()
        plt.savefig(f"{output_dir}/sku_distribution.png")
        plt.close()
    
    logging.info(f"分析图表已保存至 {output_dir} 目录")

示例调用 if name == "main": # 替换为实际的appkey和session(从淘宝开放平台获取) APPKEY = "your_appkey" SESSION = "your_session" # 替换为目标商品ID ITEM_ID = "1234567890"

python 复制代码
# 初始化API客户端
api = TaobaoItemReviewShowAPI(APPKEY, SESSION)

# 获取买家秀数据
all_reviews = api.get_all_reviews(
    item_id=ITEM_ID,
    max_pages=3,  # 最多获取3页
    sort="hot",  # 按热度排序
    # has_image=True  # 只获取有图评价
)

if all_reviews:
    # 分析买家秀
    analysis = api.analyze_reviews(all_reviews)
    
    print(f"=== 淘宝买家秀分析报告 (商品ID: {ITEM_ID}) ===")
    print(f"总买家秀数量: {analysis['total_reviews']}条")
    
    # 评分分析
    print("\n评分分析:")
    print(f"  平均评分: {analysis['rating_analysis']['average']}星")
    print("  评分分布:")
    for rating, ratio in analysis['rating_analysis']['distribution'].items():
        print(f"    {rating}星: {ratio}%")
    
    # 多媒体分析
    print("\n多媒体分析:")
    print(f"  有图评价占比: {analysis['media_analysis']['has_image_ratio']}%")
    print(f"  有视频评价占比: {analysis['media_analysis']['has_video_ratio']}%")
    print(f"  平均每条评价图片数: {analysis['media_analysis']['avg_images_per_review']}")
    
    # 关键词分析
    print("\n关键词分析:")
    print("  出现频率最高的5个关键词:")
    for i, (keyword, count) in enumerate(analysis['keyword_analysis']['sorted'][:5], 1):
        print(f"    {i}. {keyword}: {count}次")
    
    # 规格分析
    print("\n规格分析:")
    print(f"  共有{analysis['sku_analysis']['total_sku_types']}种不同规格")
    if analysis['sku_analysis']['sorted']:
        print("  最受欢迎的3种规格:")
        for i, (sku, count) in enumerate(analysis['sku_analysis']['sorted'][:3], 1):
            print(f"    {i}. {sku}: {count}人购买")
    
    # 热门买家秀
    print("\n最受欢迎的3条买家秀:")
    for i, review in enumerate(analysis['top_reviews'][:3], 1):
        print(f"  {i}. {review['user']['nickname']} ({review['rating']}星)")
        print(f"     点赞数: {review['likes']}, 评论数: {review['comments']}")
        print(f"     内容: {review['content'][:100]}{'...' if len(review['content'])>100 else ''}")
        print(f"     图片数: {len(review['images'])}, {'包含视频' if review['video'] else '无视频'}")
    
    # 生成可视化图表
    api.visualize_analysis(analysis)
    
    # 示例:下载热门买家秀的图片
    if not os.path.exists("review_images"):
        os.makedirs("review_images")
        
    for i, review in enumerate(analysis['top_reviews'][:3], 1):
        if review['images']:
            for j, img_url in enumerate(review['images'][:2], 1):  # 每个买家秀下载前2张图片
                api.download_image(img_url, f"review_images/top_{i}_img_{j}.jpg")

接口调用注意事项

  1. 调用限制与规范
  • QPS 限制:淘宝开放平台对买家秀接口的 QPS 限制通常为 5-10 次 / 秒
  • 权限要求:需要申请专门的权限才能访问买家秀接口,个人开发者权限有限
  • 数据缓存:建议缓存获取的数据,更新周期可设置为 12-24 小时
  • 图片使用:买家秀图片受版权保护,未经授权不得用于商业用途
  • 调用频率:批量获取时需控制请求频率,避免触发反爬虫机制
  1. 常见错误及解决方案
错误码 说明 解决方案
401 认证失败 检查 appkey 和 session 是否有效
403 权限不足 申请更高权限或检查接口权限配置
404 商品不存在 确认 item_id 是否正确
429 调用频率超限 降低调用频率,实现请求限流
500 服务器错误 实现重试机制,最多 3 次
110 参数错误 检查请求参数格式和取值范围
  1. 数据解析要点
  • 多媒体处理:图片 URL 可能有时效性,需及时下载或处理
  • 评分体系:淘宝评分通常为 1-5 星,需正确解析评分含义
  • 规格信息:SKU 信息可能以编码形式返回,需映射为可读名称
  • 时间格式:发布时间可能为时间戳或特定格式字符串,需统一转换
  • 内容清洗:评价内容可能包含 HTML 标签和特殊字符,需清洗处理

应用场景与扩展建议

典型应用场景

  • 商品优化分析:基于买家秀反馈改进产品设计和功能
  • 营销素材收集:筛选优质买家秀作为官方营销素材
  • 用户体验研究:分析用户真实使用场景和体验痛点
  • 竞品分析系统:对比分析同类商品的买家评价和反馈
  • 虚假交易检测:通过买家秀特征识别可疑交易

扩展建议

  • 实现图片内容分析:使用图像识别技术分析买家秀图片中的商品状态
  • 开发情感分析模块:对评价内容进行情感倾向分析,量化用户满意度
  • 构建用户画像系统:基于买家秀数据构建购买用户的特征画像
  • 实现自动标签生成:为买家秀自动生成标签,便于内容分类和检索
  • 开发竞品对比功能:横向对比不同商品的买家秀特征和用户反馈
相关推荐
用户4099322502126 小时前
如何用FastAPI玩转多模块测试与异步任务,让代码不再“闹脾气”?
后端·ai编程·trae
陈佬昔没带相机8 小时前
告别Token焦虑!我是如何用最低消费玩转AI编程的
claude·cursor·trae
兵临天下api1 天前
微店店铺商品搜索(item_search_shop)接口深度分析及 Python 实现
trae
倔强的石头1061 天前
用 Trae 玩转 Bright Data MCP 集成
智能体·trae·bright data mcp
兵临天下api1 天前
微店 item_get 接口深度深度分析及 Python 实现
trae
飞哥数智坊2 天前
终端里用 Claude Code 太难受?我把它接进 TRAE,真香!
人工智能·claude·trae
程序员X小鹿2 天前
Trae SOLO实战分享:3小时上线一个网站,全栈开发 + 自动部署,吊打Claude Code?(附保姆级教程)
ai编程·trae·solo
围巾哥萧尘2 天前
TRAE技巧便利店第二期,教师智能点名网页系统,荣获第一名啦🧣
trae
豆包MarsCode2 天前
TRAE MCP 实践: 智能人情账本系统开发
trae