×

1688 item_review 接口深度分析及 Python 实现

万邦科技Lex 万邦科技Lex 发表于2025-09-08 09:49:13 浏览242 评论0

抢沙发发表评论

            注册账号免费测试1688API数据接口

1688 平台的 item_review 接口是获取商品采购商评价数据的核心接口,专注于 B2B 场景下的交易评价信息。与面向消费者的电商平台不同,1688 的评论更侧重于产品质量、供应商服务、物流速度等批发采购相关维度,对供应商评估和采购决策具有重要参考价值。

一、接口核心特性分析

1. 接口功能与定位

  • 核心功能:获取 1688 商品的采购商评价数据,包括评价内容、评分、采购量、合作次数等 B2B 场景特有的信息

  • 数据维度

    • 基础评价:评价 ID、商品 ID、采购商信息、评价时间、评价内容

    • 评分数据:产品质量、卖家服务、物流速度等维度评分

    • 交易信息:采购数量、采购金额、合作次数、是否回头客

    • 多媒体内容:产品实拍图、质检图片

    • 追评信息:追加评价内容、长期使用反馈

  • 应用场景

    • 供应商信用评估系统

    • 采购决策辅助工具

    • 供应链风险控制

    • 同类供应商对比分析

    • 产品质量监控

2. 认证机制

1688 开放平台采用 appkey + access_token 的认证方式:


  • 开发者在 1688 开放平台注册应用,获取 appkey 和 appsecret

  • 通过 appkey 和 appsecret 获取 access_token(通常有效期为 24 小时)

  • 每次接口调用需携带有效 access_token

  • 评论接口需要申请特定权限,部分高级数据需通过企业认证

3. 核心参数与响应结构

请求参数

参数名类型是否必填说明
offer_idString商品 ID(1688 中称为 offer_id)
access_tokenString访问令牌
pageInteger页码,默认 1
page_sizeInteger每页条数,默认 20,最大 50
sortString排序方式:newest(最新)、helpful(最有帮助)、high_rating(高分)
is_retailBoolean是否只看零售单评价,默认 false
has_imageBoolean是否只看有图评价,默认 false

响应核心字段

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

  • 评价列表:每条评价包含

    • 评价基本信息:评价 ID、采购商信息、评价时间

    • 评分信息:产品质量、卖家服务、物流速度等评分

    • 交易信息:采购数量、金额、是否回头客

    • 评价内容:文本内容、标签

    • 多媒体:实拍图片 URL 列表

    • 追评:内容与时间

二、Python 脚本实现

以下是调用 1688 item_review 接口的完整 Python 实现,包含令牌获取、接口调用、数据解析及 B2B 场景特有的评价分析功能:
import requests
import time
import json
import logging
import re
from typing import Dict, Optional, List
from requests.exceptions import RequestException
from snownlp import SnowNLP  # 用于情感分析,需安装:pip install snownlp

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

