下面给出一份可直接落地的「Java 版 1688 商品详情 API 爬虫」完整示例,覆盖签名算法、HTTP 调用、JSON 解析、异常重试、频率控制等关键要点,复制即可运行。
(注:1688 接口需企业认证并申请 AppKey / AppSecret,以下代码以官方 REST 网关 item_get 为例,也可平替为第三方代理网关,只需换域名即可 。)
一、Maven 依赖
XML
<dependencies>
<!-- HTTP -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
</dependency>
<!-- JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
</dependencies>
二、签名工具(1688 官方 MD5 签名规则)
java
public class SignUtil {
public static String sign(TreeMap<String, String> params, String appSecret) {
StringBuilder sb = new StringBuilder(appSecret);
for (Map.Entry<String, String> e : params.entrySet()) {
sb.append(e.getKey()).append(e.getValue());
}
sb.append(appSecret);
return md5(sb.toString()).toUpperCase();
}
private static String md5(String raw) {
try {
byte[] bs = MessageDigest.getInstance("MD5").digest(raw.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : bs) hex.append(String.format("%02X", b & 0xFF));
return hex.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
三、统一入口 ------ ItemGetService
java
public class ItemGetService {
private static final String GATEWAY = "https://api.1688.com/router/rest";
private final String appKey;
private final String appSecret;
private final CloseableHttpClient http;
public ItemGetService(String appKey, String appSecret) {
this.appKey = appKey;
this.appSecret = appSecret;
this.http = HttpClients.custom()
.setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create()
.setMaxConnTotal(50).setMaxConnPerRoute(10).build())
.build();
}
/** 获取商品详情(自动重试 3 次) */
public ItemDO getItem(long numIid) throws IOException {
TreeMap<String, String> params = new TreeMap<>();
params.put("method", "item_get");
params.put("app_key", appKey);
params.put("timestamp", String.valueOf(System.currentTimeMillis()));
params.put("num_iid", String.valueOf(numIid));
params.put("v", "2.0");
params.put("sign_method", "md5");
params.put("format", "json");
params.put("sign", SignUtil.sign(params, appSecret));
String url = GATEWAY + "?" + URLEncodedUtils.format(
params.entrySet().stream()
.map(e -> new BasicNameValuePair(e.getKey(), e.getValue()))
.collect(Collectors.toList()), StandardCharsets.UTF_8);
for (int i = 0; i < 3; i++) {
try (CloseableHttpResponse resp = http.execute(new HttpGet(url))) {
if (resp.getCode() == 200) {
JsonNode root = new ObjectMapper().readTree(EntityUtils.toString(resp.getEntity()));
if ("0".equals(root.get("code").asText())) {
return new ObjectMapper().convertValue(root.get("item"), ItemDO.class);
}
throw new IllegalStateException("API 业务错误: " + root.get("msg").asText());
}
} catch (Exception e) {
if (i == 2) throw e;
try { Thread.sleep(1000); } catch (InterruptedException ignore) {}
}
}
throw new RuntimeException("重试 3 次仍失败");
}
@Data // lombok
public static class ItemDO {
private String title;
private BigDecimal price;
private Integer num; // 库存
private String picUrl;
private List<Sku> skus;
}
public void shutdown() throws IOException {
http.close();
}
}
四、频率控制 + 批量调用示例
java
public class CrawlerBoot {
public static void main(String[] args) throws Exception {
ItemGetService api = new ItemGetService("你的AppKey", "你的AppSecret");
List<Long> numIids = List.of(610947572360L, 623456789012L); // 商品ID池
for (Long id : numIids) {
ItemGetService.ItemDO item = api.getItem(id);
System.out.printf("标题=%s 价格=%s 库存=%d%n",
item.getTitle(), item.getPrice(), item.getNum());
Thread.sleep(350); // 约 3 次/秒,低于官方 5 次/秒限制
}
api.shutdown();
}
}
五、常见坑 & 优化建议
-
签名顺序必须
TreeMap升序,否则 4005 授权失败。 -
免费账号每日调用上限 1 万次,超出需购买套餐;峰值时段做好限流与重试。
-
如需 SKU 图、阶梯价、近 30 天销量,需在参数额外指定
fields=skus,priceRange,saleInfo。 -
若走第三方代理网关(如
api-gw.onebound.cn),签名规则不变,仅换域名即可。 -
数据落库时建议用
ON DUPLICATE KEY UPDATE做幂等,避免重复写入。
六、一句话总结
以上代码即为"Java 爬虫 1688 详情 API 接口"的最小可运行骨架,已帮你屏蔽掉签名、编码、重试、频率等所有细节,直接填上自己的 AppKey / Secret 即可把 1688 商品库变成本地数据表