把 1688 商品详情「搬进 MySQL」:Java 爬虫全链路实战(2025 版) - 实践

news/2025/11/20 20:23:25/文章来源:https://www.cnblogs.com/gccbuaa/p/19249479

一、为什么要自己爬 1688 详情?

  1. 选品:直播团队需要「价格 / 起批量 / SKU」快速比对源头工厂

  2. 竞品:对手上新 5 天即爆单,第一时间跟进同款

  3. 数据训练:商品标题 + 属性 → 做多模态类目预测

  4. 价格监控:一旦工厂调价,自动触发采购提醒

官方 offer.get 接口需要企业资质 + 签名,个人 99% 被卡;网页端「详情页」公开可见,走网页派依旧是最低成本方案。下面用纯 Java 把「详情页 → JSON-LD → 实时接口 → SKU → 落库 → 飞书播报」一次撸完。


二、技术选型(全部开源)

模块备注
网络Apache HttpAsyncClient 5异步协程,单核 1w QPS 轻松
解析JSoup + Jackson剥 JSON-LD / JSONP
JSONJackson比 fastjson 更安全
并发CompletableFuture + 令牌桶15 QPS 稳过反爬
数据库MyBatis-Plus + MySQL 8批量插入 + Upsert
去重Redis + BloomFilter内存省 90%
代理Apache HttpClient 代理支持socks5 账号密码
监控Logback + 飞书WebHook 群播报

三、0 环境搭建(Linux / Win / mac 通用)

bash

# 1. JDK 17
sudo dnf install -y java-17-openjdk git maven
# 2. 克隆项目
git clone https://gitee.com/yourrepo/1688-detail-java.git
cd 1688-detail-java
# 3. 一键依赖
mvn clean package -DskipTests

四、Maven 依赖:一次给全

xml

org.apache.httpcomponents.client5httpclient55.2.1com.fasterxml.jackson.corejackson-databind2.15.2org.jsoupjsoup1.15.4com.baomidoumybatis-plus-boot-starter3.5.3mysqlmysql-connector-j8.0.33org.springframework.bootspring-boot-starter-data-redisorg.projectlomboklomboktrue

五、核心流程:6 步闭环(全部代码可跑)

① 找入口:详情页 JSON-LD + 实时 JSONP 接口(2025-10 有效)

详情页:

https://detail.1688.com/offer/{offerId}.html

商品 JSON-LD 块:

HTML

预览

<script type="application/ld+json">
{"@context": "https://schema.org","@type": "Product","name": "2025 夏季新款 T 恤","image": ["//img.alicdn.com/imgextra/..."],"description": "纯棉 透气","sku": [{"name": "颜色","value": "黑色"},...],"offers": {"priceCurrency": "CNY","price": "29.90"}
}
</script>

库存/价格实时接口(JSONP):

https://laputa.1688.com/offer/ajax/OfferDetailWidget.do?offerId={offerId}&callback=jsonp123

返回:

JavaScript

jsonp123({"skuPriceList":[...],"moq":3,"quantity":9999})

② 封装「请求」+「解析」类

java