class Alibaba1688ItemReviewAPI:
    def __init__(self, appkey: str, appsecret: str):
        """
        初始化1688评论API客户端
        :param appkey: 1688开放平台appkey
        :param appsecret: 1688开放平台appsecret
        """
        self.appkey = appkey
        self.appsecret = appsecret
        self.base_url = "https://gw.open.1688.com/openapi"
        self.access_token = None
        self.token_expires_at = 0  # token过期时间戳
        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/110.0.0.0 Safari/537.36"
        })

    def _get_access_token(self) -> Optional[str]:
        """获取访问令牌"""
        # 检查token是否有效
        if self.access_token and self.token_expires_at > time.time() + 60:
            return self.access_token
            
        logging.info("获取新的access_token")
        params = {
            "method": "alibaba.oauth2.getToken",
            "client_id": self.appkey,
            "client_secret": self.appsecret,
            "grant_type": "client_credentials",
            "format": "json"
        }
        
        try:
            response = self.session.get(f"{self.base_url}/gateway.do", params=params, timeout=10)
            response.raise_for_status()
            result = response.json()
            
            if "error_response" in result:
                logging.error(f"获取access_token失败: {result['error_response']['msg']} (错误码: {result['error_response']['code']})")
                return None
                
            self.access_token = result["access_token"]
            self.token_expires_at = time.time() + result.get("expires_in", 86400)  # 默认为24小时
            return self.access_token
                
        except RequestException as e:
            logging.error(f"获取access_token请求异常: {str(e)}")
            return None

    def get_item_reviews(self, 
                        offer_id: str, 
                        page: int = 1, 
                        page_size: int = 20,
                        sort: str = "newest",
                        is_retail: bool = False,
                        has_image: bool = False) -> Optional[Dict]:
        """
        获取商品评论
        :param offer_id: 商品ID(1688中称为offer_id)
        :param page: 页码
        :param page_size: 每页条数
        :param sort: 排序方式
        :param is_retail: 是否只看零售单评价
        :param has_image: 是否只看有图评价
        :return: 评论数据
        """
        # 验证参数
        valid_sorts = ["newest", "helpful", "high_rating"]
        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
            
        # 获取有效的access_token
        if not self._get_access_token():
            return None
            
        params = {
            "method": "alibaba.item.review.get",
            "client_id": self.appkey,
            "access_token": self.access_token,
            "offer_id": offer_id,
            "page": page,
            "page_size": page_size,
            "sort": sort,
            "is_retail": "true" if is_retail else "false",
            "has_image": "true" if has_image else "false",
            "format": "json",
            "v": "1.0",
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
        }
        
        try:
            response = self.session.get(f"{self.base_url}/gateway.do", params=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
                
            review_response = result.get("alibaba_item_review_get_response", {})
            reviews_data = review_response.get("result", {})
            
            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_reviews": int(review_data.get("total_count", 0)),
            "total_pages": (int(review_data.get("total_count", 0)) + int(review_data.get("page_size", 20)) - 1) // int(review_data.get("page_size", 20)),
            "current_page": int(review_data.get("current_page", 1)),
            "page_size": int(review_data.get("page_size", 20))
        }
        
        # 格式化评论列表
        reviews = []
        for review in review_data.get("reviews", []):
            # 处理评价内容(去除HTML标签)
            content = self._clean_text(review.get("content", ""))
            
            # 情感分析(0-1之间,越接近1越积极)
            sentiment_score = self._analyze_sentiment(content)
            sentiment = "positive" if sentiment_score > 0.6 else "negative" if sentiment_score < 0.4 else "neutral"
            
            # 处理评价图片
            images = []
            if review.get("images"):
                images = [img.get("url") for img in review.get("images") if img.get("url")]
            
            # 处理追评(1688中可能包含长期使用反馈)
            append_comment = None
            if review.get("append_comment"):
                append_comment = {
                    "content": self._clean_text(review["append_comment"].get("content", "")),
                    "created": review["append_comment"].get("gmt_create"),
                    "days_after_purchase": review["append_comment"].get("days_after_purchase")  # 购买后多少天追评
                }
            
            # 处理交易信息(B2B特有的采购信息)
            trade_info = {
                "purchase_quantity": int(review.get("purchase_quantity", 0)),  # 采购数量
                "purchase_amount": float(review.get("purchase_amount", 0)),  # 采购金额
                "is_repeat_buyer": review.get("is_repeat_buyer", False),  # 是否回头客
                "cooperation_count": int(review.get("cooperation_count", 1)),  # 合作次数
                "purchase_time": review.get("purchase_time")  # 采购时间
            }
            
            reviews.append({
                "review_id": review.get("review_id"),
                "buyer": {
                    "user_id": review.get("buyer_user_id"),
                    "nickname": review.get("buyer_nick"),
                    "level": review.get("buyer_level"),  # 采购商等级
                    "region": review.get("buyer_region")  # 采购商地区
                },
                "rating": {
                    "product_quality": int(review.get("product_quality_rating", 0)),  # 产品质量评分
                    "seller_service": int(review.get("seller_service_rating", 0)),  # 卖家服务评分
                    "logistics_speed": int(review.get("logistics_speed_rating", 0)),  # 物流速度评分
                    "match_description": int(review.get("match_description_rating", 0))  # 与描述相符度
                },
                "content": content,
                "created_time": review.get("gmt_create"),
                "images": images,
                "append_comment": append_comment,
                "useful_count": int(review.get("useful_count", 0)),  # 有用数
                "tags": review.get("tags", "").split(","),  # 评价标签
                "trade_info": trade_info,
                "is_retail": review.get("is_retail", False),  # 是否零售单
                "sentiment": {
                    "score": round(sentiment_score, 4),
                    "label": sentiment
                }
            })
        
        return {
            "pagination": pagination,
            "reviews": reviews,
            "raw_data": review_data  # 保留原始数据
        }
    
    def _clean_text(self, text: str) -> str:
        """清理文本,去除HTML标签和特殊字符"""
        if not text:
            return ""
        # 去除HTML标签
        clean = re.sub(r'<.*?>', '', text)
        # 去除多余空格和换行
        clean = re.sub(r'\s+', ' ', clean).strip()
        # 去除特殊字符
        clean = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9,.?!,。?!]', ' ', clean)
        return clean
    
    def _analyze_sentiment(self, text: str) -> float:
        """使用SnowNLP进行情感分析"""
        if not text:
            return 0.5  # 中性
        try:
            return SnowNLP(text).sentiments
        except:
            return 0.5  # 分析失败时返回中性

    def get_all_reviews(self, offer_id: str, max_pages: int = 10, has_image: bool = False) -> List[Dict]:
        """
        获取多页评论数据
        :param offer_id: 商品ID
        :param max_pages: 最大页数限制
        :param has_image: 是否只看有图评价
        :return: 所有评论列表
        """
        all_reviews = []
        page = 1
        
        while page <= max_pages:
            logging.info(f"获取第 {page} 页评论")
            result = self.get_item_reviews(
                offer_id=offer_id,
                page=page,
                page_size=50,  # 使用最大页大小减少请求次数
                sort="newest",
                has_image=has_image
            )
            
            if not result or not result["reviews"]:
                break
                
            all_reviews.extend(result["reviews"])
            
            # 检查是否已到最后一页
            if page >= result["pagination"]["total_pages"]:
                break
                
            page += 1
            # 控制请求频率,遵守1688 API的QPS限制
            time.sleep(2)
            
        return all_reviews

    def analyze_b2b_reviews(self, reviews: List[Dict]) -> Dict:
        """分析B2B评论数据,生成针对批发采购场景的统计报告"""
        if not reviews:
            return {}
            
        total = len(reviews)
        sentiment_counts = {"positive": 0, "neutral": 0, "negative": 0}
        rating_stats = {
            "product_quality": [],
            "seller_service": [],
            "logistics_speed": [],
            "match_description": []
        }
        tag_counts = {}
        has_image_count = 0
        repeat_buyer_count = 0
        retail_order_count = 0
        total_purchase_quantity = 0
        total_purchase_amount = 0
        
        # B2B场景关键词(与批发采购相关)
        b2b_keywords = {
            "quality": ["质量", "材质", "做工", "品质", "用料"],
            "price": ["价格", "性价比", "便宜", "贵", "优惠"],
            "service": ["服务", "态度", "响应", "沟通", "售后"],
            "logistics": ["物流", "快递", "运输", "速度", "包装"],
            "moq": ["起订量", "批量", "数量", "MOQ"],
            "delivery": ["发货", "交期", "工期", "准时"]
        }
        keyword_counts = {k:0 for k in b2b_keywords}
        
        # 统计基础数据
        for review in reviews:
            # 情感统计
            sentiment = review["sentiment"]["label"]
            sentiment_counts[sentiment] += 1
            
            # 评分统计
            for key in rating_stats:
                if key in review["rating"]:
                    rating_stats[key].append(review["rating"][key])
            
            # 标签统计
            for tag in review["tags"]:
                if tag:
                    tag_counts[tag] = tag_counts.get(tag, 0) + 1
            
            # 有图评价统计
            if review["images"]:
                has_image_count += 1
                
            # 回头客统计(B2B重要指标)
            if review["trade_info"]["is_repeat_buyer"]:
                repeat_buyer_count += 1
                
            # 零售单统计
            if review["is_retail"]:
                retail_order_count += 1
                
            # 采购量和采购金额统计
            total_purchase_quantity += review["trade_info"]["purchase_quantity"]
            total_purchase_amount += review["trade_info"]["purchase_amount"]
            
            # B2B关键词统计
            content = review["content"].lower()
            for category, kws in b2b_keywords.items():
                for kw in kws:
                    if kw in content:
                        keyword_counts[category] += 1
                        break  # 每个类别只计数一次
            
        # 计算平均评分
        avg_ratings = {}
        for key, values in rating_stats.items():
            if values:
                avg_ratings[key] = round(sum(values) / len(values), 1)
            else:
                avg_ratings[key] = 0
        
        # 获取热门标签(前10)
        top_tags = sorted(tag_counts.items(), key=lambda x: x[1], reverse=True)[:10]
        
        # 计算平均采购量和采购金额
        avg_purchase = {
            "quantity": round(total_purchase_quantity / total, 1) if total > 0 else 0,
            "amount": round(total_purchase_amount / total, 2) if total > 0 else 0
        }
        
        return {
            "total_reviews": total,
            "sentiment_distribution": {
                "count": sentiment_counts,
                "percentage": {
                    k: round(v / total * 100, 1) for k, v in sentiment_counts.items()
                }
            },
            "average_rating": avg_ratings,
            "image_review_ratio": round(has_image_count / total * 100, 1) if total > 0 else 0,
            "repeat_buyer_ratio": round(repeat_buyer_count / total * 100, 1) if total > 0 else 0,  # 回头客比例(B2B重要指标)
            "retail_order_ratio": round(retail_order_count / total * 100, 1) if total > 0 else 0,  # 零售单比例
            "avg_purchase": avg_purchase,  # 平均采购量和金额
            "total_purchase": {
                "quantity": total_purchase_quantity,
                "amount": total_purchase_amount
            },
            "top_tags": top_tags,
            "b2b_keyword_distribution": keyword_counts
        }


