尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
基于网络舆情的Python股票分析系统:从爬虫到预测的完整实现
简介基于网络舆情的Python股票分析系统源码与说明是一份适合计算机相关专业学生及数据分析学习者实战练习的高分大作业覆盖从网络数据采集、自然语言情感分析、股价数据接入到可视化展示与走势预测的全流程利用新闻、社交媒体等渠道的舆情信息辅助投资判断。压缩包共2.87MB含89个文件以Python脚本、CSV数据、HTML页面及项目文档为主另有SQL与配置文件目录结构清晰便于按功能模块查阅。项目提供完整可运行的源码并附带立项文档、项目计划、需求分析文档等说明材料帮助理解从选题到实现的设计思路也适合作为课设与毕业设计的参考模板。系统经导师指导并评审得分98分通过严格调试可本地运行已有88人学习下载适合舆情分析方向入门及实战练习。1. 基于网络舆情的 Python 股票分析系统先确认它在本地能跑再谈预测准不准拿到这套《基于网络舆情的 Python 股票分析系统》源码包时我第一反应不是去翻预测模型而是先确认两件事环境依赖能不能用 conda 一键复现数据库脚本能不能直接导入。整套项目走的是 Flask MySQL 爬虫 NLP 情感分析的完整链路覆盖舆情采集、文本打分、行情对齐、涨跌预测和可视化展示五个环节是经过导师审阅、答辩评分 98 分的课程级作品。适合计算机相关专业的学生做大作业参考也适合想把手头舆情文本变成可量化信号的从业者照着改造。下面按我实际拆包、跑通、排坑的顺序来写每一步都是能直接落地的。2. 舆情数据链路爬虫采集、情感打分与数据库落地的完整实现2.1 项目结构与数据流转先看懂这几个目录再动手解压之后第一件事不是急着执行python app.py而是先看目录结构。这套项目把业务层拆得很规整我第一次跑通只改了两个文件靠的就是结构清晰stocksystem/ ├── app.py # Flask 入口注册蓝图 ├── config.py # 数据库连接、密钥等全局配置 ├── controller/ # 路由层URL 与页面映射 ├── service/ # 业务层情感分析、行情对齐、预测 ├── model/ # 数据模型与算法模型 ├── common/ # 公共工具DB 连接、日期处理 ├── templates/ # HTML 模板 ├── static/ # JS / CSS / ECharts 资源 ├── news_data/ # 爬虫抓回的原始舆情文本 ├── environment.yml # Conda 环境依赖 ├── stocksystem0107.sql # 带测试数据的库备份 ├── database.sql # 纯表结构脚本 └── README.md这里有两个设计点值得先注意。第一news_data 存的是原始爬取文本而不是直接入库好处是情感打分之后还能回看原文不会出现「分打完了却不知道凭什么」的情况。第二controller 和 service 拆开路由里没有复杂逻辑排查问题时直接进 service 层看。我一般会先把 database.sql 导入本地 MySQL再用 stocksystem0107.sql 覆盖这样既有表结构又有测试数据调接口时不用等爬虫慢慢抓。数据流转的主线是爬虫抓新闻和评论写入 news_data → service 清洗并做情感打分 → 结果写回 MySQL 的 news 表 → 行情模块拉 K 线按日期对齐 → 预测模型消费对齐结果 → Flask 渲染到 templates。断点检查也按这个顺序来先看 news_data 里有没有文件再看库里有没有记录最后看页面有没有数值。这三个位置能对上链路基本就没问题。2.2 舆情采集requests BeautifulSoup 抓新闻列表的写法舆情源的选择直接决定后续分析质量。常见做法是抓财经新闻门户的股票频道再用股票名称或代码过滤相关条目。下面是项目采集模块的简化版核心逻辑是「列表页解析 → 详情页抓取 → 落盘」三步import requests from bs4 import BeautifulSoup HEADERS {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)} def fetch_news_list(page_url): resp requests.get(page_url, headersHEADERS, timeout10) resp.encoding resp.apparent_encoding # 比写死 utf-8 更稳 soup BeautifulSoup(resp.text, html.parser) items [] for a in soup.select(.news-list a): # 选择器按目标站点实际 class 调整 title a.get_text(stripTrue) href a.get(href) if title and href: items.append({title: title, url: href}) return items def save_news(items, stock_code): path fnews_data/{stock_code}_news.jsonl with open(path, a, encodingutf-8) as f: for it in items: f.write(it[title] \t it[url] \n)逻辑说明fetch_news_list 先按 User-Agent 伪装成浏览器请求再用 BeautifulSoup 解析列表页把标题和链接成对取出。save_news 把结果追加写入 jsonl 文件按股票代码分文件存储。参数说明resp.apparent_encoding 是根据字节内容反推的字符集比写死 utf-8 稳因为不少财经站点的响应头声明和实际编码不一致抓回来全是乱码。HTML 选择器 .news-list a 只是示例不同站点结构差异很大我用浏览器开发者工具确认列表项实际 class 之后再写进代码。timeout10 是避免某个页面响应慢把整个抓取任务卡死批量跑的时候建议再加重试逻辑超时后重新请求一次。2.3 情感分析用 SnowNLP 给每条舆情算出 0 到 1 的态度分采集只是第一步真正出数值的是情感分析模块。项目用的是 SnowNLP 的 sentiment 接口返回 0 到 1 之间的概率值越接近 1 越正面越接近 0 越负面。这里有个关键做法不要直接对原文逐条跑而是先清洗再批量打分因为原始文本带着链接、标点和空白噪声会让分数整体朝 0.5 偏移。import re from snownlp import SnowNLP def clean_text(text): text re.sub(r\s, , text) # 合并空白 text re.sub(rhttp\S, , text) # 去掉 URL text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。], , text) return text.strip() def score_news(items): results [] for it in items: text clean_text(it[title]) if len(text) 4: # 过短标题没有分析价值 continue s SnowNLP(text) score s.sentiments results.append({ title: it[title], url: it[url], score: round(float(score), 3), label: positive if score 0.5 else negative, }) return results逻辑说明clean_text 依次做三件事——合并空白、删 URL、去掉与中文无关的符号这三步能明显减少误判。score_news 过滤掉长度小于 4 的标题因为过短文本在情感语料匹配上基本靠猜。参数说明0.5 是默认阈值实际使用建议先看分值分布再调。如果某只股票的舆情分值普遍在 0.45 到 0.55 之间波动阈值提到 0.6 反而更能抓住明显的态度变化正负分类也更有区分度。2.4 数据库表设计与 environment.yml 一键复现打分结果最终落进 MySQL。database.sql 里的 news 表核心字段如下这个设计足够支撑后续的聚合查询CREATE TABLE news ( id INT AUTO_INCREMENT PRIMARY KEY, stock_code VARCHAR(10) NOT NULL, title VARCHAR(200) NOT NULL, url VARCHAR(500) DEFAULT , score DECIMAL(4,3) NOT NULL, sentiment VARCHAR(10) DEFAULT neutral, news_date DATE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, KEY idx_code_date (stock_code, news_date) );stock_code 和 news_date 建了联合索引因为按股票和时间窗口聚合舆情分是最高频的查询索引直接决定页面响应速度。score 用 DECIMAL(4,3) 而不是 FLOAT避免浮点比较出现 0.5 和 0.500000001 之类的边界问题。sentiment 字段存正负类别虽然能从 score 反推但单独一列能让 SQL 聚合语句更简洁。环境复现我强烈建议用 conda别手动逐个 pip 安装版本错乱是这类型项目的头号杀手conda env create -f environment.yml conda activate stocksystem python app.pyenvironment.yml 锁定了 Flask、PyMySQL、SnowNLP、pandas、scikit-learn 这些关键依赖的版本。conda 会创建独立命名环境不污染系统 Python所以本机默认版本和项目锁定版本不一致也不影响。如果执行到一半报错或卡住多半是源的问题具体解法放在避坑章节单独说。3. 行情数据接入与对齐把舆情分值和股价放到同一个时间轴上3.1 行情接口选型为什么用 akshare 而不是手写行情爬虫舆情数据自采没问题但行情数据我强烈不建议自己爬。历史 K 线数据量大、字段格式敏感手写解析器很容易在复权、停牌、除权除息这些细节上翻车。项目里用的是 akshare 这类开源数据源接口一条调用拿到日线返回标准 DataFrame能直接和 pandas 的聚合逻辑衔接。import akshare as ak import pandas as pd def fetch_daily(stock_code000000, start2024-01-01, end2024-06-30): df ak.stock_zh_a_hist( symbolstock_code, perioddaily, start_datestart.replace(-, ), end_dateend.replace(-, ), adjustqfq ) df df.rename(columns{日期: date, 收盘: close, 涨跌幅: pct_change}) df[date] pd.to_datetime(df[date]) return df[[date, close, pct_change]].sort_values(date)逻辑说明stock_zh_a_hist 是 A 股日线接口perioddaily 表示日 Kadjustqfq 表示前复权。前复权很关键区间内若有分红送股不复权的价格会出现跳空涨跌幅计算直接失真。返回列名是中文所以 rename 成英文再转 datetime方便和舆情表的 news_date 匹配。参数说明start 和 end 建议与舆情采集区间保持一致差一天都可能造成窗口错位。akshare 的接口偶尔会因为上游页面改版临时不可用第一次调用报错时先确认库版本更新到最新版再跑。3.2 交易日对齐把自然日舆情归并到最近的交易日这是整套系统里最容易算错的地方也是我会先手算验证的一步。舆情新闻是自然日产生的周六周日大量发帖但 A 股只在交易日开盘。直接把周末舆情分值和周一收盘价放同一行相关性会被节假日稀释掉。常见做法是把舆情日期向后映射到最近的下一个交易日def align_sentiment_to_trade_day(news_df, trade_df): trade_days sorted(set(trade_df[date].dt.date)) news_df[aligned_date] news_df[news_date].apply( lambda d: next((t for t in trade_days if t d), None) ) grouped news_df.groupby(aligned_date).agg( avg_score(score, mean), news_count(score, count), pos_ratio(sentiment, lambda x: (x positive).mean()) ).reset_index() return grouped逻辑说明aligned_date 的规则是「找大于等于舆情日期的最近一个交易日」把周末和节假日的舆情全部归并到下个交易日。groupby 之后得到三个特征avg_score 是当日舆情均值news_count 是信息量pos_ratio 是正面占比。这三个特征比单纯用均值更有区分度后面预测模型直接拿它们当输入。参数说明trade_days 必须先升序排序否则 next() 返回的可能是过去的日期如果某个舆情日期在所有交易日之后lambda 会返回 None实际使用时记得 dropna。注意不同数据源对股票代码的格式化要求不同有的要带 sh/sz 前缀有的只要纯数字。接行情接口前先确认格式否则 400 错误查起来很绕。3.3 相关性预检建模前先算一次皮尔逊系数模型训练前先算舆情均分和次日涨跌幅的相关系数能快速判断数据链路通不通。如果系数接近 0后面模型做得再精细也白搭应该回头查对齐逻辑或舆情源质量而不是继续调参。merged pd.merge( aligned, trade_df[[date, pct_change]], left_onaligned_date, right_ondate, howinner ) merged[next_return] merged[pct_change].shift(-1) merged merged.dropna(subset[next_return]) corr merged[avg_score].corr(merged[next_return]) print(f日舆情均分与次日涨跌幅相关系数: {corr:.4f})howinner 是刻意选的宁可少几条数据也要保证对齐可靠。shift(-1) 把涨跌幅前移一天得到的是「舆情出现之后那一个交易日」的收益如果直接用当天涨跌幅就构成未来函数结果虚高但不真实答辩时经不起追问。相关系数落在 0.1 到 0.2 之间是正常的舆情本来就只是影响股价的众多因素之一能稳定为正就说明特征构造方向对了。4. 预测模型与可视化把舆情信号变成能展示的涨跌判断4.1 特征构造与二分类模型滞后特征加逻辑回归对齐之后的特征不能直接用单日舆情噪声太大。项目采用滚动窗口的做法用过去 N 个交易日的 avg_score、news_count、pos_ratio 构造滞后特征预测下一个交易日的涨跌方向。窗口 N 是超参3 和 5 是常见起点过大反而会把短期的情绪突变抹平。from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression def build_features(merged, window3): df merged.sort_values(date).copy() for col in [avg_score, news_count, pos_ratio]: for w in range(1, window 1): df[f{col}_lag{w}] df[col].shift(w) df[target] (df[next_return] 0).astype(int) return df.dropna() df build_features(merged) feature_cols [c for c in df.columns if c.endswith(_lag)] X, y df[feature_cols], df[target] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, shuffleFalse ) clf LogisticRegression(max_iter1000) clf.fit(X_train, y_train) print(f测试集准确率: {clf.score(X_test, y_test):.3f})逻辑说明滞后特征 shift 之后自然产生 NaNdropna 会把前 window 行样本舍弃符合「历史必须完整」的原则。shuffleFalse 是硬性要求时间序列样本存在顺序依赖打乱之后验证集会偷看未来信息评估结果虚高。参数说明max_iter1000 是因为特征数值尺度差异大时默认 100 次迭代可能不收敛并弹出警告。如果分类结果极端偏向某一类先看 target 的正负样本比例再决定要不要用 class_weight 或者移动判定阈值别急着换复杂模型。4.2 Flask 路由与模板联动把预测结果搬到页面上模型算完只完成了一半这套系统的加分项在可视化。controller 里的路由把 service 的结果传给模板逻辑很薄from flask import Blueprint, render_template from service.analyze_service import get_stock_report stock_bp Blueprint(stock, __name__) stock_bp.route(/stock/code) def stock_report(code): report get_stock_report(code) return render_template(stock_detail.html, codecode, reportreport)数据库查询、特征计算、模型预测都收在 service 的 get_stock_report 里路由只做参数转发和模板渲染以后换舆情源或换模型都不需要动路由层。前端模板用 ECharts 画双轴图左轴是收盘价折线右轴是舆情均分柱状两条曲线的峰谷错位关系就是答辩现场最好的讲解素材。static 目录里的静态资源记得用 url_for(static, filename...) 引用直接写相对路径是模板渲染 404 的最常见原因这坑我见人踩过不止一次。4.3 service 返回结构让前端拿到可解释的结果get_stock_report 内部做的事查 news 表做窗口聚合 → 拉行情 → 调模型预测 → 拼成模板需要的字典。返回结构示例return { stock_code: code, avg_score: round(float(avg_score), 3), news_count: int(news_count), prediction: 偏多 if prob 0.55 else (偏空 if prob 0.45 else 震荡), prob: round(float(prob), 3), trend: [{date: d, close: c, score: s} for d, c, s in trends], }prediction 字段故意不做「涨 / 跌」二值硬判而是三档偏多、偏空、震荡。理由很实际舆情是弱信号强行二分类容易给人「预测很准」的错觉反而容易被评委追问到细节。prob 输出的是模型预测概率而不是 0/1 标签方便使用者看到置信度也方便后续接回测模块统计不同阈值下的胜率。trend 列表是图表的数据源date、close、score 三个字段一一对应前端渲染时不需要再处理数据格式。5. 避坑排查本地跑通这套系统的五个高频问题以下五个问题是我在复现这类「爬虫 数据库 Flask」组合时遇到频率最高的按出现概率排序每条都按现象、原因、解决三段写清。5.1 conda env create 失败卡在 Solving environment现象执行conda env create -f environment.yml后长时间停在 Solving environment最后报 PackageNotFoundError 或连接超时。原因默认 conda 源在部分网络环境下访问极慢依赖求解时间被拖长另外 environment.yml 里锁定的某个包版本和当前平台存在兼容冲突时也会卡住。解决先切换镜像源再重新执行创建命令。如果仍然失败看报错中第一个缺失的包名把 environment.yml 里对应版本放宽例如把python3.9.13改成python3.9.*。执行成功后建议立刻conda env export environment_backup.yml留一份本地快照后面重装时不用再猜。5.2 数据库连不上Access denied 和建库顺序现象启动 app.py 之后页面报 500终端日志里出现Access denied for user或者报Unknown database。原因config.py 里配置的数据库账号、密码和本地 MySQL 不一致或者 stocksystem 这个库还没有创建。很多人直接跑备份脚本却忘了先建空库。解决先手工执行 database.sql 建库建表确认库存在后再导入 stocksystem0107.sql。然后核对 config.py 里的 host、port、user、password 四个字段本地开发建议统一用 root 账号避免权限不足的幺蛾子。改完配置必须重启 Flask 进程配置只在启动时加载一次。5.3 网页上中文全是问号现象页面标题和新闻文本正常但数据库里查出来的中文在页面上显示成 ???或者反过来库里是乱码、页面正常。原因建库或建表时字符集不是 utf8mb4同时连接层的 charset 参数也没设置两边有一边不对就出现乱码。解决建库语句显式指定CHARACTER SET utf8mb4config.py 里的连接串加上charsetutf8mb4。已有库可以执行ALTER DATABASE stocksystem CHARACTER SET utf8mb4但注意只改库、不改连接参数仍然无效。这个问题的表现有很强的迷惑性我第一次遇到时以为是前端编码问题浪费了半天。5.4 情感分数全在 0.5 附近语料偏差现象所有新闻的 score 几乎都在 0.45 到 0.55 之间正负标签几乎没有区分度页面上的舆情柱状图看着是一条平线。原因SnowNLP 默认语料偏向电商评论财经文本的措辞风格差异较大情感倾向被拉向中性。另一个常见原因是清洗逻辑把否定词截断了比如「不看好」被正则里的符号过滤规则拆成「不」和「看好」情感直接反转。解决先检查清洗逻辑确保「不、没、难、跌」这类否定词完整保留。再看分值分布如果整体集中在 0.5 附近把判定阈值从 0.5 上调到 0.6 或下调到 0.4。要做课程展示的话这两个手段基本够用如果要跨过 0.5 这道坎就得标注一小批财经样本做自定义训练了。5.5 页面能开但图表空白现象网页能正常打开股票列表也正常但详情页的 ECharts 区域一片空白浏览器控制台报 404 或某个变量 undefined。原因静态资源路径写错或者 trend 数据为空。ECharts 拿到空数组时不会报错只会渲染一个空白坐标系所以排查时容易被误导。解决先在浏览器 Network 面板确认 echarts.min.js 是否返回 200不是就去改模板里的 static 引用方式改用 url_for。然后到 service 层打日志确认 trends 列表的长度如果为空通常是行情接口在所选日期范围内没有数据或者日期范围本身太窄。两个位置按顺序排查问题基本都能定位。6. 答辩演示与效果验证用一条对比图讲清舆情和股价的关系跑通之后别急着截图交差先做一次完整的端到端验证。选定一只舆情样本充足的股票重新跑一遍从采集到预测的全流程然后用下面这段脚本输出几个关键指标print(舆情样本量:, len(news_df)) print(对齐后交易日数:, len(merged)) print(相关系数:, round(corr, 4)) print(模型准确率:, round(acc, 3))我一般给自己定三条验证标准样本量不少于 200 条对齐后交易日数不少于 30 天相关系数不为负。三条都过了再打开页面把舆情柱状图和收盘价折线的峰谷错位关系讲清楚重点解释滞后特征为什么要用 shift(-1)、自然日不对齐会导致什么后果。这个演示角度比单纯报一个准确率数字更有说服力因为评委能看出来你理解的是整条数据链路而不是只会调库。还有一个展示技巧优先选一只在采集区间内有明确正面或负面新闻、且股价出现对应波动的股票当演示案例比随手输一个代码进去效果好得多。舆情分析和预测模型的价值不在「猜得准」而在「事件发生时系统能否捕捉到情感变化」这个可解释的事实。带着案例讲比空谈准确率和损失函数更能让人记住。从那以后我每次复现这种带爬虫和数据库的项目都会强制自己先走一遍「造数 → 入库 → 对齐 → 出图」的最小闭环再谈模型调参。这个习惯帮我避开了不少看着能跑、实际数据是空的假象。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Flexsim自动化立体仓库仿真建模:从实体搭接到参数优化的完整指南

