如果你拿到的是《查询股票信息与新闻系统》这种毕设题目心里多半会犯嘀咕行情数据从哪来新闻怎么自动抓到系统要做到什么程度才算合格我当初做同类项目时也一步步踩过这些坑。把这个题目拆开看本质就是一个带用户体系的行业信息聚合Web应用左边是股票行情数据右边是新闻资讯流中间用数据库和定时任务把它们串起来。这类题目的好处是技术栈非常完整前后端交互、HTTP请求、数据解析、爬虫、定时任务、数据库建模全都能涉及而且数据源可以用公开免费接口不碰交易和资金安全非常适合做毕设。这篇文章会直接给你一条从需求拆解、技术选型到核心实现、答辩准备的完整链路。不管你是准备从头写还是手里已经有一套“附源码58899”的工程但完全看不懂都能照着这份思路把它落地、讲清楚。1. 先看懂这个毕设题目的本质1.1 选题的隐藏考点很多同学看到“股票”两个字就发怵觉得金融类项目离自己太远。实际上这个题目考察的根本不是金融知识而是三件事你能不能稳定地拿到外部数据能不能把数据处理后展示出来能不能用工程手段让整个系统跑得顺畅。“查询股票信息”考察的是HTTP请求、JSON/GBK解析、K线数据结构化处理“新闻系统”考察的是爬虫采集、去重、文本存储和关键词匹配“系统”两个字则暗示你要有完整的用户体系、数据库设计和前后端联动。把这个逻辑想明白你会发现它和“天气查询系统”“电影资讯系统”没有任何本质区别只是数据源不同。1.2 功能拆解与模块划分我习惯先列功能清单再写代码。一个能顺利通过答辩的版本至少应该有下面这些模块功能模块核心内容技术要点用户注册登录账号注册、登录、退出Session或JWT、密码加密股票查询输入代码或名称查看实时行情HTTP请求、字段解析K线展示日K、周K、月K图ECharts图表组件股票列表按涨跌幅、成交额排行列表接口、分页展示新闻聚合股票相关新闻抓取与展示爬虫、去重、入库自选股管理添加删除自选股关联表设计、增删查定时刷新缓存行情数据APScheduler或Scheduled很多二次开发的源码包其实只有前两个功能后面几个模块是缺失的这就给了你很大的提升空间。我建议你把“个股新闻”和“自选股”这两个模块重点补强因为它们是评分老师最容易看出来你花过心思的地方。2. 技术选型与总体架构别上来就写代码2.1 后端框架Spring Boot 还是 Flask这是每个做毕设的同学都要纠结的问题。我的建议很简单看你们小组的教学主语言。学校一直用Java讲SSM、Spring Boot那就老老实实用Java答辩时老师问框架细节你能对答如流。如果Java学得一般Python的Flask确实上手更快一个文件就能起服务也方便后期加爬虫逻辑。拿Spring Boot举例我建议用经典的Controller-Service-Mapper三层结构再加一个ScheduledTask做定时任务一个HttpUtil封装对外请求。Python方案则用Flask蓝图拆成auth、stock、news、watchlist几个模块。无论哪种一定要让包结构看得懂这比用什么框架重要得多。2.2 前端方案别整花活稳定最重要前端部分最稳妥的组合是Bootstrap加jQuery或者Vue3加Element Plus。选Bootstrap的好处是页面不改也能看适合时间紧张的同学选Vue3则方便用ECharts做图表K线交互会更流畅。K线图直接用ECharts的candlestick系列不用自己画坐标轴把数据组装成[日期, 开, 收, 低, 高]传进去就行。需要提醒的是ECharts体积不小用npm按需引入不要全量打包不然首屏加载会很慢。2.3 数据库表结构设计毕设系统不需要复杂表四张表足够用户表、股票基础信息表、自选股表、新闻表。设计时抓住几个关键点。用户表必须有salt字段配合密码加密不能用明文。股票基础信息表存代码、名称、交易所、行业插入一次基本不再变动。自选股表用user_id stock_code做联合唯一索引防止同一用户重复添加同一只股票。新闻表的核心字段是标题、来源、链接、发布时间并且给标题列加唯一索引或存一个title_hash这是后面做去重的基础。CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, salt VARCHAR(32) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );股票代码的存储我建议直接用varchar(10)格式统一成sh600000、sz000001这种带交易所前缀的形式。这样后面调用行情接口时可以直接拼URL省去判断沪市深市的麻烦。2.4 行情与新闻数据源怎么选这是整个项目最容易卡住的地方。很多同学一上来就去找付费金融数据库其实完全没必要。目前免费的方案有三种实测都稳定。新浪行情接口返回字段最全但要求请求头带Referer编码是GBK。腾讯行情接口速度稍快但字段顺序需要自己认真数。东方财富接口适合拿K线历史数据参数丰富返回JSON解析最简单。新闻数据相对麻烦一点。可以用东方财富的个股新闻接口也可以直接爬新浪财经的新闻列表页用BeautifulSoup解析a标签里的标题和链接。如果你所在学校对实时性要求不高更省事的方案是用第三方免费新闻API申请一个key就能用缺点是覆盖面和字段有限制。3. 核心功能实现拆解3.1 实时行情查询一个请求解析出现价涨跌行情接口看起来神秘拆开就是一个普通HTTP请求。我用新浪接口给你演示最核心的解析逻辑import requests def get_stock(code): url fhttps://hq.sinajs.cn/list{code} headers { Referer: https://finance.sina.com.cn, User-Agent: Mozilla/5.0 } resp requests.get(url, headersheaders) resp.encoding gbk line resp.text.split()[1] fields line.split(,) return { name: fields[0], open: float(fields[1]), pre_close: float(fields[2]), price: float(fields[3]), high: float(fields[4]), low: float(fields[5]), volume: int(fields[8]), amount: float(fields[9]) }这里有两个非常关键的细节。第一新浪接口不带头Referer直接返回403这是反爬基本手段。第二接口返回的是GBK编码如果你用默认UTF-8解析中文名称和部分字段会乱码。我在第一次调试时就因为这两点浪费了两个小时。拿到字段后涨跌幅和涨跌额推荐在后端算好再传给前端。因为前端只需要显示把计算逻辑放在后端接口数据更干净也方便以后做排行榜排序。3.2 K线数据获取与ECharts绘图K线数据我推荐用东方财富的接口因为它返回的就是标准JSON省去大量解析工作。请求格式大致如下https://push2his.eastmoney.com/api/qt/stock/kline/get ?secid1.600000 fields1f1,f2,f3,f4,f5 fields2f51,f52,f53,f54,f55,f56,f57 klt101 fqt1 beg20230101 end20241231其中secid规则是沪市以1.开头深市以0.开头600000换成你需要查询的股票代码即可。klt101表示日K102是周K103是月K。fields2里的f51到f57分别对应日期、开盘、收盘、最高、最低、成交量、成交额。后端拿到这些数据后转成ECharts需要的格式// ECharts candlestick 数据格式 const klineData rawData.map(item [ item[0], // 日期 item[1], // 开盘价 item[2], // 收盘价 item[3], // 最低价 item[4] // 最高价 ]);注意ECharts的kline系列要求的是[开盘收盘最低最高]顺序很多人会不小心按日期、开、高、低、收盘传结果图形完全不对。如果你想让项目多点技术含量在此基础上算一个MACD或KDJ指标做成副图展示答辩时绝对是个加分项。这类指标计算逻辑可以直接参考开源社区的金融技术指标库不用自己从头推导公式。3.3 新闻聚合抓取、去重、入库一套带走新闻模块的难点不在爬虫本身而在怎么保证数据不脏、不重复。最早我做的时候图省事每次页面加载都直接爬一次新闻源结果接口被限流页面加载还慢。后来改成定时任务抓取加数据库去重才解决问题。抓取用最简单的requests加BeautifulSoup即可from bs4 import BeautifulSoup import requests def crawl_news(keyword): url fhttps://finance.sina.com.cn/roll/index.d.html headers {User-Agent: Mozilla/5.0} html requests.get(url, headersheaders).text soup BeautifulSoup(html, html.parser) items soup.select(.list_009 a) # 根据实际页面结构调整 for item in items[:20]: title item.get_text(stripTrue) link item.get(href) # 入库前先算标题哈希 yield title, link去重逻辑我在入库前对标题做了一次MD5生成title_hash字段数据库里加唯一索引。插入时用INSERT IGNORE重复的标题直接跳过这样爬虫写多简单都不会产生重复数据。如果你还想做关键词匹配可以给新闻表加一个industry或tags字段保存抓取时携带的行业分类方便前端按板块过滤。3.4 用户登录与自选股关联表是核心用户模块直接用框架自带方案最省事。Java的Spring Security可能配置略重建议直接用JWT或者简单的Session拦截器。Python方案用Flask-Login或者手动写登录装饰器都可以。自选股表的本质是用户与股票的多对多关系核心字段只有三个CREATE TABLE watchlist ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, stock_code VARCHAR(10) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_user_stock (user_id, stock_code) );添加自选股时先查一次这个联合唯一索引返回冲突就提示用户已经添加过。删除自选股时需要注意前端表格传过来的可能是多个股票代码建议后端接收逗号分隔的字符串然后在SQL里用IN批量删除。这个细节能在并发操作时明显减少数据库压力实际体验也比一条条删顺畅很多。3.5 定时任务与缓存不要让用户请求打到外部接口行情接口虽然免费但不代表没有频率限制。我做压力测试时发现如果每个用户刷新页面都实时请求新浪接口几十个并发就会触发风控导致IP被临时限制。解决方案很简单加一层缓存。后台起一个定时任务每3分钟把自选股列表里涉及的行情数据批量刷新到内存缓存或Redis。用户查询时直接读缓存只有缓存过期或首次查询时才会回源请求外部接口。Python写法可以这样from apscheduler.schedulers.background import BackgroundScheduler def refresh_stock_cache(): codes get_all_watchlist_codes() for code in codes: stock_cache[code] get_stock(code) print(f缓存已刷新共 {len(codes)} 只股票) scheduler BackgroundScheduler() scheduler.add_job(refresh_stock_cache, interval, minutes3) scheduler.start()Java的Spring Boot也差不多在启动类上加上EnableScheduling然后在方法上写Scheduled(cron 0 */3 * * * ?)就可以。这一步在很多源码包里是缺失的自己补上以后性能上和答辩故事上都好讲很多。4. 常见问题与排查技巧实录4.1 高频报错与解决方案这个项目我刚做完时遇到过一堆问题后来整理了一张速查表基本覆盖了毕设阶段的常见坑现象原因解决办法新浪行情接口返回403缺少Referer头请求头添加Referer: https://finance.sina.com.cn解析出的中文乱码接口是GBK编码设置resp.encoding gbk股票代码无法区分市场sh/sz/bj前缀写错维护一只股票所属交易所的表拼接前缀请求一多就超时接口限流定时任务加缓存每只股票间隔0.3秒以上新闻数据重复多来源抓取未去重标题MD5加唯一索引K线图显示空白数据格式顺序不对确认传入顺序为开盘、收盘、最低、最高这里再提一个容易被忽视的问题学生机房出口IP经常是共享的同一时间多个人访问同一个行情接口很容易被一起封禁。我建议开发调试时尽量用本地测试数据部署演示时才让系统真正请求外部接口。4.2 答辩演示的黄金节奏毕设答辩时间通常只有10到15分钟演示顺序不对很可能核心功能还没展示完就被叫停。我推荐的演示脚本是注册新账号体现用户体系完整→ 在搜索框输入股票代码体现查询核心功能→ 切到自选股页面展示添加和删除体现关联表操作→ 打开个股K线图体现数据可视化→ 展示新闻列表体现爬虫模块→ 最后停在定时任务日志页面让老师看到系统是自动刷新的。前三个步骤控制在3分钟以内后面给新闻和定时任务留足时间。老师最关心的是“数据来源是否可靠”和“系统是不是你自己写的”所以每个环节都要准备一句话解释数据从哪来、缓存策略是什么。如果老师追问“系统崩溃了怎么办”你就说核心数据有MySQL落地外部接口失败时有缓存兜底做到这一层就已经超过大多数同学了。4.3 源码管理与文档规范很多同学拿到源码包第一件事就是解压跑通然后把readme.md删掉直接改名字提交这是非常危险的。我见过太多人因为源码包里的数据库脚本和自己的配置对不上导致运行失败。正确的做法是先建一个干净的Git仓库把源码包作为初始提交然后逐步修改代码并留下清晰的commit记录。这样既能体现工作量也能在源码出现诡异bug时随时回退。文档方面README至少写清楚四部分项目简介、环境要求、启动步骤、功能说明。数据库初始化SQL一定要单独放一个.sql文件并且带上测试数据。启动步骤要用步骤列表写清楚而不是一句话带过。答辩演示时电脑上最好提前准备好完整的运行环境不要现场临时装依赖网络一波动非常尴尬。5. 一些能让你项目更出彩的想法5.1 低成本扩展方向指标计算、股票筛选、新闻分析基础功能做完以后如果想往高分冲一冲我不建议加一些看起来很炫但根本讲不清楚的功能比如机器学习预测股价或实时期货数据。性价比最高的三个扩展方向是技术指标计算、条件筛选器和新闻情感分析。技术指标计算就是自己实现MACD、KDJ、RSI这类常见指标算完在K线图下方用折线图展示。条件筛选器可以做一个简单的表单让用户输入涨跌幅区间、成交量下限后端用SQL或内存过滤返回结果。新闻情感分析更简单准备一个包含积极词和消极词的词典对新闻标题分词后打分给每条新闻标一个正面、中性、负面的标签。这三个方向都不需要额外依赖工作量可控而且每一个都能在答辩时展开讲至少两分钟。5.2 拿到源码包之后怎么把它变成自己的东西如果你手里已经有一套“毕设附源码58899”这种工程第一步是先把它跑起来理解启动脚本、数据库配置、第三方接口这三个入口。第二步画一张架构图标出哪些是现成的、哪些是查不到文档的死代码。第三步就是动手改随便挑一个页面比如把行情表格加一列“换手率”或者把新闻列表改成卡片风格这个过程中你会被迫读懂一半代码。我个人的经验是不要急着把所有功能都重写那样容易把整个项目改挂。保留核心框架在边角功能上做增量修改既能保证演示稳定又能让你在答辩时说出“这块是我加的”“那块的逻辑我优化过”。就算老师问到底层实现你也有真实经验可讲而不是背别人的代码。这个项目做下来最有价值的地方恰恰是那几次调试失败的过程。第一次被接口403拦截第一次K线图渲染成空白第一次数据库出现重复数据每一次踩坑都会让你对系统整体设计有更深的理解。所以如果你正在为这个题目发愁不用怕把一个模块一个模块拆开做最后你会发现它只是你熟悉HTTP、爬虫和数据库设计的一个载体而已。