在店铺运营、竞品分析、商品监控等场景中,批量获取店铺所有商品 数据 是核心需求。网上常规教程仅实现「单次拉取单页商品」,存在数据重复、分页逻辑混乱、无异常容错、字段解析不完整等问题,难以落地。
本文基于淘宝开放平台官方SDK,实现店铺商品批量拉取、自动分页、数据去重、核心字段结构化解析的 企业 级方案,代码简洁合规、无敏感操作,符合CSDN审核规范,可直接用于项目开发。
一、前置准备
登录淘宝开放平台创建应用,完成实名认证,申请taobao.items.onsale.get(在售商品)/taobao.items.inventory.get(库存商品)接口权限;
获取应用AppKey、AppSecret,生产环境网关地址:https://eco.taobao.com/router/rest;
新建Maven项目,引入核心依赖(版本稳定无冲突):
<dependencies>
<!-- 淘宝官方SDK -->
<dependency>
<groupId>com.taobao.api</groupId>
<artifactId>top-sdk-java</artifactId>
<version>4.3.0</version>
</dependency>
<!-- 工具包(时间/字符串处理) -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
</dependencies>

点击获取key和secret
二、核心代码 实现(完整可运行)
1. 店铺商品接口核心工具类
import cn.hutool.core.util.StrUtil;
import com.taobao.api.DefaultTaobaoClient;
import com.taobao.api.TaobaoClient;
import com.taobao.api.request.ItemsOnsaleGetRequest;
import com.taobao.api.response.ItemsOnsaleGetResponse;
import com.taobao.api.domain.Item;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 淘宝店铺商品接口工具类
* 功能:批量拉取在售商品、自动分页、去重、字段解析
*/
public class TaobaoShopItemUtil {
// 替换为自己的配置
private static final String APP_KEY = "你的AppKey";
private static final String APP_SECRET = "你的AppSecret";
private static final String GATEWAY_URL = "https://eco.taobao.com/router/rest";
// 核心配置
private static final int MAX_PAGE = 10; // 最大拉取页数(避免无限分页)
private static final int PAGE_SIZE = 40; // 每页条数(接口上限)
private static final Set<String> ITEM_ID_CACHE = ConcurrentHashMap.newKeySet(); // 商品ID去重缓存
/**
* 批量拉取店铺在售商品(核心方法)
* @param sellerId 店铺卖家ID(必填,可从店铺页获取)
* @return 结构化后的商品列表
*/
public static List<Map<String, Object>> getShopOnsaleItems(String sellerId) {
if (StrUtil.isBlank(sellerId)) {
System.err.println("店铺卖家ID不能为空");
return new ArrayList<>();
}
ITEM_ID_CACHE.clear();
List<Item> rawItemList = new ArrayList<>();
// 自动分页拉取
for (int page = 1; page <= MAX_PAGE; page++) {
List<Item> pageList = getSinglePageItems(sellerId, page);
if (pageList.isEmpty()) {
System.out.println("第" + page + "页无商品,终止拉取");
break;
}
// 商品ID去重(解决接口重复返回问题)
List<Item> filteredList = pageList.stream()
.filter(item -> !ITEM_ID_CACHE.contains(item.getNumIid()))
.peek(item -> ITEM_ID_CACHE.add(item.getNumIid()))
.collect(Collectors.toList());
rawItemList.addAll(filteredList);
sleep(1); // 分页延迟,避免触发限流
}
// 解析为结构化数据
return parseShopItems(rawItemList);
}
/**
* 单页拉取商品(内部方法)
*/
private static List<Item> getSinglePageItems(String sellerId, int pageNo) {
TaobaoClient client = new DefaultTaobaoClient(GATEWAY_URL, APP_KEY, APP_SECRET);
ItemsOnsaleGetRequest req = new ItemsOnsaleGetRequest();
req.setSellerId(sellerId);
req.setPageNo(pageNo);
req.setPageSize(PAGE_SIZE);
// 指定返回核心字段,减少数据冗余
req.setFields("num_iid,title,price,org_price,stock,sales,category_id,shop_name,location");
try {
ItemsOnsaleGetResponse resp = client.execute(req);
return resp.isSuccess() ? resp.getItems() : new ArrayList<>();
} catch (Exception e) {
System.err.println("第" + pageNo + "页拉取失败:" + e.getMessage());
return new ArrayList<>();
}
}
/**
* 商品数据结构化解析(适配业务使用)
*/
private static List<Map<String, Object>> parseShopItems(List<Item> rawList) {
List<Map<String, Object>> result = new ArrayList<>();
for (Item item : rawList) {
Map<String, Object> itemMap = new HashMap<>();
itemMap.put("itemId", item.getNumIid()); // 商品ID
itemMap.put("title", StrUtil.cleanBlank(item.getTitle())); // 商品标题(去空格)
itemMap.put("price", item.getPrice()); // 售价
itemMap.put("originalPrice", item.getOrgPrice()); // 原价
itemMap.put("stock", item.getStock() == null ? 0 : item.getStock()); // 库存(空值兼容)
itemMap.put("sales", item.getSales() == null ? 0 : item.getSales()); // 销量(空值兼容)
itemMap.put("categoryId", item.getCid()); // 类目ID
itemMap.put("shopName", item.getShopName()); // 店铺名称
itemMap.put("location", item.getLocation()); // 发货地
result.add(itemMap);
}
return result;
}
// 辅助方法:分页延迟
private static void sleep(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// 测试入口(直接运行)
public static void main(String[] args) {
// 替换为目标店铺的卖家ID
String sellerId = "替换为真实店铺卖家ID";
List<Map<String, Object>> shopItems = getShopOnsaleItems(sellerId);
System.out.println("店铺商品总数:" + shopItems.size());
System.out.println("商品列表:" + shopItems);
}
}
三、核心亮点解析(区别于网上教程)
自动分页+空页终止:最多拉取10页,遇到空页自动停止,避免无效接口调用,适配淘宝接口「页码过大返回空数据」的特性;
精准去重:基于商品唯一ID(num_iid)构建并发安全缓存,解决分页拉取中接口返回重复商品的问题;
限流适配:分页间添加1秒延迟,降低触发平台QPS限制的概率,提升调用稳定性;
结构化解析:对标题去空格、库存/销量做空值兼容处理,返回可直接用于业务的结构化数据,无需二次处理;
字段精简:仅拉取核心业务字段,减少数据传输量,提升接口调用效率。
四、常见避坑点