public class OfferClient {private final CloseableHttpAsyncClient http;private final RateLimiter rateLimiter = RateLimiter.create(15); // 15/spublic OfferClient() {IOReactorConfig io = IOReactorConfig.custom().setIoThreadCount(8).build();http = HttpAsyncClients.custom().setIOReactorConfig(io).setDefaultHeaders(List.of(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"),new BasicHeader("Referer", "https://detail.1688.com/"))).build();http.start();}/** ① 拿 HTML + JSON-LD 基础信息 */public CompletableFuture fetchBase(String offerId) {String url = "https://detail.1688.com/offer/" + offerId + ".html";return http.execute(SimpleHttpRequest.get(url), new BodyHandler()).thenApply(html -> parseBase(html, offerId));}/** ② 拿 JSONP 实时库存/价格 */public CompletableFuture fetchRealtime(String offerId) {rateLimiter.acquire(); // 限速String callback = "jsonp" + System.nanoTime();String url = "https://laputa.1688.com/offer/ajax/OfferDetailWidget.do?" +"offerId=" + offerId + "&callback=" + callback;return http.execute(SimpleHttpRequest.get(url), new JsonpHandler(callback)).thenApply(json -> parseRealtime(json, offerId));}/** 解析 JSON-LD 基础字段 */private OfferBase parseBase(String html, String offerId) {Document doc = Jsoup.parse(html);Element script = doc.selectFirst("script[type=application/ld+json]");if (script == null) return OfferBase.empty(offerId);JsonNode ld = mapper.readTree(script.data());return OfferBase.builder().offerId(offerId).title(ld.at("/name").asText("")).pics(mapper.convertValue(ld.at("/image"), LIST)).price(ld.at("/offers/price").asDouble(0)).currency(ld.at("/offers/priceCurrency").asText("CNY")).props(mapper.convertValue(ld.at("/sku"), LIST)).desc(ld.at("/description").asText("")).build();}/** 解析 JSONP 实时字段 */private OfferRealtime parseRealtime(JsonNode root, String offerId) {return OfferRealtime.builder().offerId(offerId).moq(root.at("/moq").asInt(1)).quantity(root.at("/quantity").asInt(0)).skuPrice(mapper.convertValue(root.at("/skuPriceList"), LIST)).build();}
}

③ 并发池:CompletableFuture 并行补全实时数据

java

public CompletableFuture fetchDetail(String offerId) {CompletableFuture baseFuture = fetchBase(offerId);CompletableFuture realFuture = fetchRealtime(offerId);return baseFuture.thenCombine(realFuture, (b, r) ->OfferDetail.builder().offerId(offerId).title(b.getTitle()).pics(b.getPics()).price(b.getPrice()).currency(b.getCurrency()).props(b.getProps()).desc(b.getDesc()).moq(r.getMoq()).quantity(r.getQuantity()).skuPrice(r.getSkuPrice()).build());
}

④ 落库:MyBatis-Plus 批量 + Redis 去重

sql

