Java 获取淘宝评论接口开发文档
淘宝商品评论是电商数据分析、竞品监控、用户口碑研究的核心数据源。本文将系统性地介绍通过淘宝开放平台官方 API 获取商品评论的完整方案,涵盖接口权限申请、签名生成、分页拉取、增量同步及情感分析预处理,并提供可直接运行的 Java 代码实现。
一、接口体系与权限说明
1.1 核心评论接口
淘宝开放平台提供的评论相关接口主要有以下几个:
| 接口名称 | 功能描述 | 适用场景 | 权限要求 |
|---|---|---|---|
taobao.item.reviews.get |
获取商品评论列表(含评分、内容、追评、晒图) | 商品口碑分析、竞品监控 | 企业/个人开发者,需申请权限 |
taobao.item.review.get |
获取单商品评论(较老版本) | 兼容旧系统 | 权限收紧,可能已下线 |
taobao.traderates.get |
获取交易评价(买家与卖家互评) | 店铺运营质量分析 | 商家授权 |
taobao.seller.review.list |
商家查询自己店铺的评论 | 商家自营评论管理 | 仅限商家自己店铺 |
重要提示:淘宝开放平台对评论接口权限管控严格,个人开发者每日配额约 500 次,企业需申请扩容。部分历史接口(如
taobao.item.review.get)已逐步下线,建议优先使用taobao.item.reviews.get。
1.2 接入准备
-
注册开发者账号并完成实名认证
-
创建应用,获取 App Key 和 App Secret
-
在应用权限管理中申请
taobao.item.reviews.get接口权限 -
通过 OAuth2.0 获取 Access Token(涉及用户数据时需授权)
-
注意:评论数据仅返回近 180 天有效评论,且需遵守平台数据使用协议
二、接口核心参数详解
2.1 请求参数
| 参数名 | 类型 | 必选 | 说明 |
|---|---|---|---|
method |
String | 是 | 固定值:taobao.item.reviews.get |
app_key |
String | 是 | 应用 App Key |
timestamp |
String | 是 | 时间戳,格式 yyyy-MM-dd HH:mm:ss |
format |
String | 是 | 固定 json |
v |
String | 是 | 固定 2.0 |
sign_method |
String | 是 | md5 或 hmac-sha1 |
sign |
String | 是 | 请求签名 |
num_iid |
String | 是 | 淘宝商品 ID |
page_no |
Integer | 否 | 页码,默认 1 |
page_size |
Integer | 否 | 每页条数,1~50,默认 20 |
review_type |
Integer | 否 | 0=全部,1=好评,2=中评,3=差评 |
has_image |
Boolean | 否 | true 仅查带图评论 |
has_append |
Boolean | 否 | true 仅查含追评评论 |
session |
String | 条件 | Access Token(部分场景需要) |
2.2 返回数据结构
{
"item_reviews_get_response": {
"total_results": 1258,
"reviews": {
"review": [
{
"review_id": "7295689452365896235",
"user_nick": "小***柚",
"is_anonymous": false,
"rate": 5,
"content": "面料柔软,尺码标准,做工精细,性价比很高",
"created": "2026-04-12 09:22:36",
"sku_info": "黑色-XL",
"useful_num": 36,
"images": [
"https://img.alicdn.com/imgextra/i1/O1CN01xxxxxx1.jpg"
],
"has_append": true,
"append_content": "穿洗三次没缩水,版型不变形,推荐购买",
"append_created": "2026-04-25 11:15:22",
"seller_reply": "感谢您细致的评价,我们严控面料品质",
"seller_reply_time": "2026-04-13 15:02:11",
"comment_tags": ["面料好", "尺码准", "性价比高"]
}
]
}
}
}
三、完整 Java 实现
3.1 Maven 依赖
<dependencies>
<!-- 淘宝官方 SDK(推荐) -->
<dependency>
<groupId>com.taobao.top</groupId>
<artifactId>top-sdk-java</artifactId>
<version>4.3.0</version>
</dependency>
<!-- OkHttp HTTP 客户端 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- FastJSON JSON 解析 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.25</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>
3.2 核心评论客户端
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 淘宝商品评论 API Java 客户端
* 支持分页拉取、增量同步、情感分析预处理
*/
public class TaobaoReviewClient {
private static final Logger log = LoggerFactory.getLogger(TaobaoReviewClient.class);
// TOP 统一网关
private static final String GATEWAY_URL = "https://eco.taobao.com/router/rest";
private final String appKey;
private final String appSecret;
private final String sessionKey; // Access Token,可选
private final OkHttpClient httpClient;
// 限流控制:QPS 建议 ≤ 5
private static final long MIN_INTERVAL_MS = 200;
private long lastRequestTime = 0;
public TaobaoReviewClient(String appKey, String appSecret) {
this(appKey, appSecret, null);
}
public TaobaoReviewClient(String appKey, String appSecret, String sessionKey) {
this.appKey = appKey;
this.appSecret = appSecret;
this.sessionKey = sessionKey;
this.httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
}
// ==================== 签名生成 ====================
/**
* 生成淘宝 TOP API MD5 签名
* 规则:MD5(AppSecret + key1value1 + key2value2 + ... + AppSecret).toUpperCase()
*/
public String generateSign(Map<String, String> params) {
// 1. 过滤空值,排除 sign 和 sign_method
List<String> sortedKeys = params.entrySet().stream()
.filter(e -> e.getValue() != null && !e.getValue().isEmpty())
.filter(e -> !e.getKey().equals("sign") && !e.getKey().equals("sign_method"))
.map(Map.Entry::getKey)
.sorted()
.toList();
// 2. 拼接签名字符串
StringBuilder signStr = new StringBuilder(appSecret);
for (String key : sortedKeys) {
signStr.append(key).append(params.get(key));
}
signStr.append(appSecret);
// 3. MD5 加密并转大写
return md5Encrypt(signStr.toString()).toUpperCase();
}
private String md5Encrypt(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1) sb.append("0");
sb.append(hex);
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 加密失败", e);
}
}
// ==================== 限流控制 ====================
private synchronized void rateLimit() {
long now = System.currentTimeMillis();
long elapsed = now - lastRequestTime;
if (elapsed < MIN_INTERVAL_MS) {
try {
Thread.sleep(MIN_INTERVAL_MS - elapsed);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
lastRequestTime = System.currentTimeMillis();
}
// ==================== 核心请求方法 ====================
/**
* 执行 API 请求
*/
private JSONObject executeRequest(Map<String, String> params) throws IOException {
rateLimit(); // 限流控制
// 添加公共参数
params.put("app_key", appKey);
params.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
params.put("format", "json");
params.put("v", "2.0");
params.put("sign_method", "md5");
// 添加 Session(如需要)
if (sessionKey != null && !sessionKey.isEmpty()) {
params.put("session", sessionKey);
}
// 生成签名
params.put("sign", generateSign(params));
// 构建表单请求
FormBody.Builder formBuilder = new FormBody.Builder();
for (Map.Entry<String, String> entry : params.entrySet()) {
formBuilder.add(entry.getKey(), entry.getValue());
}
Request request = new Request.Builder()
.url(GATEWAY_URL)
.post(formBuilder.build())
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("HTTP 请求失败: " + response.code());
}
return JSON.parseObject(response.body().string());
}
}
// ==================== 评论查询接口 ====================
/**
* 获取单页商品评论
*
* @param numIid 商品 ID
* @param pageNo 页码
* @param pageSize 每页条数(最大 50)
* @param reviewType 评论类型:0=全部, 1=好评, 2=中评, 3=差评
* @param hasImage 是否仅查带图评论
* @param hasAppend 是否仅查含追评评论
*/
public ReviewPageResult getReviews(String numIid, int pageNo, int pageSize,
Integer reviewType, Boolean hasImage, Boolean hasAppend) {
Map<String, String> params = new HashMap<>();
params.put("method", "taobao.item.reviews.get");
params.put("num_iid", numIid);
params.put("page_no", String.valueOf(pageNo));
params.put("page_size", String.valueOf(Math.min(pageSize, 50)));
if (reviewType != null) {
params.put("review_type", String.valueOf(reviewType));
}
if (hasImage != null) {
params.put("has_image", String.valueOf(hasImage));
}
if (hasAppend != null) {
params.put("has_append", String.valueOf(hasAppend));
}
try {
JSONObject response = executeRequest(params);
return parseReviewResponse(response, numIid);
} catch (IOException e) {
log.error("获取评论失败,商品ID: {}, 页码: {}", numIid, pageNo, e);
return ReviewPageResult.error("REQUEST_ERROR", e.getMessage());
}
}
/**
* 自动分页获取全部评论
*/
public List<Review> getAllReviews(String numIid, Integer reviewType,
Boolean hasImage, Boolean hasAppend) {
List<Review> allReviews = new ArrayList<>();
int pageNo = 1;
int pageSize = 50;
while (true) {
ReviewPageResult result = getReviews(numIid, pageNo, pageSize,
reviewType, hasImage, hasAppend);
if (!result.isSuccess()) {
log.error("获取评论失败: {}", result.getErrorMsg());
break;
}
allReviews.addAll(result.getReviews());
log.info("获取第 {} 页评论,本页 {} 条,累计 {} 条",
pageNo, result.getReviews().size(), allReviews.size());
// 判断是否还有更多数据
if (result.getReviews().size() < pageSize ||
allReviews.size() >= result.getTotalResults()) {
break;
}
pageNo++;
// 安全限制:最多拉取 100 页
if (pageNo > 100) {
log.warn("达到最大分页限制,停止拉取");
break;
}
}
return allReviews;
}
/**
* 增量拉取:按时间戳过滤获取新评论
*/
public List<Review> getIncrementalReviews(String numIid, String sinceTime) {
List<Review> allReviews = getAllReviews(numIid, null, null, null);
if (sinceTime == null || sinceTime.isEmpty()) {
return allReviews;
}
// 过滤出 sinceTime 之后的评论
return allReviews.stream()
.filter(r -> r.getCreated() != null && r.getCreated().compareTo(sinceTime) > 0)
.toList();
}
// ==================== 响应解析 ====================
private ReviewPageResult parseReviewResponse(JSONObject response, String numIid) {
// 检查错误响应
if (response.containsKey("error_response")) {
JSONObject error = response.getJSONObject("error_response");
return ReviewPageResult.error(
error.getString("code"),
error.getString("msg") + " - " + error.getString("sub_msg", "")
);
}
JSONObject reviewResponse = response.getJSONObject("item_reviews_get_response");
if (reviewResponse == null) {
return ReviewPageResult.error("PARSE_ERROR", "响应中无 item_reviews_get_response");
}
int totalResults = reviewResponse.getIntValue("total_results", 0);
JSONArray reviewsArray = reviewResponse.getJSONObject("reviews").getJSONArray("review");
List<Review> reviews = new ArrayList<>();
if (reviewsArray != null) {
for (int i = 0; i < reviewsArray.size(); i++) {
JSONObject item = reviewsArray.getJSONObject(i);
reviews.add(parseReviewItem(item));
}
}
return new ReviewPageResult(true, totalResults, reviews);
}
private Review parseReviewItem(JSONObject json) {
Review review = new Review();
review.setReviewId(json.getString("review_id"));
review.setUserNick(json.getString("user_nick"));
review.setAnonymous(json.getBooleanValue("is_anonymous"));
review.setRate(json.getIntValue("rate", 5));
review.setContent(json.getString("content"));
review.setCreated(json.getString("created"));
review.setSkuInfo(json.getString("sku_info"));
review.setUsefulNum(json.getIntValue("useful_num", 0));
// 解析图片列表
JSONArray images = json.getJSONArray("images");
if (images != null) {
List<String> imageList = new ArrayList<>();
for (int i = 0; i < images.size(); i++) {
imageList.add(images.getString(i));
}
review.setImages(imageList);
}
// 追评
review.setHasAppend(json.getBooleanValue("has_append"));
review.setAppendContent(json.getString("append_content"));
review.setAppendCreated(json.getString("append_created"));
// 商家回复
review.setSellerReply(json.getString("seller_reply"));
review.setSellerReplyTime(json.getString("seller_reply_time"));
// 评论标签
JSONArray tags = json.getJSONArray("comment_tags");
if (tags != null) {
List<String> tagList = new ArrayList<>();
for (int i = 0; i < tags.size(); i++) {
tagList.add(tags.getString(i));
}
review.setCommentTags(tagList);
}
return review;
}
// ==================== 数据模型 ====================
public static class ReviewPageResult {
private boolean success;
private String errorCode;
private String errorMsg;
private int totalResults;
private List<Review> reviews;
public ReviewPageResult(boolean success, int totalResults, List<Review> reviews) {
this.success = success;
this.totalResults = totalResults;
this.reviews = reviews;
}
public static ReviewPageResult error(String code, String msg) {
ReviewPageResult r = new ReviewPageResult(false, 0, new ArrayList<>());
r.errorCode = code;
r.errorMsg = msg;
return r;
}
// Getters & Setters
public boolean isSuccess() { return success; }
public String getErrorCode() { return errorCode; }
public String getErrorMsg() { return errorMsg; }
public int getTotalResults() { return totalResults; }
public List<Review> getReviews() { return reviews; }
}
public static class Review {
private String reviewId;
private String userNick;
private boolean isAnonymous;
private int rate; // 评分 1-5
private String content; // 评论内容
private String created; // 评论时间
private String skuInfo; // SKU 规格
private int usefulNum; // 有用数
private List<String> images; // 晒图 URL 列表
// 追评
private boolean hasAppend;
private String appendContent;
private String appendCreated;
// 商家回复
private String sellerReply;
private String sellerReplyTime;
// 评论标签
private List<String> commentTags;
// Getters & Setters
public String getReviewId() { return reviewId; }
public void setReviewId(String reviewId) { this.reviewId = reviewId; }
public String getUserNick() { return userNick; }
public void setUserNick(String userNick) { this.userNick = userNick; }
public boolean isAnonymous() { return isAnonymous; }
public void setAnonymous(boolean anonymous) { isAnonymous = anonymous; }
public int getRate() { return rate; }
public void setRate(int rate) { this.rate = rate; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getCreated() { return created; }
public void setCreated(String created) { this.created = created; }
public String getSkuInfo() { return skuInfo; }
public void setSkuInfo(String skuInfo) { this.skuInfo = skuInfo; }
public int getUsefulNum() { return usefulNum; }
public void setUsefulNum(int usefulNum) { this.usefulNum = usefulNum; }
public List<String> getImages() { return images; }
public void setImages(List<String> images) { this.images = images; }
public boolean isHasAppend() { return hasAppend; }
public void setHasAppend(boolean hasAppend) { this.hasAppend = hasAppend; }
public String getAppendContent() { return appendContent; }
public void setAppendContent(String appendContent) { this.appendContent = appendContent; }
public String getAppendCreated() { return appendCreated; }
public void setAppendCreated(String appendCreated) { this.appendCreated = appendCreated; }
public String getSellerReply() { return sellerReply; }
public void setSellerReply(String sellerReply) { this.sellerReply = sellerReply; }
public String getSellerReplyTime() { return sellerReplyTime; }
public void setSellerReplyTime(String sellerReplyTime) { this.sellerReplyTime = sellerReplyTime; }
public List<String> getCommentTags() { return commentTags; }
public void setCommentTags(List<String> commentTags) { this.commentTags = commentTags; }
@Override
public String toString() {
return String.format("Review{rate=%d, user='%s', content='%s...', created='%s'}",
rate, userNick, content != null ? content.substring(0, Math.min(20, content.length())) : "", created);
}
}
}
四、情感分析预处理工具 接口测试
import java.util.*;
import java.util.regex.Pattern;
/**
* 评论情感分析预处理工具
* 基于关键词规则的情感倾向判断
*/
public class ReviewSentimentAnalyzer {
// 正面情感词库
private static final Set<String> POSITIVE_WORDS = new HashSet<>(Arrays.asList(
"好", "不错", "满意", "喜欢", "推荐", "值", "棒", "完美", "优秀", "给力",
"质量好", "做工精细", "面料柔软", "尺码标准", "性价比高", "物流快", "服务好",
"nice", "good", "great", "excellent", "perfect", "love", "amazing"
));
// 负面情感词库
private static final Set<String> NEGATIVE_WORDS = new HashSet<>(Arrays.asList(
"差", "不好", "失望", "垃圾", "坑", "骗", "假", "烂", "糟", "劣质",
"质量差", "做工粗糙", "面料硬", "尺码不准", "性价比低", "物流慢", "服务差",
"bad", "terrible", "worst", "hate", "disappointed", "fake", "poor"
));
// 广告/刷单过滤关键词
private static final Set<String> SPAM_KEYWORDS = new HashSet<>(Arrays.asList(
"好评返现", "返红包", "加微信", "刷单", "兼职", "联系客服", "截图返现"
));
/**
* 分析单条评论的情感倾向
*/
public SentimentResult analyze(TaobaoReviewClient.Review review) {
SentimentResult result = new SentimentResult();
result.setReviewId(review.getReviewId());
result.setContent(review.getContent());
// 1. 广告过滤
if (isSpam(review.getContent())) {
result.setSpam(true);
result.setSentiment("spam");
return result;
}
// 2. 基于评分快速判断
int rate = review.getRate();
if (rate >= 4) {
result.setSentiment("positive");
result.setConfidence(0.8);
} else if (rate <= 2) {
result.setSentiment("negative");
result.setConfidence(0.8);
} else {
// 3. 基于文本内容判断
result.setSentiment(analyzeText(review.getContent()));
result.setConfidence(0.6);
}
// 4. 提取关键词
result.setKeywords(extractKeywords(review.getContent()));
// 5. 判断是否有图/追评(通常有图/追评的可信度更高)
result.setHasImage(review.getImages() != null && !review.getImages().isEmpty());
result.setHasAppend(review.isHasAppend());
return result;
}
/**
* 批量分析评论列表
*/
public SentimentReport analyzeBatch(List<TaobaoReviewClient.Review> reviews) {
SentimentReport report = new SentimentReport();
report.setTotalCount(reviews.size());
int positiveCount = 0;
int negativeCount = 0;
int neutralCount = 0;
int spamCount = 0;
Map<String, Integer> keywordFreq = new HashMap<>();
Map<String, Integer> skuRatingMap = new HashMap<>();
for (TaobaoReviewClient.Review review : reviews) {
SentimentResult result = analyze(review);
switch (result.getSentiment()) {
case "positive" -> positiveCount++;
case "negative" -> negativeCount++;
case "spam" -> spamCount++;
default -> neutralCount++;
}
// 统计关键词
for (String kw : result.getKeywords()) {
keywordFreq.merge(kw, 1, Integer::sum);
}
// 按 SKU 统计评分
String sku = review.getSkuInfo();
if (sku != null && !sku.isEmpty()) {
skuRatingMap.merge(sku, review.getRate(), Integer::sum);
}
}
report.setPositiveCount(positiveCount);
report.setNegativeCount(negativeCount);
report.setNeutralCount(neutralCount);
report.setSpamCount(spamCount);
report.setPositiveRate((double) positiveCount / reviews.size());
// 排序高频关键词
List<Map.Entry<String, Integer>> sortedKeywords = keywordFreq.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(20)
.toList();
report.setTopKeywords(sortedKeywords);
return report;
}
private boolean isSpam(String content) {
if (content == null) return false;
for (String keyword : SPAM_KEYWORDS) {
if (content.contains(keyword)) return true;
}
return false;
}
private String analyzeText(String content) {
if (content == null || content.isEmpty()) return "neutral";
int posScore = 0;
int negScore = 0;
for (String word : POSITIVE_WORDS) {
if (content.contains(word)) posScore++;
}
for (String word : NEGATIVE_WORDS) {
if (content.contains(word)) negScore++;
}
if (posScore > negScore) return "positive";
if (negScore > posScore) return "negative";
return "neutral";
}
private List<String> extractKeywords(String content) {
List<String> keywords = new ArrayList<>();
if (content == null) return keywords;
for (String word : POSITIVE_WORDS) {
if (content.contains(word)) keywords.add(word);
}
for (String word : NEGATIVE_WORDS) {
if (content.contains(word)) keywords.add(word);
}
return keywords;
}
// ==================== 数据模型 ====================
public static class SentimentResult {
private String reviewId;
private String content;
private String sentiment; // positive / negative / neutral / spam
private double confidence;
private List<String> keywords;
private boolean hasImage;
private boolean hasAppend;
private boolean isSpam;
// Getters & Setters
public String getReviewId() { return reviewId; }
public void setReviewId(String reviewId) { this.reviewId = reviewId; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getSentiment() { return sentiment; }
public void setSentiment(String sentiment) { this.sentiment = sentiment; }
public double getConfidence() { return confidence; }
public void setConfidence(double confidence) { this.confidence = confidence; }
public List<String> getKeywords() { return keywords; }
public void setKeywords(List<String> keywords) { this.keywords = keywords; }
public boolean isHasImage() { return hasImage; }
public void setHasImage(boolean hasImage) { this.hasImage = hasImage; }
public boolean isHasAppend() { return hasAppend; }
public void setHasAppend(boolean hasAppend) { this.hasAppend = hasAppend; }
public boolean isSpam() { return isSpam; }
public void setSpam(boolean spam) { isSpam = spam; }
}
public static class SentimentReport {
private int totalCount;
private int positiveCount;
private int negativeCount;
private int neutralCount;
private int spamCount;
private double positiveRate;
private List<Map.Entry<String, Integer>> topKeywords;
@Override
public String toString() {
return String.format(
"SentimentReport{total=%d, positive=%d(%.1f%%), negative=%d, neutral=%d, spam=%d}",
totalCount, positiveCount, positiveRate * 100, negativeCount, neutralCount, spamCount
);
}
// Getters & Setters
public int getTotalCount() { return totalCount; }
public void setTotalCount(int totalCount) { this.totalCount = totalCount; }
public int getPositiveCount() { return positiveCount; }
public void setPositiveCount(int positiveCount) { this.positiveCount = positiveCount; }
public int getNegativeCount() { return negativeCount; }
public void setNegativeCount(int negativeCount) { this.negativeCount = negativeCount; }
public int getNeutralCount() { return neutralCount; }
public void setNeutralCount(int neutralCount) { this.neutralCount = neutralCount; }
public int getSpamCount() { return spamCount; }
public void setSpamCount(int spamCount) { this.spamCount = spamCount; }
public double getPositiveRate() { return positiveRate; }
public void setPositiveRate(double positiveRate) { this.positiveRate = positiveRate; }
public List<Map.Entry<String, Integer>> getTopKeywords() { return topKeywords; }
public void setTopKeywords(List<Map.Entry<String, Integer>> topKeywords) { this.topKeywords = topKeywords; }
}
}
五、完整使用示例
public class TaobaoReviewDemo {
public static void main(String[] args) {
// 初始化客户端
TaobaoReviewClient client = new TaobaoReviewClient(
"your_app_key",
"your_app_secret",
"your_session_key" // 可选
);
String numIid = "6801234567890"; // 目标商品 ID
// ========== 示例1:获取单页评论 ==========
System.out.println("=== 获取第1页评论 ===");
TaobaoReviewClient.ReviewPageResult pageResult = client.getReviews(
numIid, 1, 20, null, null, null
);
if (pageResult.isSuccess()) {
System.out.println("总评论数: " + pageResult.getTotalResults());
for (TaobaoReviewClient.Review review : pageResult.getReviews()) {
System.out.println(review);
}
}
// ========== 示例2:获取全部评论 ==========
System.out.println("\n=== 获取全部评论 ===");
List<TaobaoReviewClient.Review> allReviews = client.getAllReviews(
numIid, null, null, null
);
System.out.println("共获取 " + allReviews.size() + " 条评论");
// ========== 示例3:仅获取差评 ==========
System.out.println("\n=== 获取差评 ===");
List<TaobaoReviewClient.Review> badReviews = client.getAllReviews(
numIid, 3, null, null // review_type=3 表示差评
);
System.out.println("差评数量: " + badReviews.size());
// ========== 示例4:情感分析 ==========
System.out.println("\n=== 情感分析 ===");
ReviewSentimentAnalyzer analyzer = new ReviewSentimentAnalyzer();
ReviewSentimentAnalyzer.SentimentReport report = analyzer.analyzeBatch(allReviews);
System.out.println(report);
// 输出高频关键词
System.out.println("\n高频关键词:");
for (Map.Entry<String, Integer> entry : report.getTopKeywords()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue() + "次");
}
// ========== 示例5:增量拉取 ==========
System.out.println("\n=== 增量拉取(2026-06-01 之后)===");
List<TaobaoReviewClient.Review> newReviews = client.getIncrementalReviews(
numIid, "2026-06-01 00:00:00"
);
System.out.println("新增评论: " + newReviews.size() + " 条");
}
}
六、常见问题与解决方案
| 问题现象 | 错误码 | 可能原因 | 解决方案 |
|---|---|---|---|
| 权限不足 | 11 / 403 |
未申请评论接口权限或权限被收回 | 在开放平台申请 taobao.item.reviews.get 权限,企业认证通过率更高 |
| 调用频率超限 | 50001 |
QPS 超过限制(企业 3~10,个人 ≤2) | 实现限流控制,增加请求间隔,或申请扩容 |
| 签名错误 | 40003 |
MD5 签名生成错误 | 检查参数排序、AppSecret 是否正确、是否遗漏参数 |
| 商品不存在 | 400 |
num_iid 错误或商品已下架 | 确认商品 ID 正确且商品处于上架状态 |
| 数据为空 | - | 商品无评论或评论超过 180 天 | 检查商品是否有评论,注意数据仅保留近 180 天 |
| 仅返回部分字段 | - | 接口权限被阉割 | 淘宝逐步收紧权限,部分字段可能不再返回 |
七、最佳实践建议
-
限流控制:严格限制 QPS ≤ 5,避免触发平台限流导致账号受限
-
增量同步:记录上次同步时间戳,避免全量拉取浪费配额
-
数据缓存:评论数据变化频率较低,建议本地缓存 1-6 小时
-
异常重试:网络异常时实现指数退避重试(1s, 2s, 4s)
-
数据脱敏:遵守平台协议,用户昵称等敏感信息需脱敏处理
-
容灾设计:官方接口可能随时调整,预留爬虫或第三方接口作为兜底方案
-
合规使用:评论数据仅用于内部分析,禁止对外传播或商用
八、扩展应用场景
基于淘宝评论 API 可构建以下应用:
-
竞品口碑监控:定期抓取竞品评论,分析用户痛点和产品优劣势
-
差评预警系统:实时监控差评,自动通知运营团队处理
-
选品决策支持:分析类目评论高频词,挖掘市场需求
-
用户画像构建:基于评论内容和 SKU 偏好分析用户群体特征
-
商品质量评估:综合评分、好评率、追评率评估商品质量
-
客服智能回复:基于评论内容训练客服话术模型
更多推荐

所有评论(0)