Flexsim自动化立体仓库仿真建模:从实体搭接到参数优化的完整指南

简介:这是一份围绕自动化立体仓库(AS/RS)效率优化展开的毕业设计论文资源,适用于物流工程、工业工程及计算机相关专业学生,也适合需要借助 Flexsim 进行仓储系统建模与仿真分析的设计人员。文档完整呈现了从仓库组成与…

📅 2026/10/18 14:18:37
Python高德交通数据分析:从拥堵指数到早高峰出行建议

Python高德交通数据分析:从拥堵指数到早高峰出行建议

简介:这是一份面向交通物流与数据分析学习者的高德地图交通拥堵分析项目源码,针对早高峰通勤场景,通过抓取指定路段历史路况数据,分析拥堵时段分布,帮助合理规划出门时间,适合有Python基础、想实践爬虫、AP…

📅 2026/10/18 14:18:37
Deepseek-harness新手安装教程:附带实用插件与OpenCode对接

Deepseek-harness新手安装教程:附带实用插件与OpenCode对接

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/18 14:18:37
MORE NEWS

更多资讯

📰

Java中javac和JIT编译到底有何区别?一文讲透两阶段编译机制

1. 别再把两件事混为一谈了:先分清“编译”的两个含义只要写过Java的人,基本都干过这两件事:一是执行javac把.java文件编译成.class文件,二是在IDE里点一下运行,然后看着程序跑起来。表面上看,这两个动作都…