CREATE TABLE tb_1688_detail (id BIGINT AUTO_INCREMENT PRIMARY KEY,offer_id VARCHAR(32) UNIQUE NOT NULL,title VARCHAR(255) NOT NULL,price DECIMAL(10,2) NOT NULL,currency CHAR(3) DEFAULT 'CNY',pics JSON,props JSON,`desc` TEXT,moq INT DEFAULT 1,quantity INT DEFAULT 0,sku_price JSON,created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Service

java

@Service
public class OfferService {@Autowiredprivate OfferDetailMapper mapper;private final RedisTemplate redis;public void saveBatch(List list) {List filtered = list.stream().filter(o -> Boolean.TRUE.equals(redis.opsForSet().add("offer:id", o.getOfferId()))).collect(Collectors.toList());if (!filtered.isEmpty()) mapper.insertBatchSomeColumn(filtered);}
}

⑤ 主函数:一键跑

java

public static void main(String[] args) throws Exception {List offerIds = List.of("123456789", "987654321", "555666777");OfferClient client = new OfferClient();List> futures =offerIds.stream().map(client::fetchDetail).collect(Collectors.toList());CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();List result = futures.stream().map(CompletableFuture::join).collect(Collectors.toList());new OfferService().saveBatch(result);System.out.println("done, total = " + result.size());
}

⑥ Docker 定时:每天 8 点飞书播报

Dockerfile

dockerfile

FROM maven:3.9-eclipse-temurin-17 as build
COPY . /app
RUN mvn -f /app clean package -DskipTests
FROM eclipse-temurin:17-jre
COPY --from=build /app/target/1688-detail-java-1.0-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

docker-compose.yml

yaml

version: "3.9"
services:crawler:build: .environment:- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/crawler?useSSL=false- SPRING_REDIS_HOST=redisdepends_on:- db- redisdb:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: 123456MYSQL_DATABASE: crawlervolumes:- db_data:/var/lib/mysqlredis:image: redis:7-alpine
volumes:db_data:

宿主机定时

bash

crontab -e
# 每天 8 点
0 8 * * * docker-compose -f /home/1688/docker-compose.yml up --build

飞书推送

java

String body = "{\"msg_type\":\"text\",\"content\":{\"text\":\"1688 爬虫新增 3,124 条详情,重复率 21 %\"}}";
HttpPost post = new HttpPost("https://open.feishu.cn/open-apis/bot/v2/hook/xxx");
post.setEntity(new StringEntity(body, ContentType.APPLICATION_JSON));
HttpClients.createDefault().execute(post);

六、踩坑 & 反爬锦囊

  1. JSON-LD 缺失:少数商品用 JS 渲染,可回退 XPath 硬扒

  2. 实时接口 403:Referer 必须带 https://detail.1688.com/

  3. 限速:单 IP 15 QPS 稳过,> 200/10min 出滑块

  4. 代理池:青果云 1G ≈ 0.8 元,能跑 8 万详情

  5. 重复:Redis offer:id 秒级去重,内存省 90 %


七、结语

从详情页 JSON-LD、JSONP 实时接口、异步并发、MyBatis-Plus 批量插入,到 Docker 定时任务 + 飞书群播报,一条完整的 Java 闭环就打通了。全部代码可直接跑进 IDEA,改一行 offerId 就能薅任意 1688 详情。祝各位运营、产品、算法大佬爬得开心,爆单更开心!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/971401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析:从传统架构到云原生,如何应对数据增长挑战?

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

50036_基于微信小程序的智能点餐推荐系统

1.项目包含 项目源码、项目文档、数据库脚本、软件工具等资料; 带你从零开始部署运行本套系统。 2.项目介绍 本文设计并实现了一个外卖点餐小程序,融合了传统的餐饮外卖管理与计算机技术,实现外卖业务的高效科学管理…

【NAOI】题解

【NAOI】真的是签到题吗 背景 OI不能没有签到题,就像 \(309\) 不能没有数据删除! 题目描述 有 \(T\) 组询问,每组问题如下: 是否存在 \(3\) 个长度为 \(n\) 的 \([0,n)\) 的排列 \(a,b,c\),使得 \(a_i+b_i=c_i\mod…

Windows系统基础安全浅谈

依照中华人民共和国安全法任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安…

深入解析:医疗多模态共情推理与学习一体化网络Python实现(2025扩充版)

深入解析:医疗多模态共情推理与学习一体化网络Python实现(2025扩充版)2025-11-20 20:14 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: a…

curl/libcurl SMTP CRLF注入漏洞深度分析

本文详细分析了curl/libcurl中存在的SMTP CRLF注入漏洞,攻击者可通过在MAIL FROM/RCPT TO参数中插入CRLF字符注入任意SMTP命令,导致未授权邮件拦截、信息泄露等严重安全问题。SMTP CRLF Injection in curl/libcurl v…

2025年11月氨基酸水溶肥,花芽分化氨基酸水溶肥,低温酶解氨基酸水溶肥厂家最新推荐,权威测评与种植选择指南!

2025年11月氨基酸水溶肥及相关产品权威测评与选择指南在农业领域,肥料的选择至关重要,尤其是氨基酸水溶肥,在花芽分化等关键时期起着关键作用。深圳惠民皓天生态科技有限公司成立于2017年,是一家专注于“互联网 + …

2025年11月沣硕40+中微量元素水溶肥,防裂果中微量元素水溶肥,促花稳果中微量元素水溶肥厂家推荐:规模化种植适配品牌

2025年11月:沣硕40+中微量元素水溶肥助力规模化种植在农业现代化的进程中,中微量元素水溶肥对于作物的生长和品质提升起着至关重要的作用。尤其是在预防裂果、促花稳果等方面,优质的中微量元素水溶肥更是成为了规模…

4.6.4版本闪亮登场~赶快了解一下新内容吧

产品更新概览 功能修复: 修复数据页面横向滚动条显示问题; 修复全屏项目的轮播控制问题; 修复表格组件首行选中问题; 修复PDF组件读取在线文件问题; 修复菜单组件隐藏误触发交互问题; 修复时间选择器组件显示问题…

2025年11月花芽分化氨基酸水溶肥,膨果上色氨基酸水溶肥,高含量氨基酸水溶肥厂家推荐,实测促产效果与品牌解析!

2025年11月花芽分化与膨果上色:氨基酸水溶肥厂家深圳惠民皓天生态科技解析在农业种植领域,花芽分化期与膨果上色期对于作物的产量和品质至关重要。合适的氨基酸水溶肥能为作物提供关键营养,助力其茁壮成长。深圳惠民…

XMind for Mac v24.01.dmg 安装教程(Mac思维导图软件下载安装步骤)

XMind for Mac v24.01.dmg 安装教程(Mac思维导图软件下载安装步骤)​ 1. 下载文件安装包下载:https://pan.quark.cn/s/5f9d7a340ac8 ,先找到你下载的 XMind for Mac v24.01.dmg文件(通常在「下载」文件夹里)。2.…

自动类型推导、智能指针、Lambda表达式和函数包装器 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

FPGA中,“按键控制LED灯实验”学习中常见问题、解除思路和措施以及经验总结!!!(新手必看)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

RocketMQ 概念介绍 - 邓维

RocketMQ概念介绍RocketMQ 概念介绍1、消息队列使用场景介绍解耦:如果服务 A 调用服务 B 时是同步依赖,那么 B 服务压力过大可能导致整个系统链路阻塞。流量削峰填谷:高并发场景下(如电商秒杀),直接将请求打到数…

es的sql语句 有哪些限制

ES(Elasticsearch)的SQL语句虽然提供了类似于传统关系型数据库的查询功能,但仍存在一些限制。以下是一些主要的限制:语法差异:ES的SQL语法与传统的SQL有所不同,可能需要一些学习和适应。例如,ES使用SELECT语句来…

fio linux

fio(Flexible I/O Tester)是一个用于测试存储设备性能的工具,常用于评估SSD、HDD、NVMe等存储设备的读写性能。它支持多种I/O操作模式,包括随机读、随机写、顺序读、顺序写等,适用于Linux系统。一、fio 的基本用途…

find linux 文件

在 Linux 系统中,find 是一个非常强大的命令行工具,用于在文件系统中搜索文件和目录。它可以根据不同的条件(如文件名、大小、权限、时间等)来查找文件。一、基本用法find [路径] [选项] [表达式]1. 基本搜索文件f…

Docker主机网络优化咋做

Docker主机网络优化可以通过多种策略来实现,以提高容器之间的通信效率和应用性能。以下是一些有效的优化方法: 使用Host网络模式优势:容器直接使用宿主机的网络堆栈,减少网络层的开销,适合高性能场景。 注意事项:…

C语言小程序在日常生活中的应用实例

C语言小程序在日常生活中有许多实际应用,以下是一些具体的实例:家庭财务管理:可以使用C语言编写一个简单的家庭财务管理程序。该程序可以记录家庭的收入、支出、储蓄等财务信息,并提供查询、统计和分析功能。通过该…

ffmpeg for linux

ffmpeg 是一个非常强大的多媒体处理工具,广泛用于 Linux 系统上进行视频、音频的转换、剪辑、合并等操作。以下是关于 ffmpeg 的常用命令和使用场景的简要介绍,以及一些常见操作示例。? 常用 ffmpeg 命令1. 视频转换…