资讯详情

资讯详情

Java SpringBoot+Scrapy构建在线新闻聚合平台:爬虫采集到展示全链路解析

简介在线新闻聚合平台是一份基于Java与SpringBoot框架的完整课程设计或毕业设计资源面向需要实现新闻自动抓取与聚合展示的开发者也适合作为计算机专业项目实践参考。资源包共466个文件压缩包大小13.77MB主体内容包含99个Java后端源码、46个Vue前端组件、34个JavaScript脚本以及爬虫相关的Python脚本、SQL数据库初始化和多种项目配置文件可覆盖从环境搭建、数据抓取、服务发布到页面调试的完整链路。实现层面涉及网络爬虫定时抓取、新闻标题摘要图片信息解析、数据库存储与响应式页面渲染等关键环节同时考虑SQL注入、XSS攻击等安全防护。资源内附带安装运行构建批处理脚本和数据库配置文件便于快速启动与二次开发。当前已有85人学习下载适合毕业设计参考或新闻聚合类项目的工程范本。1. 在线新闻聚合平台一套能跑通抓取、存储、展示全链路的 Java 课程设计做毕业设计或课程作业的同学多半都经历过这种场景选题选了“在线新闻聚合平台”以为自己是在做一个新闻客户端结果打开项目才发现真正的工作量全在“数据从哪来”和“怎么让它自动更新”这两件事上。这套基于 Java SpringBoot 加数据抓取技术的在线新闻聚合平台正是把这条链路完整串起来的资源——前端用 SpringBoot 搭响应式页面后端管请求和数据落库抓取层用 Scrapy 按预设规则定时去目标站点采集新闻标题、摘要、图片和链接。相反市面上不少同类项目要么只做了个静态页面糊弄展示要么爬虫代码和业务代码完全割裂根本不能一键跑起来。这套项目里带了 install/run/build 的批处理脚本和 Maven 包装器意味着你不用折腾复杂的环境配置适合用来交课程作业、毕业设计也适合想快速理解“爬虫 Web 框架 数据库”三者怎么协作的 Java 学习者。2. 项目构成与运行链路先从文件清单看懂这套东西的架构2.1 关键文件逐个拆解批处理脚本、Maven 配置和 Scrapy 入口拿到项目压缩包后别急着双击运行先把文件结构认一遍。这套资源里最有辨识度的是一组.bat文件分别叫安装.bat、运行.bat、1-install.bat、2-run.bat、3-build.bat还有mvnw.cmd、scrapy.cfg和main.js.bak。初看会有点懵觉得文件重复其实它们各管一段。1-install.bat一般负责初始化环境比如检查 Java 和 Maven 是否在 PATH 里然后执行依赖下载2-run.bat是启动 SpringBoot 应用的入口核心命令就是mvnw spring-boot:run或java -jar3-build.bat对应打包生成可部署的 jar 包。安装.bat和运行.bat更像是把前面两步合并起来的一键版本适合演示时用。echo off REM 安装脚本检查依赖并下载 Maven 项目依赖 mvnw.cmd clean install -DskipTests if %errorlevel% neq 0 ( echo 依赖安装失败请检查网络或 Maven 配置 exit /b 1 ) echo 依赖安装完成 pause这段脚本是 Windows 下常见的批处理写法。mvnw.cmd是 Maven Wrapper它保证在没有全局 Maven 的环境里也能用指定版本构建。-DskipTests表示跳过测试课程设计项目一般不需要跑单元测试加这个参数能节省大量构建时间。%errorlevel%是批处理里的退出码判断不为 0 说明上一条命令执行失败。我把这段脚本放在前面讲是因为很多新手第一次跑项目翻车就是把这里的clean去掉导致旧的编译产物和新的依赖冲突。main.js.bak是前端静态资源的备份文件后缀.bak说明它是被替换过的版本。常见做法是项目里原有一个main.js后来因为调试或按需加载改过逻辑备份出来防止改坏。你不用管它知道这是前端 JavaScript 的存量文件就行。scrapy.cfg是 Python Scrapy 爬虫的配置文件这个文件的存在说明抓取层不是写在 Java 里而是独立的 Python 爬虫服务通过数据库或接口和 SpringBoot 交互。2.2 整体链路爬虫采集、数据库落库、SpringBoot 展示三步走这个项目的核心链路可以用一句话概括Scrapy 爬虫定时抓取新闻站点把解析出的结构化字段写入 MySQLSpringBoot 通过 MyBatis 或 JPA 读取数据渲染到前端页面。前端页面是响应式布局后端提供 REST 接口爬虫和 Web 应用通过数据库解耦互不阻塞。这种设计的优势在课程设计答辩时特别明显老师问“数据是怎么来的”你可以说 Scrapy 负责采集MySQL 做持久化SpringBoot 负责 API 和页面渲染每一层职责清晰。相比把爬虫直接用 Java 的 HttpClient 写在 Service 层里独立爬虫进程的好处是——抓取频率高时不会拖垮 Web 服务的响应抓取失败时也不会导致用户访问 500。坏处是部署时要多维护一个 Python 进程但这对于毕设场景来说完全值得。数据模型层面新闻表至少要包含这些字段id主键、title标题、summary摘要、image_url图片地址、source_url原文链接、source_site来源站点、published_at发布时间、created_at抓取入库时间。这个表结构是所有后续功能的基础后面章节讲调度和展示都会围绕它展开。3. 数据抓取层实战Scrapy 爬虫的编写思路与关键参数调优3.1 一个通用新闻爬虫的骨架从 scrapy.cfg 说起Scrapy 项目的入口是scrapy.cfg它指定了 settings 模块的位置。标准结构是项目根目录下有scrapy.cfg同级的news_spider/包里有settings.py、items.py、pipelines.py和spiders/目录。这套资源既然带了scrapy.cfg大概率就是这种标准布局。# Scrapy settings.py 中的关键配置 BOT_NAME news_spider SPIDER_MODULES [news_spider.spiders] NEWSPIDER_MODULE news_spider.spiders # 抓取间隔与并发控制 DOWNLOAD_DELAY 2 CONCURRENT_REQUESTS 8 CONCURRENT_REQUESTS_PER_DOMAIN 4 # 请求头伪装 DEFAULT_REQUEST_HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, }DOWNLOAD_DELAY 2表示每个请求之间至少间隔 2 秒这是给目标网站留缓冲也是避免被封 IP 的底线。CONCURRENT_REQUESTS 8是全局并发上限CONCURRENT_REQUESTS_PER_DOMAIN 4是单域名并发上限后者的优先级更高。对于毕设项目我的建议是把DOWNLOAD_DELAY设在 1 到 3 之间太低容易被封太高抓全量数据太慢。User-Agent 必须伪装成浏览器否则很多新闻站直接返回 403。DEFAULT_REQUEST_HEADERS里的 UA 字符串可以直接照抄实战中最好改成和你本机 Chrome 版本一致的完整 UA。别用 Scrapy 默认的Scrapy/2.xUA那等于告诉对方你是爬虫。3.2 页面解析与字段提取Selector 写法和常见翻车点新闻页面的结构通常是列表页有多个新闻条目链接进入详情页后才是完整的标题、正文、发布时间。所以爬虫一般写两个解析函数第一个 parse 解析列表页取出详情链接第二个 parse_detail 解析具体字段。import scrapy from news_spider.items import NewsItem class NewsListSpider(scrapy.Spider): name news_list start_urls [https://news.example.com/] # 常见写法直接使用 response.css 提取节点 def parse(self, response): # 提取列表页所有新闻链接 for link in response.css(div.news-list a::attr(href)).extract(): yield scrapy.Request(urlresponse.urljoin(link), callbackself.parse_detail) def parse_detail(self, response): item NewsItem() # 新闻标题 item[title] response.css(h1.article-title::text).extract_first() # 新闻摘要很多页面没有独立摘要从正文截断 content_list response.css(div.article-content p::text).extract() content .join(content_list).strip() item[summary] content[:200] # 发布时间 item[published_at] response.css(span.publish-time::text).extract_first() item[source_url] response.url item[image_url] response.css(div.article-content img::attr(src)).extract_first() yield item这段代码里最需要注意的是::text和::attr(href)的语法。::text取的是标签内的文本::attr(href)取标签属性。extract_first()返回第一个匹配项没有匹配时返回None不会抛异常所以后续存库时要对空值做兜底。摘要字段的常见做法是从正文裁前 200 个字符而不是指望目标网站提供 meta description因为不少站点根本没写这个标签。这种处理方式虽然粗暴但在聚合场景下够用。response.urljoin(link)用来把相对路径拼成绝对 URL这个必须处理否则链接直接跳转到错误页面。爬虫写完后的调试方式是scrapy crawl news_list -o output.json把结果输出成 JSON 文件先人工检查字段提取是否准确再接入数据库管道。不要一上来就全量跑先拿两个种子链接试跑确认字段没问题了再放开。3.3 数据入库管道Pipeline 里做清洗和去重Scrapy 抓到的数据要经过 Pipeline 才能进 MySQL。Pipeline 里至少要做三件事字段空值过滤、标题去重、入库。import mysql.connector class NewsPipeline: def open_spider(self, spider): self.conn mysql.connector.connect( host127.0.0.1, userroot, passwordyour_password, databasenews_aggregator, charsetutf8mb4 ) self.cursor self.conn.cursor() def process_item(self, item, spider): # 标题为空的数据直接丢弃 if not item.get(title): return item # 去重source_url 唯一索引防止重复入库 sql INSERT INTO t_news (title, summary, image_url, source_url, source_site, published_at) VALUES (%s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE summary VALUES(summary) self.cursor.execute(sql, ( item[title], item[summary], item[image_url], item[source_url], item[source_site], item[published_at] )) self.conn.commit() return item def close_spider(self, spider): self.cursor.close() self.conn.close()这里的关键设计是 MySQL 的INSERT ... ON DUPLICATE KEY UPDATE配合source_url的唯一索引做去重。爬虫重复抓同一篇新闻时不会插入新记录只会更新摘要。注意charsetutf8mb4一定要写否则遇到生僻字或 emoji 直接报错。open_spider和close_spider分别负责建立和关闭数据库连接这是标准姿势。实际项目中我并不建议每次抓取都commit()而是攒够一定数量批量提交比如在process_item里计数满 50 条commit()一次效率能提升一个量级。这个优化在毕设数据量下看不出来但如果你要抓上万条新闻差距会非常明显。你可以根据自己的数据量选择代码里先写成每条提交先保证正确再优化。4. SpringBoot 聚合与展示把抓到的新闻变成可浏览的网页4.1 REST 接口设计Controller 层如何对接数据库爬虫负责把数据写进 MySQLSpringBoot 这边要做的是把这些数据按时间倒序输出到页面。Controller 层设计遵循简单的 REST 风格一个查询接口按分页返回新闻列表一个接口返回新闻详情。项目里用的是 SpringBoot 加 MyBatis 的组合这类课程设计最常见的配置就是spring-boot-starter-web加mybatis-spring-boot-starter。RestController RequestMapping(/api/news) public class NewsController { Autowired private NewsService newsService; GetMapping(/list) public ResultPageResultNews list(RequestParam(defaultValue 1) int page, RequestParam(defaultValue 10) int size) { PageResultNews result newsService.pageQuery(page, size); return Result.success(result); } GetMapping(/detail/{id}) public ResultNews detail(PathVariable Long id) { News news newsService.getById(id); return Result.success(news); } }RequestParam(defaultValue 1)让前端不传页码时默认从第一页开始defaultValue 10控制每页条数。PageResult是统一分页返回对象包含总条数、当前页、每页大小和数据列表。Result是统一响应包装前后端约定code、message、data三个字段前端根据code判断请求是否成功。Service 层建议用PageHelper做分页插件它和 MyBatis 集成很顺滑——在application.yml里配置好helper-dialect: mysql然后在 Mapper 查询前调用PageHelper.startPage(page, size)就能自动生成 limit 语句。要注意的是PageHelper.startPage只对紧接着的第一条查询生效如果你在它和 Mapper 调用之间插了其他数据库操作分页就会失效。这是一个非常隐蔽的坑排错时先看 MyBatis 的 SQL 日志里有没有LIMIT关键字。4.2 前端页面渲染响应式布局和定时刷新前端用 Thymeleaf 模板引擎渲染页面因为 SpringBoot 对 Thymeleaf 的支持几乎是零配置。静态资源如 CSS 和 JS 放在src/main/resources/static/下main.js.bak备份文件的存在说明原项目里的main.js很有可能承担了前端请求逻辑。页面布局的常见做法是顶部导航栏放平台名称和分类入口中间主体是新闻卡片流每张卡片展示缩略图、标题、摘要和来源站点底部是分页组件。响应式布局靠 Bootstrap 栅格系统实现——col-md-4表示中等屏幕上每行 3 列col-sm-6表示小屏幕上每行 2 列手机端自动变单列。这个设计能覆盖电脑、平板、手机三种浏览场景毕业论文截图时也更有说服力。定时刷新用前端轮询或后端调度都行。课程设计场景建议用 Spring 自带的定时任务注解Component public class NewsSyncTask { Scheduled(fixedDelay 60000) public void syncNews() { // 调用Python爬虫脚本触发增量抓取 // 这里用ProcessBuilder调用系统命令 ProcessBuilder pb new ProcessBuilder(python, news_spider_crawl.py); pb.start(); } }fixedDelay 60000表示上次任务执行完后等 60 秒再执行下一次。这里用ProcessBuilder调用 Python 脚本是因为爬虫是独立进程直接内嵌 Java 代码调度最省事。ProcessBuilder调用外部命令时要特别注意工作目录问题——脚本里的相对路径会基于当前工作目录解析而不是基于脚本所在目录这可能导致找不到配置文件。解决方法是pb.directory(new File(/absolute/path/to/project))显式指定。这种设计的缺陷是定时任务和 Web 服务共用同一个 JVM 进程如果爬虫执行时间过长会占用 Tomcat 的线程资源。但在毕设的数据量下抓一次几十条新闻也就几秒完全够用。如果你追求更好的解耦可以把爬虫做成独立服务通过 HTTP 接口或消息队列触发这就是后话了。4.3 数据库设计要点索引、字符集和连接池数据库是整个平台的瓶颈所在设计时至少要保证两点查得快、不报错。建表语句里source_url要加唯一索引published_at要加普通索引title字段要加全文索引或至少用LIKE查询时配合%keyword%的通配符。MySQL 的默认存储引擎 InnoDB 支持行级锁和事务适合这种场景。字符集统一用utf8mb4排序规则用utf8mb4_unicode_ci。utf8mb4兼容 emoji 表情和所有 Unicode 字符新闻标题里偶尔会出现特殊符号用utf8会直接报Incorrect string value错误。这个坑我在第一次部署时踩过当时所有中英文都正常一遇到标题里的特殊字符整个事务回滚排查半天才反应过来是字符集问题。连接池配置在application.yml里spring: datasource: url: jdbc:mysql://127.0.0.1:3306/news_aggregator?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 10 minimum-idle: 2URL 参数里的serverTimezoneAsia/Shanghai必须加否则新版 MySQL 驱动会报时区错误。characterEncodingutf8mb4要和数据库、表的字符集保持一致三层不一致必炸。HikariCP 是 SpringBoot 默认连接池maximum-pool-size10够用别调太大数据库的连接数是有限的。前端展示时日期格式化是一个易漏的点。数据库存的是DATETIMEJackson 默认序列化成时间戳数组或 ISO 字符串前端显示不友好。解决方案是在application.yml里配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8这样接口返回的时间直接就是2025-01-15 14:30:00这种格式前端不用再做转换。如果你用的是LocalDateTime而不是Date还需要额外引入jackson-datatype-jsr310依赖否则 Jackson 无法正常序列化。5. 避坑与常见问题这些坑不踩一遍项目跑不起来5.1 端口被占用导致 SpringBoot 启动失败现象执行运行.bat后控制台报Port 8080 was already in use服务启动失败。原因之前跑过项目的进程没有关闭或者有其他程序占用了 8080 端口。解决先查端口占用情况netstat -ano | findstr 8080看到 PID 后在任务管理器里结束对应进程。不想每次手动查的话在application.yml里改端口server.port8090换个没人用的端口。5.2 Scrapy 抓取到的数据中文乱码现象MySQL 表里存的中文是???或者商业这类乱码。原因三层字符集不一致——数据库表用的是latin1Python 连接字符串没指定charsetutf8mb4或者 HTML 响应编码和 Scrapy 默认不一致。解决建表时指定DEFAULT CHARSETutf8mb4MySQL 连接串加上charsetutf8mb4Scrapy 的response.text会自动从 HTML 的meta charset推断编码但有些网站 meta 标签错误需要在settings.py里设置FEED_EXPORT_ENCODINGutf-8。5.3 爬虫被目标网站拦截返回 403现象爬虫日志显示HTTP 403 Forbidden拿不到任何页面内容。原因没有伪装 User-Agent或者请求频率太高触发了网站的反爬策略。解决在settings.py里配好浏览器 UA下载中间件加RetryMiddlewareDOWNLOAD_DELAY调大到 3 秒以上。我在实际项目里还会加一个随机 UA 的中间件——在DOWNLOADER_MIDDLEWARES里注册自定义中间件对每个请求随机从列表里选一个 UA这样更不容易被识别。5.4 JS 资源加载失败导致页面样式错乱现象前端页面能打开但布局完全错乱控制台报main.js加载失败。原因main.js.bak文件还在但真正的main.js可能被误删或者路径大小写不一致。Windows 路径不区分大小写Linux 服务器上区分部署到 Linux 环境就翻车。解决检查static/js/目录下是否有main.js没有就从main.js.bak复制一份过来改名。部署到 Linux 后所有静态资源引用路径要和实际文件名完全一致包括大小写。5.5 Maven 依赖下载慢或失败现象安装.bat执行时卡在下载依赖或者报Could not transfer artifact超时。原因Maven 默认从中央仓库拉依赖国内网络访问不稳定。解决改settings.xml在mirrors节点里加阿里云镜像mirror idaliyunmaven/id mirrorOfcentral/mirrorOf urlhttps://maven.aliyun.com/repository/public/url /mirror改完后再跑1-install.bat速度能快几倍。这是国内 Java 开发的标配操作面试被问 Maven 调优时也可以拿这个知识点说。6. 进阶技巧robots.txt 合规检查与抓取频率动态调节新闻聚合平台上线前我建议你把合规性检查作为最后一道工序。Scrapy 默认遵守ROBOTSTXT_OBEY配置在settings.py里设成True后Scrapy 会自动读取目标站的robots.txt如果disallow规则包含/article/爬虫就不会抓取这个路径。# settings.py 中启用 robots.txt 协议 ROBOTSTXT_OBEY True这个参数不是摆设它直接影响你部署后的安全性。我在做第一个实战项目时没开这个开关抓某新闻站时被对方安全团队发了告警邮件从那以后我每次配置爬虫都会先确认三件事ROBOTSTXT_OBEY是否开启、请求头是否伪装完整、抓取频率是否低于每秒一个请求。这三件事确认完再谈抓取效率的优化。另一个值得动手改的细节是请求频率的动态调节。静态的DOWNLOAD_DELAY不够灵活——目标网站响应慢时容易超时响应快时又抓得太慢。Scrapy 的AutoThrottle插件能根据响应时间自动调节延迟在settings.py里开启后效果明显AUTOTHROTTLE_ENABLED True AUTOTHROTTLE_START_DELAY 2.0 AUTOTHROTTLE_MAX_DELAY 10.0 AUTOTHROTTLE_TARGET_CONCURRENCY 2.0AUTOTHROTTLE_START_DELAY是初始延迟AUTOTHROTTLE_MAX_DELAY是最大延迟AUTOTHROTTLE_TARGET_CONCURRENCY是 Scrapy 希望达到的平均并发数。这个插件能边抓边调在保证速度的同时降低被封风险。调试时建议先在本地跑一个种子列表观察日志里的download_delay变化再全量跑。最后验证平台的完整性我会按这个顺序走一遍启动 MySQL 并确认库里能看到爬虫写入的数据启动爬虫手动抓一次启动 SpringBoot 应用浏览器访问首页确认新闻卡片正常渲染等待定时任务触发一次看新增新闻是否出现在页面顶部。五个步骤全绿这个项目才算真正跑通。这套验证流程也建议你在答辩前完整走一遍很多平时隐藏的问题都是在这个环节暴露的——比如库表字符集配置不一致、定时任务工作目录错误、前端静态资源路径缺失。经过一轮排查后再演示基本不会翻车。希望这些思路帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →