淘宝商品详情API接口开发指南:应用市场选品比价实战
在电商应用市场(如应用宝、App Store)中,选品比价类APP是用户量最大的工具型应用之一。这类应用的核心能力在于实时、准确地获取淘宝、京东、1688等多平台的商品数据,为用户提供"同款比价""历史价格追踪""促销提醒"等核心功能。本文将深入讲解如何通过淘宝商品详情API接口(
taobao.item.get)获取商品数据,并构建一套完整的选品比价系统。一、淘宝商品详情API接口概述
1.1 核心接口介绍
表格
| 接口名称 | 功能描述 | 适用场景 |
|---|---|---|
taobao.item.get | 获取单个商品全量详情 | 商品详情页展示、比价分析 |
taobao.items.list.get | 批量获取商品列表 | 商品库同步、批量监控 |
taobao.tbk.item.get | 淘宝客商品详情 | CPS推广、返利应用 |
taobao.item.search | 关键词搜索商品 | 选品发现、竞品监控 |
taobao.item.reviews.get | 获取商品评价 | 口碑分析、差评预警 |
1.2 接口核心能力
plain
┌─────────────────────────────────────────┐
│ taobao.item.get 数据能力 │
├─────────────────────────────────────────┤
│ 基础信息:标题、副标题、类目、品牌 │
│ 价格信息:售价、原价、促销价、优惠券 │
│ 库存信息:总库存、SKU库存、预售状态 │
│ 销量信息:月销量、总销量、评价数 │
│ 图片信息:主图、详情图、SKU图、视频 │
│ SKU信息:规格组合、价格差异、库存分布 │
│ 店铺信息:店铺名、评分、DSR │
│ 物流信息:发货地、运费模板 │
│ 促销信息:满减、优惠券、限时折扣 │
└─────────────────────────────────────────┘二、准备工作
2.1 注册淘宝开放平台开发者账号
- 注册开发者账号
- 完成实名认证(个人或企业)
- 创建应用,选择"网站应用"或"自用型应用"
表格
| 凭证 | 说明 |
|---|---|
App Key | 应用唯一标识 |
App Secret | 应用密钥,用于签名 |
Session Key | 用户授权令牌(部分接口需要) |
2.2 申请接口权限
表格
| 接口 | 所需权限 | 申请条件 |
|---|---|---|
taobao.item.get | 商品详情API | 基础权限,较易申请 |
taobao.tbk.item.get | 淘宝客商品API | 需加入淘宝客联盟 |
taobao.item.search | 商品搜索API | 需企业认证 |
2.3 Maven依赖配置
xml
<dependencies>
<!-- HTTP请求 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<!-- JSON解析 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.43</version>
</dependency>
<!-- MD5加密 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.16.0</version>
</dependency></dependencies>三、核心代码实现
3.1 TOP签名工具类
淘宝开放平台(TOP)签名规则:所有业务参数+公共参数(不含sign、file字段,空值剔除),按key ASCII升序排列,拼接为
app_secret+key1value1key2value2...+app_secret,最后进行MD5加密并转大写。java
import org.apache.commons.codec.digest.DigestUtils;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.Map;import java.util.TreeMap;/**
* 淘宝开放平台(TOP)签名工具类
* 签名规则:app_secret + 按key升序拼接(key+value) + app_secret → MD5 → 大写
*/public class TopSignUtil {
/**
* 生成TOP API签名
* @param params 请求参数(不含sign)
* @param appSecret 应用密钥
* @return 大写MD5签名
*/
public static String generateSign(Map<String, String> params, String appSecret) {
// 1. 剔除sign和空值参数,按key ASCII升序排列
TreeMap<String, String> sortedParams = new TreeMap<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (!"sign".equals(key) && !"file".equals(key)
&& value != null && !value.trim().isEmpty()) {
sortedParams.put(key, value);
}
}
// 2. 按key升序拼接 key+value
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
sb.append(entry.getKey()).append(entry.getValue());
}
// 3. 首尾拼接app_secret
String toSign = appSecret + sb.toString() + appSecret;
// 4. MD5加密,转大写
return DigestUtils.md5Hex(toSign).toUpperCase();
}
/**
* URL编码参数值
*/
public static String urlEncode(String value) {
try {
return URLEncoder.encode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("URL编码失败", e);
}
}}3.2 淘宝API基础客户端
java
import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import org.apache.http.client.methods.HttpPost;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;import java.util.HashMap;import java.util.Map;/**
* 淘宝API基础客户端
*/public class TopApiClient {
// 生产环境网关
private static final String PROD_GATEWAY = "https://gw.api.taobao.com/router/rest";
// 沙箱环境网关(测试用)
private static final String SANDBOX_GATEWAY = "https://gw.api.tbsandbox.com/router/rest";
private final String appKey;
private final String appSecret;
private final String sessionKey;
private final boolean useSandbox;
public TopApiClient(String appKey, String appSecret, String sessionKey) {
this(appKey, appSecret, sessionKey, false);
}
public TopApiClient(String appKey, String appSecret, String sessionKey, boolean useSandbox) {
this.appKey = appKey;
this.appSecret = appSecret;
this.sessionKey = sessionKey;
this.useSandbox = useSandbox;
}
/**
* 执行API请求
* @param method 接口方法名
* @param bizParams 业务参数
* @return JSON响应
*/
public JSONObject execute(String method, Map<String, String> bizParams) {
try {
// 构建完整参数
Map<String, String> params = new HashMap<>();
params.put("method", method);
params.put("app_key", appKey);
params.put("timestamp", getCurrentTimestamp());
params.put("format", "json");
params.put("v", "2.0");
params.put("sign_method", "md5");
// 添加session(需要授权的接口)
if (sessionKey != null && !sessionKey.isEmpty()) {
params.put("session", sessionKey);
}
// 添加业务参数
for (Map.Entry<String, String> entry : bizParams.entrySet()) {
params.put(entry.getKey(), entry.getValue());
}
// 生成签名
String sign = TopSignUtil.generateSign(params, appSecret);
params.put("sign", sign);
// 构建请求URL
String gateway = useSandbox ? SANDBOX_GATEWAY : PROD_GATEWAY;
String url = buildUrl(gateway, params);
// 发送POST请求
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
String response = EntityUtils.toString(
client.execute(httpPost).getEntity(), "UTF-8");
return JSON.parseObject(response);
}
} catch (Exception e) {
throw new RuntimeException("API请求失败: " + e.getMessage(), e);
}
}
/**
* 获取当前时间戳(格式:yyyy-MM-dd HH:mm:ss)
*/
private String getCurrentTimestamp() {
return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new java.util.Date());
}
/**
* 构建带参数的URL
*/
private String buildUrl(String gateway, Map<String, String> params) {
StringBuilder url = new StringBuilder(gateway);
url.append("?");
for (Map.Entry<String, String> entry : params.entrySet()) {
url.append(entry.getKey())
.append("=")
.append(TopSignUtil.urlEncode(entry.getValue()))
.append("&");
}
// 移除末尾的&
return url.substring(0, url.length() - 1);
}}3.3 商品详情服务类
java
import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/**
* 淘宝商品详情服务
*/public class TaobaoItemService {
private final TopApiClient apiClient;
public TaobaoItemService(TopApiClient apiClient) {
this.apiClient = apiClient;
}
/**
* 获取单个商品详情
* @param numIid 商品数字ID
* @return 商品详情对象
*/
public TaobaoItemDetail getItemDetail(String numIid) {
Map<String, String> bizParams = new HashMap<>();
bizParams.put("fields", "num_iid,title,price,original_price,pic_url,detail_url,"
+ "num,post_fee,express_fee,ems_fee,item_weight,item_size,"
+ "seller_id,nick,stuff_status,location,has_discount,"
+ "volume,has_invoice,has_warranty,has_showcase,"
+ "modified,approve_status,product_id,outer_id,"
+ "is_virtual,is_taobao,is_ex,is_timing,"
+ "auction_point,property_alias,props_name,props,"
+ "sku,desc,item_imgs,prop_imgs,video,"
+ "sell_point,coupon_info,shopinfo");
bizParams.put("num_iid", numIid);
JSONObject response = apiClient.execute("taobao.item.get", bizParams);
// 解析响应
if (response.containsKey("item_get_response")) {
JSONObject itemJson = response.getJSONObject("item_get_response")
.getJSONObject("item");
return parseItemDetail(itemJson);
} else if (response.containsKey("error_response")) {
JSONObject error = response.getJSONObject("error_response");
throw new RuntimeException("接口错误: " + error.getString("msg"));
}
throw new RuntimeException("未知响应格式");
}
/**
* 批量获取商品详情(最多20个)
*/
public List<TaobaoItemDetail> getItemDetailBatch(List<String> numIids) {
if (numIids.size() > 20) {
throw new IllegalArgumentException("单次最多查询20个商品");
}
Map<String, String> bizParams = new HashMap<>();
bizParams.put("fields", "num_iid,title,price,pic_url,volume,nick");
bizParams.put("num_iids", String.join(",", numIids));
JSONObject response = apiClient.execute("taobao.items.list.get", bizParams);
List<TaobaoItemDetail> items = new ArrayList<>();
if (response.containsKey("items_list_get_response")) {
JSONArray itemsArray = response.getJSONObject("items_list_get_response")
.getJSONObject("items").getJSONArray("item");
for (int i = 0; i < itemsArray.size(); i++) {
items.add(parseItemDetail(itemsArray.getJSONObject(i)));
}
}
return items;
}
/**
* 关键词搜索商品
* @param keyword 搜索关键词
* @param page 页码
* @param pageSize 每页数量
*/
public List<TaobaoItemDetail> searchItems(String keyword, int page, int pageSize) {
Map<String, String> bizParams = new HashMap<>();
bizParams.put("fields", "num_iid,title,pict_url,small_images,reserve_price,"
+ "zk_final_price,user_type,provcity,item_url,"
+ "seller_id,volume,nick");
bizParams.put("q", keyword);
bizParams.put("page_no", String.valueOf(page));
bizParams.put("page_size", String.valueOf(pageSize));
JSONObject response = apiClient.execute("taobao.tbk.item.get", bizParams);
List<TaobaoItemDetail> items = new ArrayList<>();
if (response.containsKey("tbk_item_get_response")) {
JSONArray results = response.getJSONObject("tbk_item_get_response")
.getJSONObject("results").getJSONArray("n_tbk_item");
for (int i = 0; i < results.size(); i++) {
items.add(parseTbkItem(results.getJSONObject(i)));
}
}
return items;
}
/**
* 解析商品详情JSON
*/
private TaobaoItemDetail parseItemDetail(JSONObject json) {
TaobaoItemDetail item = new TaobaoItemDetail();
item.setNumIid(json.getString("num_iid"));
item.setTitle(json.getString("title"));
item.setPrice(json.getDouble("price"));
item.setOriginalPrice(json.getDouble("original_price"));
item.setPicUrl(json.getString("pic_url"));
item.setDetailUrl(json.getString("detail_url"));
item.setNum(json.getIntValue("num")); // 库存
item.setVolume(json.getIntValue("volume")); // 销量
item.setNick(json.getString("nick")); // 卖家昵称
item.setLocation(json.getString("location"));
item.setPostFee(json.getString("post_fee"));
item.setExpressFee(json.getString("express_fee"));
item.setEmsFee(json.getString("ems_fee"));
item.setItemWeight(json.getString("item_weight"));
item.setItemSize(json.getString("item_size"));
item.setSellerId(json.getLong("seller_id"));
item.setStuffStatus(json.getString("stuff_status"));
item.setHasDiscount(json.getBooleanValue("has_discount"));
item.setHasInvoice(json.getBooleanValue("has_invoice"));
item.setHasWarranty(json.getBooleanValue("has_warranty"));
item.setApproveStatus(json.getString("approve_status"));
item.setProductId(json.getLong("product_id"));
item.setOuterId(json.getString("outer_id"));
item.setSellPoint(json.getString("sell_point"));
item.setDesc(json.getString("desc"));
// 解析图片列表
if (json.containsKey("item_imgs")) {
JSONArray imgs = json.getJSONObject("item_imgs").getJSONArray("item_img");
List<String> imageList = new ArrayList<>();
for (int i = 0; i < imgs.size(); i++) {
imageList.add(imgs.getJSONObject(i).getString("url"));
}
item.setItemImages(imageList);
}
// 解析SKU信息
if (json.containsKey("skus")) {
JSONArray skus = json.getJSONObject("skus").getJSONArray("sku");
List<SkuInfo> skuList = new ArrayList<>();
for (int i = 0; i < skus.size(); i++) {
JSONObject skuJson = skus.getJSONObject(i);
SkuInfo sku = new SkuInfo();
sku.setSkuId(skuJson.getString("sku_id"));
sku.setProperties(skuJson.getString("properties_name"));
sku.setPrice(skuJson.getDouble("price"));
sku.setQuantity(skuJson.getIntValue("quantity"));
sku.setOuterId(skuJson.getString("outer_id"));
skuList.add(sku);
}
item.setSkus(skuList);
}
// 解析店铺信息
if (json.containsKey("shopinfo")) {
JSONObject shop = json.getJSONObject("shopinfo");
ShopInfo shopInfo = new ShopInfo();
shopInfo.setShopName(shop.getString("shop_name"));
shopInfo.setShopUrl(shop.getString("shop_url"));
shopInfo.setCreditLevel(shop.getIntValue("credit_level"));
item.setShopInfo(shopInfo);
}
return item;
}
private TaobaoItemDetail parseTbkItem(JSONObject json) {
TaobaoItemDetail item = new TaobaoItemDetail();
item.setNumIid(json.getString("num_iid"));
item.setTitle(json.getString("title"));
item.setPicUrl(json.getString("pict_url"));
item.setPrice(json.getDouble("zk_final_price"));
item.setOriginalPrice(json.getDouble("reserve_price"));
item.setVolume(json.getIntValue("volume"));
item.setNick(json.getString("nick"));
item.setLocation(json.getString("provcity"));
item.setUserType(json.getIntValue("user_type")); // 0=C店, 1=天猫
return item;
}}3.4 商品详情实体类
java
import java.util.List;/**
* 淘宝商品详情实体类
*/public class TaobaoItemDetail {
// 基础信息
private String numIid; // 商品数字ID
private String title; // 商品标题
private String subTitle; // 副标题
private Double price; // 当前售价
private Double originalPrice; // 原价
private String picUrl; // 主图URL
private String detailUrl; // 详情页URL
// 库存与销量
private Integer num; // 库存数量
private Integer volume; // 销量
private String stuffStatus; // 商品新旧:new=全新,unused=闲置
// 物流信息
private String postFee; // 平邮费用
private String expressFee; // 快递费用
private String emsFee; // EMS费用
private String location; // 发货地
private String itemWeight; // 商品重量
private String itemSize; // 商品尺寸
// 卖家信息
private Long sellerId; // 卖家ID
private String nick; // 卖家昵称
private ShopInfo shopInfo; // 店铺信息
private Integer userType; // 0=淘宝C店, 1=天猫
// 商品属性
private String props; // 商品属性
private String propsName; // 属性名称
private String propertyAlias; // 属性别名
private String sellPoint; // 卖点
private String desc; // 商品描述(HTML)
// 状态与标识
private String approveStatus; // 商品状态:onsale=出售中,instock=库中
private Boolean hasDiscount; // 是否支持会员折扣
private Boolean hasInvoice; // 是否支持发票
private Boolean hasWarranty; // 是否支持保修
private Boolean hasShowcase; // 是否橱窗推荐
private Long productId; // 产品ID
private String outerId; // 商家编码
// 媒体信息
private List<String> itemImages; // 商品图片列表
private List<SkuInfo> skus; // SKU列表
// Getters and Setters
public String getNumIid() { return numIid; }
public void setNumIid(String numIid) { this.numIid = numIid; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getSubTitle() { return subTitle; }
public void setSubTitle(String subTitle) { this.subTitle = subTitle; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
public Double getOriginalPrice() { return originalPrice; }
public void setOriginalPrice(Double originalPrice) { this.originalPrice = originalPrice; }
public String getPicUrl() { return picUrl; }
public void setPicUrl(String picUrl) { this.picUrl = picUrl; }
public String getDetailUrl() { return detailUrl; }
public void setDetailUrl(String detailUrl) { this.detailUrl = detailUrl; }
public Integer getNum() { return num; }
public void setNum(Integer num) { this.num = num; }
public Integer getVolume() { return volume; }
public void setVolume(Integer volume) { this.volume = volume; }
public String getStuffStatus() { return stuffStatus; }
public void setStuffStatus(String stuffStatus) { this.stuffStatus = stuffStatus; }
public String getPostFee() { return postFee; }
public void setPostFee(String postFee) { this.postFee = postFee; }
public String getExpressFee() { return expressFee; }
public void setExpressFee(String expressFee) { this.expressFee = expressFee; }
public String getEmsFee() { return emsFee; }
public void setEmsFee(String emsFee) { this.emsFee = emsFee; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
public String getItemWeight() { return itemWeight; }
public void setItemWeight(String itemWeight) { this.itemWeight = itemWeight; }
public String getItemSize() { return itemSize; }
public void setItemSize(String itemSize) { this.itemSize = itemSize; }
public Long getSellerId() { return sellerId; }
public void setSellerId(Long sellerId) { this.sellerId = sellerId; }
public String getNick() { return nick; }
public void setNick(String nick) { this.nick = nick; }
public ShopInfo getShopInfo() { return shopInfo; }
public void setShopInfo(ShopInfo shopInfo) { this.shopInfo = shopInfo; }
public Integer getUserType() { return userType; }
public void setUserType(Integer userType) { this.userType = userType; }
public String getProps() { return props; }
public void setProps(String props) { this.props = props; }
public String getPropsName() { return propsName; }
public void setPropsName(String propsName) { this.propsName = propsName; }
public String getPropertyAlias() { return propertyAlias; }
public void setPropertyAlias(String propertyAlias) { this.propertyAlias = propertyAlias; }
public String getSellPoint() { return sellPoint; }
public void setSellPoint(String sellPoint) { this.sellPoint = sellPoint; }
public String getDesc() { return desc; }
public void setDesc(String desc) { this.desc = desc; }
public String getApproveStatus() { return approveStatus; }
public void setApproveStatus(String approveStatus) { this.approveStatus = approveStatus; }
public Boolean getHasDiscount() { return hasDiscount; }
public void setHasDiscount(Boolean hasDiscount) { this.hasDiscount = hasDiscount; }
public Boolean getHasInvoice() { return hasInvoice; }
public void setHasInvoice(Boolean hasInvoice) { this.hasInvoice = hasInvoice; }
public Boolean getHasWarranty() { return hasWarranty; }
public void setHasWarranty(Boolean hasWarranty) { this.hasWarranty = hasWarranty; }
public Boolean getHasShowcase() { return hasShowcase; }
public void setHasShowcase(Boolean hasShowcase) { this.hasShowcase = hasShowcase; }
public Long getProductId() { return productId; }
public void setProductId(Long productId) { this.productId = productId; }
public String getOuterId() { return outerId; }
public void setOuterId(String outerId) { this.outerId = outerId; }
public List<String> getItemImages() { return itemImages; }
public void setItemImages(List<String> itemImages) { this.itemImages = itemImages; }
public List<SkuInfo> getSkus() { return skus; }
public void setSkus(List<SkuInfo> skus) { this.skus = skus; }
@Override
public String toString() {
return "TaobaoItemDetail{" +
"numIid='" + numIid + '\'' +
", title='" + title + '\'' +
", price=" + price +
", originalPrice=" + originalPrice +
", num=" + num +
", volume=" + volume +
", nick='" + nick + '\'' +
", location='" + location + '\'' +
'}';
}
// SKU信息内部类
public static class SkuInfo {
private String skuId;
private String properties;
private Double price;
private Integer quantity;
private String outerId;
public String getSkuId() { return skuId; }
public void setSkuId(String skuId) { this.skuId = skuId; }
public String getProperties() { return properties; }
public void setProperties(String properties) { this.properties = properties; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
public Integer getQuantity() { return quantity; }
public void setQuantity(Integer quantity) { this.quantity = quantity; }
public String getOuterId() { return outerId; }
public void setOuterId(String outerId) { this.outerId = outerId; }
}
// 店铺信息内部类
public static class ShopInfo {
private String shopName;
private String shopUrl;
private Integer creditLevel;
public String getShopName() { return shopName; }
public void setShopName(String shopName) { this.shopName = shopName; }
public String getShopUrl() { return shopUrl; }
public void setShopUrl(String shopUrl) { this.shopUrl = shopUrl; }
public Integer getCreditLevel() { return creditLevel; }
public void setCreditLevel(Integer creditLevel) { this.creditLevel = creditLevel; }
}}3.5 主程序入口
java
public class TaobaoItemDemo {
public static void main(String[] args) {
// 配置信息(请替换为实际值)
String appKey = "your_app_key";
String appSecret = "your_app_secret";
String sessionKey = "your_session_key"; // 部分接口需要
String numIid = "12345678901"; // 淘宝商品数字ID
try {
// 初始化客户端(沙箱环境测试)
TopApiClient apiClient = new TopApiClient(appKey, appSecret, sessionKey, true);
TaobaoItemService itemService = new TaobaoItemService(apiClient);
System.out.println("正在查询商品详情,num_iid: " + numIid);
System.out.println("=".repeat(60));
// 调用接口获取商品详情
TaobaoItemDetail item = itemService.getItemDetail(numIid);
// 输出商品信息
System.out.println("【商品基础信息】");
System.out.println("商品ID: " + item.getNumIid());
System.out.println("商品标题: " + item.getTitle());
System.out.println("当前售价: ¥" + item.getPrice());
System.out.println("原价: ¥" + item.getOriginalPrice());
System.out.println("库存: " + item.getNum() + "件");
System.out.println("销量: " + item.getVolume() + "件");
System.out.println("主图: " + item.getPicUrl());
System.out.println("详情页: " + item.getDetailUrl());
System.out.println("\n【物流信息】");
System.out.println("发货地: " + item.getLocation());
System.out.println("平邮: ¥" + item.getPostFee());
System.out.println("快递: ¥" + item.getExpressFee());
System.out.println("EMS: ¥" + item.getEmsFee());
System.out.println("重量: " + item.getItemWeight());
System.out.println("\n【卖家信息】");
System.out.println("卖家昵称: " + item.getNick());
System.out.println("卖家ID: " + item.getSellerId());
if (item.getShopInfo() != null) {
System.out.println("店铺名: " + item.getShopInfo().getShopName());
System.out.println("店铺链接: " + item.getShopInfo().getShopUrl());
}
System.out.println("\n【商品属性】");
System.out.println("是否全新: " + ("new".equals(item.getStuffStatus()) ? "是" : "否"));
System.out.println("是否支持发票: " + (item.getHasInvoice() != null && item.getHasInvoice() ? "是" : "否"));
System.out.println("是否支持保修: " + (item.getHasWarranty() != null && item.getHasWarranty() ? "是" : "否"));
System.out.println("卖点: " + item.getSellPoint());
System.out.println("\n【SKU规格】");
if (item.getSkus() != null) {
for (TaobaoItemDetail.SkuInfo sku : item.getSkus()) {
System.out.println(" - " + sku.getProperties()
+ " | 价格: ¥" + sku.getPrice()
+ " | 库存: " + sku.getQuantity() + "件");
}
}
System.out.println("\n【图片列表】");
if (item.getItemImages() != null) {
System.out.println("共" + item.getItemImages().size() + "张图片");
for (int i = 0; i < Math.min(3, item.getItemImages().size()); i++) {
System.out.println(" " + (i+1) + ". " + item.getItemImages().get(i));
}
}
// 关键词搜索示例
System.out.println("\n" + "=".repeat(60));
System.out.println("【关键词搜索示例】搜索: iPhone 16");
List<TaobaoItemDetail> searchResults = itemService.searchItems("iPhone 16", 1, 5);
System.out.println("找到" + searchResults.size() + "个商品:");
for (TaobaoItemDetail result : searchResults) {
System.out.println(" - " + result.getTitle()
+ " | ¥" + result.getPrice()
+ " | 销量:" + result.getVolume()
+ " | " + (result.getUserType() != null && result.getUserType() == 1 ? "天猫" : "淘宝"));
}
} catch (Exception e) {
System.err.println("程序执行异常: " + e.getMessage());
e.printStackTrace();
}
}}四、接口返回数据结构
4.1 成功响应示例
JSON
{
"item_get_response": {
"item": {
"num_iid": "12345678901",
"title": "Apple/苹果 iPhone 16 Pro Max 256GB 钛金属",
"price": "9999.00",
"original_price": "10999.00",
"pic_url": "https://img.alicdn.com/xxx.jpg",
"detail_url": "https://item.taobao.com/item.htm?id=12345678901",
"num": 5000,
"volume": 12500,
"post_fee": "0.00",
"express_fee": "0.00",
"ems_fee": "20.00",
"location": "上海",
"item_weight": "0.227",
"item_size": "159.9x76.7x8.25",
"seller_id": 123456789,
"nick": "苹果官方旗舰店",
"stuff_status": "new",
"has_discount": true,
"has_invoice": true,
"has_warranty": true,
"approve_status": "onsale",
"product_id": 1234567890,
"outer_id": "IP16PM-256-TITAN",
"sell_point": "A18芯片 4800万像素 超长续航",
"desc": "<div>商品详细描述HTML...</div>",
"item_imgs": {
"item_img": [
{"url": "https://img.alicdn.com/1.jpg"},
{"url": "https://img.alicdn.com/2.jpg"},
{"url": "https://img.alicdn.com/3.jpg"}
]
},
"skus": {
"sku": [
{
"sku_id": "1234567890123",
"properties_name": "1627207:3232483:颜色:黑色;20509:28315:内存:256GB",
"price": "9999.00",
"quantity": 2000,
"outer_id": "IP16PM-256-BLACK"
},
{
"sku_id": "1234567890124",
"properties_name": "1627207:3232484:颜色:白色;20509:28315:内存:256GB",
"price": "9999.00",
"quantity": 3000,
"outer_id": "IP16PM-256-WHITE"
}
]
},
"shopinfo": {
"shop_name": "苹果官方旗舰店",
"shop_url": "https://apple.tmall.com",
"credit_level": 18
}
}
}}4.2 错误响应示例
JSON
{
"error_response": {
"code": 27,
"msg": "Invalid session",
"sub_code": "isv.invalid-session",
"sub_msg": "Session无效或已过期"
}}五、核心返回字段说明
表格
| 字段分类 | 字段名 | 类型 | 说明 |
|---|---|---|---|
| 基础信息 | num_iid | String | 商品数字ID(淘宝唯一标识) |
title | String | 商品标题 | |
price | String | 当前售价 | |
original_price | String | 原价/市场价 | |
pic_url | String | 商品主图URL | |
detail_url | String | 商品详情页链接 | |
| 库存销量 | num | Integer | 库存数量 |
volume | Integer | 30天销量 | |
stuff_status | String | 新旧程度:new=全新 | |
| 物流信息 | post_fee | String | 平邮费用 |
express_fee | String | 快递费用 | |
ems_fee | String | EMS费用 | |
location | String | 发货地 | |
item_weight | String | 商品重量(kg) | |
item_size | String | 商品尺寸 | |
| 卖家信息 | seller_id | Long | 卖家ID |
nick | String | 卖家昵称 | |
user_type | Integer | 0=淘宝C店, 1=天猫 | |
| 商品属性 | props | String | 商品属性串 |
props_name | String | 属性名称串 | |
sell_point | String | 商品卖点 | |
desc | String | 商品描述(HTML) | |
| 状态标识 | approve_status | String | onsale=出售中, instock=库中 |
has_discount | Boolean | 是否支持会员折扣 | |
has_invoice | Boolean | 是否支持发票 | |
has_warranty | Boolean | 是否支持保修 | |
product_id | Long | 产品ID | |
outer_id | String | 商家编码 | |
| 媒体信息 | item_imgs | Array | 商品图片列表 |
| SKU信息 | skus | Array | SKU规格列表 |
| 店铺信息 | shopinfo | Object | 店铺信息 |
六、选品比价应用场景
6.1 同款比价系统架构
plain
┌─────────────────────────────────────────┐
│ 用户端(APP/小程序) │
│ 搜索商品 → 展示比价结果 → 跳转购买 │
├─────────────────────────────────────────┤
│ 比价服务端 │
│ 商品搜索 → 多平台采集 → 同款匹配 → 价格对比 │
├─────────────────────────────────────────┤
│ 数据采集层 │
│ 淘宝API │ 京东API │ 1688API │ 拼多多API │
├─────────────────────────────────────────┤
│ 数据存储层 │
│ MySQL │ Redis │ Elasticsearch │
└─────────────────────────────────────────┘6.2 同款匹配算法
java
/**
* 基于商品标题和属性的同款匹配
*/public class ItemMatcher {
/**
* 计算两个商品的相似度
* @return 相似度分数 (0-1)
*/
public double calculateSimilarity(TaobaoItemDetail item1, TaobaoItemDetail item2) {
double score = 0.0;
// 1. 标题相似度(Jaccard系数)
double titleSim = jaccardSimilarity(item1.getTitle(), item2.getTitle());
score += titleSim * 0.4;
// 2. 品牌匹配
if (extractBrand(item1.getTitle()).equals(extractBrand(item2.getTitle()))) {
score += 0.2;
}
// 3. 规格属性匹配
double propSim = compareProperties(item1.getProps(), item2.getProps());
score += propSim * 0.3;
// 4. 价格接近度
double priceRatio = Math.min(item1.getPrice(), item2.getPrice())
/ Math.max(item1.getPrice(), item2.getPrice());
score += priceRatio * 0.1;
return score;
}
private double jaccardSimilarity(String s1, String s2) {
Set<String> set1 = new HashSet<>(Arrays.asList(s1.split("")));
Set<String> set2 = new HashSet<>(Arrays.asList(s2.split("")));
Set<String> intersection = new HashSet<>(set1);
intersection.retainAll(set2);
Set<String> union = new HashSet<>(set1);
union.addAll(set2);
return (double) intersection.size() / union.size();
}
private String extractBrand(String title) {
// 从标题提取品牌名(需维护品牌词库)
String[] brands = {"Apple", "华为", "小米", "耐克", "阿迪达斯"};
for (String brand : brands) {
if (title.contains(brand)) return brand;
}
return "";
}
private double compareProperties(String props1, String props2) {
// 比较关键属性(颜色、尺码、内存等)
// 实现略...
return 0.5;
}}6.3 价格监控与预警
java
/**
* 价格监控服务
*/public class PriceMonitorService {
/**
* 监控商品价格变动
*/
public void monitorPrice(String numIid, double threshold) {
// 获取当前价格
TaobaoItemDetail current = itemService.getItemDetail(numIid);
double currentPrice = current.getPrice();
// 获取历史价格
Double historicalPrice = priceHistoryDao.getLatestPrice(numIid);
if (historicalPrice != null) {
double changeRate = (currentPrice - historicalPrice) / historicalPrice;
if (Math.abs(changeRate) >= threshold) {
// 价格变动超过阈值,发送通知
sendPriceAlert(numIid, current.getTitle(), historicalPrice, currentPrice, changeRate);
}
}
// 保存当前价格到历史记录
priceHistoryDao.savePrice(numIid, currentPrice);
}
private void sendPriceAlert(String numIid, String title,
double oldPrice, double newPrice, double changeRate) {
String direction = changeRate > 0 ? "上涨" : "下降";
String message = String.format(
"【价格%s提醒】\n商品: %s\n原价: ¥%.2f\n现价: ¥%.2f\n变动: %.1f%%",
direction, title, oldPrice, newPrice, Math.abs(changeRate) * 100
);
// 发送推送通知...
}}七、常见问题与解决方案
表格
| 问题 | 原因 | 解决方案 |
|---|---|---|
Invalid signature | 签名算法错误或参数排序不对 | 确认按key ASCII升序排列,首尾拼接app_secret |
Invalid session | Session Key过期或未授权 | 重新获取Session Key,检查授权范围 |
Insufficient permissions | 未申请接口权限 | 在开放平台申请对应API权限 |
Item not found | 商品ID错误或商品已下架 | 核对num_iid,确认商品状态 |
Rate limit exceeded | 超出调用频率限制 | 控制QPS,申请提升配额 |
Fields invalid | 返回字段参数错误 | 检查fields字段名是否正确 |
八、进阶优化建议
8.1 数据缓存策略
java
public class ItemCache {
// 商品详情缓存5分钟
private static final LoadingCache<String, TaobaoItemDetail> itemCache =
Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(key -> itemService.getItemDetail(key));
// 价格缓存1分钟(价格变动频繁)
private static final LoadingCache<String, Double> priceCache =
Caffeine.newBuilder()
.maximumSize(50000)
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(key -> itemService.getItemDetail(key).getPrice());}8.2 批量查询优化
java
public List<TaobaoItemDetail> batchGetWithLimit(List<String> numIids, int batchSize) {
List<TaobaoItemDetail> results = new ArrayList<>();
// 分批查询,每批不超过20个
for (int i = 0; i < numIids.size(); i += batchSize) {
List<String> batch = numIids.subList(i, Math.min(i + batchSize, numIids.size()));
results.addAll(itemService.getItemDetailBatch(batch));
// 控制频率,避免触发限流
if (i + batchSize < numIids.size()) {
Thread.sleep(1000);
}
}
return results;}九、总结
本文详细介绍了使用Java调用淘宝商品详情API接口(
taobao.item.get)的完整流程,包括:- 签名算法:TOP签名规则(MD5),参数按key ASCII升序排列,首尾加app_secret
- 核心代码:签名工具类、API客户端、商品服务类、实体类
- 数据解析:完整返回字段说明及JSON解析逻辑
- 应用场景:选品比价、同款匹配、价格监控
- 优化策略:数据缓存、批量查询、限流控制
如遇任何疑问或有进一步的需求,请随时与我私信或者评论联系。