📰

在 Python 编程中,字符串是最基础也最常用的数据类型之一

在 Python 编程中,字符串是最基础也最常用的数据类型之一。无论是数据处理、日志记录、用户交互还是报表生成,都离不开对字符串的格式化输出和清洗操作。str.format() 方法提供了强大的格式化能力,可以控制字段宽度、对齐方式、小数精度等&am…

📰

AI工具装了没人用?从接入成本到习惯养成的落地指南

“AI工具装好了,但团队没人用”——这句话我这两年听过太多次。几乎每个想推AI落地的开发团队,都会撞上同一个尴尬:工具选型报告写得漂漂亮亮,部署文档比需求文档还细,结果上线两周后后台一看,日活不到两位…

📰

归并排序递归与非递归实现:从分治原理到工程化优化

搞过一次大数据量排序之后,我才真正意识到递归版归并排序在教学上和工程上完全是两码事。理论课上讲归并排序,教科书永远是递归写法,简洁漂亮;但真到了处理大批量数据的时候,频繁的临时数组分配和函数调用开销会让人想…

📰

函数是Python编程的核心构建块,也是程序设计中实现代码复用、模块化和抽象化的重要手段

函数是Python编程的核心构建块,也是程序设计中实现代码复用、模块化和抽象化的重要手段。本报告将系统性地探讨Python函数的声明与调用机制、参数传递原理、变量作用域规则以及静态变量(static)的实现方式。通过丰富的代码示例和深入的原理解…

📰

切片级漏洞检测:用GNN实现函数内精准漏洞定位

简介:本资源是一套面向计算机及相关专业(如信息安全、人工智能、软件工程)在校学生与初阶研究者的毕业设计级项目,聚焦图神经网络在源代码切片层面的漏洞检测与可解释性分析。项目完整实现从C语言代码预处理、Joern生成PDG图与lin…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