Java爬虫第三方平台获取1688关键词搜索接口实战教程

以下实战教程基于第三方 API 网关(如 onebound.cn)暴露的 1688 关键词搜索接口编写,不依赖官方 SDK,只需普通开发者账号即可调用。示例代码全部用 Java 17 + Maven 实现,可直接复制到 IDEA 跑通。


一、接口原理速览

  1. 第三方网关把 1688 的 item_search 接口封装成 REST 风格,GET 请求,返回 JSON。

  2. 调用前需在第三方平台申请 key / secret(通常即时下发,无需企业资质)。

  3. 关键词、价格区间、排序、分页等参数全部放在 QueryString,无需 OAuth。

  4. 每次请求必须计算一次 MD5 签名,签名串为 key=value 升序拼接后 + secret。


二、开发环境准备

  1. JDK ≥ 8(教程基于 17)

  2. Maven 3.8+

  3. 依赖坐标(pom.xml)

XML 复制代码
<dependencies>
    <!-- 发送请求 -->
    <dependency>
        <groupId>org.apache.httpcomponents.client5</groupId>
        <artifactId>httpclient5</artifactId>
        <version>5.2.1</version>
    </dependency>
    <!-- 解析 JSON -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
    <!-- 工具类 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
</dependencies>

三、核心代码

  1. 签名工具
java 复制代码
public class SignUtil {
    public static String md5Upper(String src) {
        try {
            byte[] bs = MessageDigest.getInstance("MD5").digest(src.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : bs) sb.append(String.format("%02X", b));
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String buildSign(Map<String, String> params, String secret) {
        // 升序排序
        String base = params.entrySet().stream()
                .filter(e -> e.getValue() != null && !e.getValue().isEmpty())
                .sorted(Map.Entry.comparingByKey())
                .map(e -> e.getKey() + e.getValue())
                .collect(Collectors.joining()) + secret;
        return md5Upper(base);
    }
}
  1. 搜索服务
java 复制代码
public class AlibabaSearchService {
    private static final String GATEWAY = "https://api-gw.onebound.cn/1688/item_search/";
    private final String key;
    private final String secret;
    private final CloseableHttpClient client;

    public AlibabaSearchService(String key, String secret) {
        this.key = key;
        this.secret = secret;
        this.client = HttpClients.createDefault();
    }

    public JsonNode search(String keyword, int page, int pageSize) throws IOException {
        Map<String, String> params = new TreeMap<>();
        params.put("key", key);
        params.put("secret", secret);
        params.put("q", keyword);
        params.put("page", String.valueOf(page));
        params.put("page_size", String.valueOf(pageSize));
        params.put("sort", "default");
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("sign", SignUtil.buildSign(params, secret));

        URIBuilder ub = new URIBuilder(GATEWAY);
        params.forEach(ub::addParameter);

        HttpGet get = new HttpGet(ub.toString());
        get.addHeader("Accept-Encoding", "gzip");
        try (CloseableHttpResponse resp = client.execute(get)) {
            String json = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
            return new ObjectMapper().readTree(json);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    public void close() throws IOException {
        client.close();
    }
}
  1. 运行入口(带分页拉取示例)
java 复制代码
public class Boot {
    public static void main(String[] args) throws Exception {
        String key    = "你的key";
        String secret = "你的secret";
        String word   = "蓝牙耳机";
        int maxPage   = 5;          // 只抓 5 页做演示

        try (AlibabaSearchService api = new AlibabaSearchService(key, secret)) {
            for (int i = 1; i <= maxPage; i++) {
                JsonNode root = api.search(word, i, 40);
                JsonNode items = root.path("items").path("item");
                if (items.isEmpty()) break;

                items.forEach(n -> {
                    String title = n.path("title").asText();
                    String price = n.path("price").asText();
                    String numIid= n.path("num_iid").asText();
                    System.out.printf("%s\t%s\t%s%n", numIid, price, title);
                });
                Thread.sleep(800);   // 限速,避免 429
            }
        }
    }
}

四、返回字段速查(常用)

字段名 含义
num_iid 商品数字 ID
title 商品标题
price 单价(元)
pic_url 主图 URL
detail_url PC 端详情页
sales 30 天成交件数
seller_nick 店铺名称

五、防封 & 调优经验

  1. 单 IP 建议 ≤ 15 QPS,超过后网关会丢 429 。

  2. 生产环境务必使用代理池(青果云、携趣等),轮换出口 IP。

  3. 对同一关键词做增量更新时,用 Redis 记录 num_iid 布隆过滤器去重,内存省 90 %。

  4. 第三方网关偶尔 502,做好指数退避重试(3 次即可)。

  5. 签名 timestamp 与服务器时间差 ≤ 300 s,否则报 "sign invalid"。


六、一键抓全量并落库(扩展思路)

  1. 用 MyBatis-Plus 批量插入 MySQL,主键冲突时更新价格、销量。

  2. 每页 40 条,10 页就是 400 SKU,可放到 CompletableFuture 并行拉取,15 线程 3 s 结束。

  3. 定时任务:Docker + cron,每小时增量跑一次,飞书 WebHook 推送变更条数。


七、结语

以上代码全部基于第三方网关实测通过,改两行密钥就能跑。

如果想进一步抓详情页 SKU、阶梯价,再把 num_iid 传给同一网关的 item_get 接口即可,解析逻辑与本文完全一致,不再赘述。祝各位选品、监控、算法训练一路畅通,爆单不封 IP!

如遇任何疑问或有进一步的需求,请随时与我私信或者评论联系。

相关推荐
k***12171 小时前
SpringCloud实战【九】 SpringCloud服务间调用
java·spring boot·spring cloud
请为小H留灯1 小时前
Java快捷健(详细版)
java·开发语言
执笔论英雄1 小时前
【RL】 ROLL Generate Scheduler
java·服务器·数据库
北郭guo1 小时前
垃圾回收底层原理【深入了解】
java·jvm·算法
小年糕是糕手1 小时前
【C++同步练习】C++入门
开发语言·数据结构·c++·算法·pdf·github·排序算法
D***44141 小时前
【SpringBoot】Spring Boot 项目的打包配置
java·spring boot·后端
5***E6851 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
u***B7921 小时前
Spring Boot的项目结构
java·spring boot·后端
Lethehong1 小时前
openGauss在教育领域的AI实践:基于Java JDBC的学生成绩预测系统
java·开发语言·人工智能·sql·rag