# 示例调用
if __name__ == "__main__":
    # 替换为实际的appkey和appsecret(从1688开放平台获取)
    APPKEY = "your_appkey"
    APPSECRET = "your_appsecret"
    # 替换为目标商品offer_id
    OFFER_ID = "61234567890"
    
    # 初始化API客户端
    api = Alibaba1688ItemReviewAPI(APPKEY, APPSECRET)
    
    # 方式1:获取单页评论
    # review_result = api.get_item_reviews(
    #     offer_id=OFFER_ID,
    #     page=1,
    #     page_size=20,
    #     sort="newest",
    #     has_image=False
    # )
    
    # 方式2:获取多页评论
    review_result = api.get_all_reviews(
        offer_id=OFFER_ID,
        max_pages=3,
        has_image=False
    )
    
    if isinstance(review_result, dict) and "reviews" in review_result:
        print(f"共获取到 {review_result['pagination']['total_reviews']} 条评论")
        print(f"当前第 {review_result['pagination']['current_page']}/{review_result['pagination']['total_pages']} 页\n")
        
        # 打印前3条评论
        for i, review in enumerate(review_result["reviews"][:3], 1):
            print(f"{i}. 采购商: {review['buyer']['nickname']} ({review['buyer']['region'] or '未知地区'})")
            print(f"   采购信息: {review['trade_info']['purchase_quantity']}件, {review['trade_info']['purchase_amount']}元, {'回头客' if review['trade_info']['is_repeat_buyer'] else '新客户'}")
            print(f"   评分: 质量 {review['rating']['product_quality']}, 服务 {review['rating']['seller_service']}, 物流 {review['rating']['logistics_speed']}")
            print(f"   时间: {review['created_time']}")
            print(f"   内容: {review['content'][:100]}{'...' if len(review['content'])>100 else ''}")
            print(f"   情感: {review['sentiment']['label']} (得分: {review['sentiment']['score']})")
            if review['images']:
                print(f"   图片数: {len(review['images'])}")
            if review['tags']:
                print(f"   标签: {', '.join(review['tags'])}")
            if review['append_comment']:
                print(f"   追评({review['append_comment']['days_after_purchase']}天后): {review['append_comment']['content'][:50]}{'...' if len(review['append_comment']['content'])>50 else ''}")
            print("-" * 100)
            
        # 分析评论
        analysis = api.analyze_b2b_reviews(review_result["reviews"])
        print("\n=== B2B评论分析报告 ===")
        print(f"总评论数: {analysis['total_reviews']}")
        print(f"情感分布: 正面 {analysis['sentiment_distribution']['percentage']['positive']}%, 中性 {analysis['sentiment_distribution']['percentage']['neutral']}%, 负面 {analysis['sentiment_distribution']['percentage']['negative']}%")
        print(f"平均评分: 质量 {analysis['average_rating']['product_quality']}, 服务 {analysis['average_rating']['seller_service']}, 物流 {analysis['average_rating']['logistics_speed']}")
        print(f"回头客比例: {analysis['repeat_buyer_ratio']}%")
        print(f"平均采购量: {analysis['avg_purchase']['quantity']}件, 平均采购金额: {analysis['avg_purchase']['amount']}元")
        print("热门标签:")
        for tag, count in analysis['top_tags']:
            print(f"  {tag}: {count}次")
        print("B2B关键维度提及次数:")
        for category, count in analysis['b2b_keyword_distribution'].items():
            print(f"  {category}: {count}次")
            
    elif isinstance(review_result, list):
        # 处理多页评论结果
        print(f"共获取到 {len(review_result)} 条评论")
        
        # 分析评论
        analysis = api.analyze_b2b_reviews(review_result)
        print("\n=== B2B评论分析报告 ===")
        print(f"总评论数: {analysis['total_reviews']}")
        print(f"情感分布: 正面 {analysis['sentiment_distribution']['percentage']['positive']}%, 中性 {analysis['sentiment_distribution']['percentage']['neutral']}%, 负面 {analysis['sentiment_distribution']['percentage']['negative']}%")
        print(f"回头客比例: {analysis['repeat_buyer_ratio']}%")

