
简介本资源是一套基于JAVA与SpringBoot的在线新闻聚合平台完整项目源码面向计算机相关专业的毕业设计、课程作业开发者以及希望实践网页开发与数据抓取技术的学习者。项目通过爬虫定期抓取各大新闻网站内容聚合标题、摘要、图片与链接并借助数据库完成存储与检索前端采用Vue构建响应式界面后端由SpringBoot处理请求与业务逻辑。压缩包共466个文件约13.77MB包含99个java后端源码、46个vue前端组件、34个js脚本、9个py爬虫程序以及xml配置、sql建表脚本、yml与properties配置文件、bat与cmd启动脚本和svg、jpg等静态资源覆盖从抓取、存储到展示的完整链路。目前已有86人学习下载。读者可据此掌握爬虫策略调优、数据库索引优化、响应式页面设计及SQL注入、XSS防护等要点并参考需求分析、系统设计与部署上线的工程流程快速搭建可运行的新闻聚合系统。1. 从一份带.bat的 Java 新闻聚合项目说起它到底能跑起来吗第一次拿到这个包我盯着根目录那几个文件看了半天1-install.bat、2-run.bat、3-build.bat旁边还躺着scrapy.cfg、mvnw.cmd、main.js.bak和一个app.97a85389.css。这套组合挺有意思——一个号称用 SpringBoot 做在线新闻聚合平台的 Java 项目却把 Python 爬虫的配置文件和前端打包产物混在同一层目录里。对正在找毕业设计或课程作业参考的人来说这种混搭恰恰是最真实的状态它不是实验室里精修过的样板而是一个真被跑过、被改过、留下过痕迹的工程。这个资源解决的核心问题很明确给你一套能本地启动的新闻聚合平台骨架前端用 SpringBoot 渲染响应式页面后端负责调度抓取、清洗、入库和展示。适合三类人——要交毕业设计但不想从零搭架子的、想学 Java 后端怎么和爬虫协作的、以及想拆一个完整数据流看它怎么串起来的人。下面我按能不能跑、怎么跑、哪里会翻车的顺序拆一遍。2. 环境与启动链路三个 bat 脚本背后的真实依赖2.1 为什么是 SpringBoot Scrapy 这种组合先讲选型。新闻聚合这件事本质是抓取—清洗—存储—展示四段流水线。展示层用 SpringBoot 是常见做法因为它把 Tomcat 内嵌了mvnw一跑就能起服务不用单独装容器对课程作业这种交付场景特别友好。抓取层用 Scrapy 而不是纯 Java 的 Jsoup 或 WebMagic理由也很实际Scrapy 自带调度器、去重队列和中间件机制写规则比手搓 HttpClient 省事得多scrapy.cfg就是它的项目入口配置。两者怎么协作常见做法是 Scrapy 抓完把结构化数据落到数据库或中间文件SpringBoot 只读不抓通过定时任务触发或直接读结果表。这样职责清晰爬虫崩了不影响页面展示页面重启也不用重抓。你看到根目录同时有scrapy.cfg和mvnw.cmd基本就是这个架构的痕迹。提示如果你的环境里 Python 和 JDK 版本对不上先别急着改代码八成是环境问题不是逻辑问题。2.2 三个 bat 脚本的执行顺序与含义Windows 下这套脚本是给不熟命令行的人准备的快捷入口顺序不能乱# 1-install.bat —— 首次运行装依赖 # 通常包含mvnw 拉取 Maven 依赖 pip install scrapy 相关包 # 只跑一次除非你改了 pom.xml 或 requirements # 2-run.bat —— 日常启动起 SpringBoot 服务 # 内部一般是 mvnw spring-boot:run 或 java -jar target/xxx.jar # 3-build.bat —— 打包产出可部署的 jar # 对应 mvnw clean package产物在 target 目录逻辑说明1-install负责把两套依赖Java 的 Maven 依赖、Python 的 Scrapy 依赖都拉齐这是最容易失败的一步因为要联网且对镜像源敏感。2-run是开发态启动改代码后重启即可。3-build是交付态打出 jar 后可以脱离 IDE 运行。参数说明如果你机器上有多个 JDKmvnw.cmd会读JAVA_HOME务必确认它指向的是项目要求的版本一般是 JDK 8 或 11SpringBoot 2.x 居多。Python 侧则要确认scrapy命令在 PATH 里否则1-install.bat里调 pip 的那段会静默失败。2.3 手动跑通的替代路径bat 脚本在 Mac 或 Linux 上没用我一般会手动走一遍反而更清楚每一步在干嘛# Java 侧用自带的 mvnw避免本机 Maven 版本冲突 ./mvnw clean install -DskipTests # 启动服务指定端口防止和本机其他服务撞车 ./mvnw spring-boot:run -Dspring-boot.run.arguments--server.port8081 # Python 侧进入爬虫目录确认 scrapy.cfg 同级执行 scrapy list # 先看有哪些 spider 被识别到 scrapy crawl news # news 换成你实际的 spider 名逻辑说明./mvnw clean install会编译并安装到本地仓库-DskipTests跳过测试加快速度课程作业阶段测试往往不全跳过能省时间。scrapy list是个被低估的命令它能告诉你 Scrapy 到底认出了几个爬虫如果输出为空说明scrapy.cfg里的[settings]指向的模块路径写错了。参数说明--server.port是 SpringBoot 的标准覆盖参数比改application.yml更灵活适合临时调试。scrapy crawl后面的名字必须和 spider 类里的name属性完全一致大小写敏感。3. 数据抓取与入库从网页到数据库的完整链路3.1 Scrapy 抓取规则怎么写才不翻车新闻站点的结构差异极大所以爬虫的通用性永远是伪命题。这个项目里scrapy.cfg只是入口真正的规则在 spider 文件里。一个能用的新闻 spider 通常长这样import scrapy class NewsSpider(scrapy.Spider): name news # 起始 URL 列表实际项目里常从配置或数据库读 start_urls [https://example-news-site.com/list] def parse(self, response): # 列表页提取每条新闻的详情链接 for link in response.css(a.news-title::attr(href)).getall(): yield response.follow(link, self.parse_detail) # 翻页找下一页按钮递归抓取 next_page response.css(a.next::attr(href)).get() if next_page: yield response.follow(next_page, self.parse) def parse_detail(self, response): # 详情页抽取标题、摘要、图片、正文 yield { title: response.css(h1.title::text).get(default).strip(), summary: response.css(div.summary::text).get(default).strip(), image: response.css(img.cover::attr(src)).get(), url: response.url, }逻辑说明parse处理列表页负责发现详情链接和翻页parse_detail处理详情页产出结构化字典。response.follow会自动补全相对链接比手动拼 URL 稳。get(default)是关键防御字段缺失时返回空串而不是 None避免入库时报错。参数说明start_urls建议改成从外部配置读硬编码在代码里后期维护很痛苦。::text和::attr()是 CSS 选择器的两种取值方式前者取文本后者取属性。如果目标站是 JS 渲染的这套 CSS 选择器会抓不到内容得换 Selenium 或 Playwright这是新手最容易踩的坑。3.2 请求频率与 robots.txt 的边界抓取策略里最容易被忽视的是频率控制。默认 Scrapy 的并发不低对着小站点猛抓轻则被封 IP重则给对方服务器造成压力。常见做法是在settings.py里加几行# 每次请求间隔单位秒给目标站喘息空间 DOWNLOAD_DELAY 1.5 # 同一域名并发数调低更稳 CONCURRENT_REQUESTS_PER_DOMAIN 2 # 遵守 robots.txt这是底线不是可选项 ROBOTSTXT_OBEY True # 自动限速根据响应时间动态调整 AUTOTHROTTLE_ENABLED True AUTOTHROTTLE_TARGET_CONCURRENCY 1.0逻辑说明DOWNLOAD_DELAY是最直接的限速手段1.5 秒意味着每分钟最多 40 个请求对大多数新闻站是安全区间。AUTOTHROTTLE更智能它会根据服务器响应延迟自动放慢服务器慢它就等服务器快它也不冒进。参数说明ROBOTSTXT_OBEY True是合规底线别为了多抓几条新闻把它关掉。CONCURRENT_REQUESTS_PER_DOMAIN设成 2 是保守值如果你抓的是自己的测试站可以调高抓别人的站就老实点。3.3 入库MySQL 表结构与去重逻辑抓下来的数据要落库表结构设计直接决定后面查询快不快。一个够用的新闻表大致这样CREATE TABLE news ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(255) NOT NULL, summary TEXT, image_url VARCHAR(500), source_url VARCHAR(500) NOT NULL, source_name VARCHAR(100), publish_time DATETIME, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 用 URL 做唯一索引天然去重 UNIQUE KEY uk_source_url (source_url), -- 按发布时间倒序查列表这个索引必须有 KEY idx_publish_time (publish_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;逻辑说明uk_source_url唯一索引是去重的核心同一条新闻重复抓取时用INSERT ... ON DUPLICATE KEY UPDATE或INSERT IGNORE就能避免脏数据。idx_publish_time服务于首页按时间倒序的查询没有它数据量上万后列表页会明显变慢。参数说明utf8mb4而不是utf8因为新闻标题里可能有 emoji 或生僻字utf8存不下会报错。VARCHAR(500)给 URL 留足空间有些带参数的链接很长。summary用TEXT因为摘要长度不定。注意如果项目用的是 MyBatis-Plus实体类字段和表字段的映射要确认驼峰转下划线是否开启否则sourceUrl对不上source_url查询会返回空。4. 前端展示与接口联调SpringBoot 怎么把数据喂给页面4.1 控制器与分页接口后端对外的核心接口就是新闻列表和详情。用 SpringBoot 写一个分页查询RestController RequestMapping(/api/news) public class NewsController { Autowired private NewsService newsService; // 分页查询page 从 1 开始size 默认 10 GetMapping(/list) public Result list(RequestParam(defaultValue 1) int page, RequestParam(defaultValue 10) int size) { // 用 MyBatis-Plus 的 Page 对象做物理分页 PageNews p new Page(page, size); newsService.page(p, new QueryWrapperNews() .orderByDesc(publish_time)); return Result.ok(p.getRecords(), p.getTotal()); } }逻辑说明RequestParam的defaultValue保证前端不传参也能用。orderByDesc(publish_time)配合前面的索引查询效率有保障。返回结构里带上total是为了前端分页组件能算总页数。参数说明page从 1 开始是 MyBatis-Plus 的约定别传 0否则会算出负数偏移。size建议设上限比如超过 50 就强制截断防止有人传size100000把数据库拖垮。4.2 响应式页面与静态资源根目录那个app.97a85389.css是前端构建产物带哈希后缀说明用了打包工具Vite 或 Webpack。SpringBoot 默认从src/main/resources/static提供静态资源所以这些文件要放在正确位置才能被访问到。响应式布局靠的是 CSS 媒体查询或框架栅格常见做法是用 Bootstrap 或自己写 flex 布局。main.js.bak这个备份文件值得说一句它说明有人改过前端逻辑又留了后路。如果你要改交互先看main.js而不是.bak.bak是历史版本可能和当前 CSS 哈希对不上。4.3 接口联调时的跨域问题前后端分离时浏览器会因为同源策略拦截请求。开发阶段常见做法是加一个全局跨域配置Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST) .allowCredentials(true); } }逻辑说明addMapping(/api/**)只对接口路径放开静态资源不受影响。allowedOriginPatterns(*)比allowedOrigins(*)更安全后者在带凭证时会被浏览器拒绝。参数说明allowCredentials(true)允许携带 Cookie如果不用 Session 可以设 false。生产环境务必把*换成具体域名否则等于没做跨域限制。5. 避坑与排查那些让我重跑三遍的坑5.1 启动报OutOfMemoryError或堆内存不足现象2-run.bat跑到一半抛java.lang.OutOfMemoryError: Java heap space服务起不来。原因默认 JVM 堆太小而 SpringBoot 加 MyBatis 加连接池本身就吃内存再加上如果爬虫和 Web 在同一进程里跑内存更紧张。解决启动时显式指定堆大小java -Xms512m -Xmx2048m -jar xxx.jar。如果用的是mvnw spring-boot:run加-Dspring-boot.run.jvmArguments-Xmx2048m。别一上来就设 8G先看实际占用再调。5.2 爬虫抓回来全是空字段现象数据库里title有值但summary、image全是空。原因目标站改版了CSS 选择器失效或者详情页是 JS 动态渲染Scrapy 拿到的是空壳 HTML。解决先用scrapy shell 详情页URL进去手动试选择器response.css(div.summary)看返回什么。如果是 JS 渲染换 Selenium 或找站点的 JSON 接口直接请求。别硬啃 HTML。5.3 中文乱码现象页面显示问号或方块数据库里存进去也是乱码。原因三个环节任一没对齐都会乱——数据库字符集、连接串编码、页面 meta 声明。解决数据库建库时用utf8mb4JDBC 连接串加?useUnicodetruecharacterEncodingutf8HTML 头部确认meta charsetUTF-8。三处都对了才不乱。5.4 端口被占用导致启动失败现象Port 8080 was already in use。原因本机有其他服务占了 8080或者上一次的进程没退干净。解决netstat -ano | findstr 8080找到 PIDtaskkill /PID xxx /F干掉。或者直接换端口启动--server.port8081省事。5.5 Maven 依赖下载卡住现象1-install.bat卡在下载依赖半天不动。原因默认走中央仓库网络不稳时容易超时。解决在settings.xml里配国内镜像源或者用mvnw -o离线模式前提是依赖已经下过。别反复重跑先确认是网络问题还是依赖冲突。6. 进阶技巧把抓取和展示解耦成定时任务跑通之后我建议做一件事别让爬虫和 Web 服务绑在一起。常见做法是用 Spring 的Scheduled定时触发抓取或者干脆把 Scrapy 做成独立进程通过命令行调用。Component public class NewsFetchTask { // 每 30 分钟触发一次cron 表达式按需改 Scheduled(cron 0 0/30 * * * ?) public void fetch() { try { // 调用外部 Python 脚本阻塞等待完成 Process p Runtime.getRuntime() .exec(scrapy crawl news); int code p.waitFor(); if (code ! 0) { // 非零退出码说明抓取异常记日志 System.err.println(抓取任务失败退出码 code); } } catch (Exception e) { e.printStackTrace(); } } }逻辑说明Scheduled的 cron 表达式0 0/30 * * * ?表示每 30 分钟执行一次。Runtime.exec起一个子进程跑 ScrapywaitFor阻塞到它结束。退出码非零时记日志方便排查。参数说明cron 里?表示不指定用在日或周字段避免冲突。waitFor会阻塞当前线程如果抓取耗时长建议放到独立线程池里别堵住调度线程。验证方法改完 cron 后把时间调成每分钟一次观察日志里是否按时触发、退出码是否为 0、数据库记录数是否增长。确认无误再改回 30 分钟。从那以后我每次拿到这种带 bat 脚本的项目都强制先手动走一遍mvnw和scrapy命令确认每一步的报错信息再回头用脚本——因为脚本会把错误吞掉而手动跑能让你看清到底哪一环断了。希望帮到你。本文还有配套的精品资源点击获取