三、接口调用注意事项

1. 调用限制与规范

  • QPS 限制:1688 开放平台对评论接口的 QPS 限制通常为 3-5 次 / 秒,低于消费类电商平台

  • 数据权限:评论接口需要申请特定权限,企业账号比个人账号能获取更多数据

  • 分页限制:最多可获取前 50 页评论数据(约 2500 条)

  • 行业差异:不同行业的评论数据结构可能略有差异,尤其是定制类商品

  • 合规使用:评论数据包含采购商信息,需严格遵守隐私保护条款

2. 常见错误及解决方案

错误码说明解决方案
401未授权或 token 无效重新获取 access_token,检查权限是否正确
403权限不足升级账号类型,申请评论接口的访问权限
404商品不存在或无评论确认 offer_id 是否正确,该商品可能没有评论
429调用频率超限降低调用频率,实现请求限流
500服务器内部错误实现重试机制,最多 3 次,间隔指数退避
110商品 ID 无效检查 offer_id 是否正确,1688 商品 ID 通常为 10-12 位数字

3. 数据解析要点

  • B2B 特有字段:重点关注采购量、采购金额、是否回头客等批发场景特有字段

  • 评分体系:1688 评分通常为 1-5 分,部分字段采用星级制(1-5 星)

  • 地区信息:采购商地区分布对供应链分析有重要价值,需正确解析

  • 图片内容:1688 评论图片多为产品实拍,对质量评估有直接参考价值

  • 合作次数:反映供应商的长期合作稳定性,是 B2B 场景的重要指标

四、应用场景与扩展建议

典型应用场景

  • 供应商评估系统:综合评论数据评估供应商的产品质量和服务水平

  • 采购决策辅助工具:基于其他采购商的评价数据辅助采购决策

  • 供应链风险监控:通过负面评价识别潜在的供应链风险

  • 同类供应商对比:横向对比同类商品供应商的评价数据

  • 市场趋势分析:通过评论内容分析产品需求和市场趋势

扩展建议

  • 实现供应商信用评分模型:结合评论数据构建供应商信用评分体系

  • 开发采购风险预警:基于负面评论关键词自动识别高风险供应商

  • 构建采购量与评价相关性分析:分析采购量与评价之间的关系

  • 开发地区采购偏好分析:分析不同地区采购商的评价差异和偏好

  • 实现长期合作价值评估:基于回头客比例和合作次数评估供应商长期价值

  • 构建多维度供应商雷达图:从质量、服务、物流等维度可视化供应商表现


通过合理使用 1688 item_review 接口,开发者可以构建针对 B2B 场景的供应商评价分析系统,为采购决策和供应链管理提供数据支持。使用时需特别注意 1688 平台的 B2B 特性,关注与批发采购相关的特有数据维度,以获取更有价值的分析结果。


群贤毕至

访客