资讯详情

Python网络舆情股票分析:从情感量化到交易信号生成实战

📅 2026/10/12 13:39:23 | 华诺云谱 👁 阅读
Python网络舆情股票分析:从情感量化到交易信号生成实战
简介基于网络舆情的Python股票分析系统是一份面向计算机专业学生与实战学习者的高分课程项目聚焦从互联网舆情采集到股票走势预测的完整分析链路。项目源码经导师指导与评审得分98分全部代码可本地运行适合用作毕业设计参考、数据挖掘练习或金融量化入门实战。资源包共89个文件总大小约2.87MB。主体为49个Python脚本覆盖网络爬虫、情感分析、预测建模等核心模块另含11个CSV数据文件、9个HTML页面、SQL数据库脚本、Word文档与YAML环境配置可快速还原项目依赖与运行环境。目录按系统模块划分便于对照源码理解从舆情数据收集、自然语言处理到可视化展示与预测模型构建的完整实现。目前已有88人浏览学习。对于想掌握Python数据分析、爬虫与股票市场结合应用的学习者这份高分项目提供了可直接运行的工程实现和配套文档可有效降低上手门槛并方便二次开发。1. 基于网络舆情的Python股票分析系统大作业做到能答辩靠的是把情绪量化成信号做课程设计时最怕的不是代码写不出来而是系统做完之后导师问一句“你的创新点在哪”。用网络舆情驱动股票分析算是Python大作业里少数能把数据采集、文本挖掘、量化策略串成一个闭环的方向。它的核心思路并不复杂先把股吧、新闻评论区里的散户情绪抓下来用情感分析打成“乐观/悲观”分数再把分数和K线、均线、RSI这类行情指标叠加生成买入或卖出的参考信号。这套系统做完既能展示Python全栈能力又能拿出可视化图表和回测数据撑住答辩。适合课程设计、毕业设计也适合想从爬虫往量化方向过渡的Python学习者照着复现。2. 舆情数据从哪来东方财富股吧评论的采集、清洗与存储2.1 抓什么、怎么抓接口选型与请求参数做舆情分析的第一步不是写爬虫而是先想清楚数据源。常见做法是抓东方财富股吧的帖子列表和评论内容因为股吧评论量大、更新快而且接口是公开的不需要登录就能拿到JSON数据。相比抓新闻网站股吧文本更口语化情感倾向更明显适合做情感分析。我一般用东方财富的股吧列表接口地址是https://gbapi.eastmoney.com/stock/getNews?code...它有几个比较关键的请求参数code是股票代码带上市场前缀比如上海股票是sh600519pageindex是页码pagesize是每页条数最大可以拉到 50。返回的是标准JSON包含帖子标题、阅读数、评论数、发布时间但没有正文内容正文需要再拿帖子ID请求详情接口。如果嫌麻烦也可以直接抓帖子标题来当分析语料——标题的情绪密度比正文还高。实际写代码的时候我发现几个容易被忽略的细节。第一是请求头必须带User-Agent和Referer否则很容易被拦截第二是接口返回的showtime字段是时间戳格式要先转成北京时间再落库第三是翻页是pageindex递增但有些股票帖子量很大建议只抓最近 13 天的数据而不是整个历史否则数据量和分析时间都会失控。2.2 数据清洗与中文分词从原始文本到可分析语料股吧评论直接拿去跑情感分析效果一定很糟糕。原因很简单文本里有大量噪声比如表情符号、用户、股票代码、数字、重复的“哈哈哈”以及HTML标签残留。我的清洗流程固定四步先去HTML标签和URL再去掉数字和英文字母保留中文和基础标点然后用正则把表情符号和特殊字符替换成空格最后用jieba做精确模式分词。分词之后还有一个关键操作去停用词。网上有现成的中文停用词表但股吧场景需要自己再追加一批词比如“转发”“评论”“点赞”“楼主”“股吧”这些词几乎每条评论都有对情感分析毫无贡献频率又高会把后续权重计算带偏。我一般会在代码里维护一个自定义停用词列表把这种语料特有的高频词过滤掉。清洗和分词这一步看似不起眼却直接决定情感分析的上限。曾经我们把清洗前后的文本分别跑情感分析发现未经清洗的数据里中性占比多出 20 多个百分点原因就是数字和URL干扰了情感词的识别。清洗代码建议单独写一个clean.py模块因为后面的情感分析、词云生成、特征统计都要复用同一套清洗管线写在一起后面改起来很痛苦。2.3 评论采集的完整实现请求、解析、翻页与限速下面这份采集代码是我一个课程项目里实际在用的版本抓取指定股票最近几页的股吧帖子标题并把结果存成CSV。代码做了三件事请求接口、解析JSON、翻页循环。为了不让爬虫给服务器造成压力每次请求之间强制休息 12 秒。import requests import json import time import csv from datetime import datetime def fetch_guba_posts(stock_code, pages5, page_size50): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://guba.eastmoney.com/ } base_url https://gbapi.eastmoney.com/stock/getNews all_posts [] for page in range(1, pages 1): params { code: stock_code, # 例如 sh600519 pageindex: str(page), pagesize: str(page_size) } try: resp requests.get(base_url, paramsparams, headersheaders, timeout10) resp.raise_for_status() data resp.json() # 接口返回的 data 是 JSON 字符串需要二次解析 news_list json.loads(data[data])[list] for item in news_list: all_posts.append({ code: stock_code, title: item.get(title, ), read_count: item.get(readcount, 0), comment_count: item.get(commentcount, 0), post_time: datetime.fromtimestamp(item.get(showtime, 0)).strftime(%Y-%m-%d %H:%M:%S) }) except Exception as e: print(f第 {page} 页抓取失败: {e}) time.sleep(random.uniform(1, 2)) # 随机延时避免请求过快被限流 return all_posts if __name__ __main__: posts fetch_guba_posts(sh600519, pages5, page_size50) with open(guba_posts.csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[code, title, read_count, comment_count, post_time]) writer.writeheader() writer.writerows(posts) print(f共抓取 {len(posts)} 条帖子已保存到 guba_posts.csv)这里有两个参数要重点说。pages控制在 5 页以内是因为股吧的帖子标题翻到后面基本是重复内容和广告帖多抓只会拉低文本质量time.sleep的随机范围设在 1 到 2 秒之间既不会触发频率限制也不会让整个采集过程慢到让人失去耐心。如果你要抓多只股票建议在for stock in stock_list的外层再加一层循环并且每换一只股票时睡眠时间拉长到 35 秒——换股票相当于切换接口参数东方财富对这类高频请求的监测会更敏感。另外抓下来的 CSV 用utf-8-sig编码保存这样用 Excel 打开时不会出现中文乱码这个细节在答辩演示时很加分。3. 情感打分与交易信号从舆情分数到可验证的量化输入3.1 情感分析选型为什么我用词典法而不是SnowNLP情感分析这个环节新手最容易踩的坑是一上来就上SnowNLP或者BERT追求“AI感”。我建议大作业场景先用基于情感词典的规则方法把系统跑通再考虑升级。原因很现实SnowNLP 默认模型是在电商评论语料上训练的对股吧里“主力出货”“抄底”“梭哈”这类股市黑话识别能力极差几乎所有句子都会被打成中性你会在答辩现场看到情绪曲线是一条直线场面很难收。词典法的思路是先准备一份带情感分值的中文情感词典然后把分词后的文本逐词查表累加正负分值得到句子情感倾向。清华大学的《情感分析用中文褒贬词典》Tsinghua Sentiment Dictionary和知网的情感词典是常用资源但股市场景我一般会额外加一个stock_sentiment_dict.csv自定义词表把“涨停”“牛股”“吃肉”算作强正项把“跌停”“套牢”“割肉”“退市”算作强负项权重设为 ±2比通用词的 ±1 更重。这样处理的好处是你完全清楚每个分数是怎么算出来的答辩时评委问“为什么这条评论打了 2 分”你能直接翻词典给出解释这是黑匣子模型做不到的。3.2 舆情分数折算当日情绪分、滑动均值与异动判定拿到单条评论的情感分后下一步是聚合成日级别的情绪指标。我用的公式很简单当日情绪分 当日所有评论情感分的平均值取值范围在 -2 到 2 之间然后再算一个 5 日滑动均值作为情绪趋势线。为什么非要做滑动均值因为单日的情绪分像心电图一样剧烈跳动某一天有几条极端看空发言会把整个分数拉成负值但整体趋势并不悲观。做一次平滑信号才具备参考性。当情绪异动出现时是系统最值得记录的时刻。我定义了两种异动模式一是当日情绪分超过过去 5 日均值 1 个标准差二是情绪分连续 3 天与股价涨跌方向相反。这第二种也就是所谓的“情绪背离”比如股价在跌但股吧情绪分在抬升通常说明散户开始惜售或准备抄底是一个值得关注的潜在反转信号。把这两个异动事件输出成事件日志在后面的回测里会反复用到。还有一个小细节评论数也需要纳入统计。某天只有三条评论平均分再极端也不具备统计意义。我会设置一个最低样本阈值比如当日评论数少于 10 条时该日情绪分直接标记为NaN在信号计算时跳过防止单日噪声生成假信号。界面上可以把这个情况标注为“舆情样本不足”比直接不显示更有说服力。3.3 叠加技术指标生成交易信号RSI、均线背离与情绪过滤舆情分数本身不能直接拿来买卖还需要和技术指标做交叉验证。我的做法是叠加两个指标5 日均线和 RSI(14)。均线负责判断大方向——股价在 5 日均线上方时只允许出现买入信号下方时只允许出现卖出信号这是最基础的过滤器RSI 负责判断超买超卖——RSI 低于 30 且舆情分数上穿 0 时给出买入信号高于 70 且舆情分数跌破 0 时给出卖出信号。信号生成的完整逻辑写在一个generate_signal.py文件里核心代码结构如下import pandas as pd def generate_signals(price_df, sentiment_df): price_df: 包含 close, rsi, ma5 的行情DataFrame sentiment_df: 包含 sentiment_score 的舆情DataFrame 返回新增 signal 列的合并DataFrame df price_df.merge(sentiment_df, left_indexTrue, right_indexTrue, howouter) # 1. 信号初始化为 00持有, 1买入, -1卖出 df.loc[df[rsi] 30, signal_temp] 1 # 超卖区间准备买入 df.loc[df[rsi] 70, signal_temp] -1 # 超买区间准备卖出 # 2. 用舆情分数过滤信号分数上穿0才允许买入跌破0才允许卖出 df[signal] 0 df.loc[(df[signal_temp] 1) (df[sentiment_score] 0), signal] 1 df.loc[(df[signal_temp] -1) (df[sentiment_score] 0), signal] -1 # 3. 均线方向过滤只保留顺势信号 df[ma5] df[close].rolling(window5).mean() df.loc[(df[signal] 1) (df[close] df[ma5]), signal] 0 df.loc[(df[signal] -1) (df[close] df[ma5]), signal] 0 # 4. 去掉信号重复出现的日子只保留信号值变化的那一天 df[signal_shift] df[signal].shift(1).fillna(0) df.loc[(df[signal] df[signal_shift]), signal] 0 return df[[close, ma5, rsi, sentiment_score, signal]]这段代码里最容易被忽略的是第 4 步的去重处理。如果没有这一步RSI 连续 5 天低于 30 时系统会连续 5 天生成买入信号回测时会被重复开仓导致收益虚高。去重之后整个回测期间每个方向只会出现一次信号逻辑更接近真实交易决策。fillna(0)的作用是处理shift产生的首行空值否则第一个信号会被误判为“信号变化”而保留。4. 系统源码结构与运行指南拿到大作业直接跑通的路径4.1 项目文件结构每个py文件在做什么一份能拿高分的大作业源码文件结构必须让人一眼看懂。我通常把系统拆成六个模块crawler.py负责舆情采集cleaner.py负责文本清洗sentiment.py负责情感打分indicator.py负责行情指标计算signal.py负责信号生成main.py负责串联整个流程。数据文件单独放在data/目录下结果输出到output/目录日志统一打到log/。这个结构本身也是答辩评分的一部分说明你有工程化意识。main.py的工作流按照“采集 → 清洗 → 打分 → 取行情 → 算指标 → 生成信号 → 可视化”的顺序执行。为了方便直接演示效果我一般会在main.py里写两种运行模式--crawl参数控制是否重新抓数据不加这个参数时直接读取已有的 CSV 数据这样答辩现场就不怕网络出问题导致整个流程断掉。在main.py顶部用argparse接收参数是一个很实用的小技巧。4.2 行情数据获取用 akshare 拉K线与技术指标行情数据绝对不要自己写爬虫去抓直接用akshare这个开源库是最稳的。它是目前Python生态里免费行情接口里做得比较完整的库支持A股、港股、美股日线数据关键是不需要注册token直接pip install akshare就能用。我常用的接口是stock_zh_a_hist返回的是带日期索引的日线DataFrame正好可以直接拿来算均线和RSI。用akshare的时候要注意两个点第一接口偶尔会因为上游数据源波动而返回空值代码里要做异常处理空数据时直接跳过这一天或者重新请求一次第二stock_zh_a_hist默认返回“前复权”数据做信号回测时复权方式要保持一致不然除权除息日附近的信号会失真。我一般会设置参数adjustqfq前复权它能让历史价格和当前价格保持连续回测更贴近真实买卖。4.3 可视化与结果输出图表怎么做才像“高分大作业”可视化是打分最快的地方——答辩老师看不懂你代码多优雅但一眼就能看出图表是否专业。我建议做三张图第一张是K线图叠加买卖信号标记第二张是舆情情绪分曲线与涨跌幅的对比图第三张是资金曲线回测图。绘图库用pyecharts它生成的HTML交互图表可以缩放、悬停查看数值比matplotlib的静态图直观太多而且在答辩投影上展示效果也更好。绘制K线图时我踩过一个坑pyecharts的Kline组件要求数据格式是[open, close, low, high]不是常见的[open, close, low, high]顺序写错的话K线图会完全错乱。解决方法是看官方示例把列顺序调整好再传给add方法。还有一个小技巧买卖信号用Scatter图层叠加到K线图上买入标红点、卖出标绿点一眼就能看出信号分布是否合理。如果信号太多太密说明指标参数过于敏感回测时反而不好看此时应该调大RSI阈值或增加情绪分的过滤强度。5. 大作业实战避坑清单舆情分析与股票信号最容易翻车的 5 个场景5.1 爬虫频繁被限流明明代码没问题抓几页就被封IP现象抓取前两页正常第三页开始返回空数据或者直接超时程序卡住不动。这个问题几乎每个做采集的大作业都会遇到属于最常见的翻车现场。原因请求频率过高或者缺少必要的请求头。东方财富的接口虽然没有强验证码但同一IP短时间内的请求次数有隐式限制尤其是不带Referer的请求特征太明显。解决请求头必须带Referer指向股吧域名请求之间随机睡眠 13 秒。如果还是被限尝试降低pagesize到 20并增大翻页间隔。我给学生的建议是数据量够用就好别追求抓全做分析只需要最近几天的数据抓太多反而做了无用功。5.2 情感分析结果全偏向中性换哪种模型都没用现象跑完情感分析发现 90% 的评论情感分都在 -0.1 到 0.1 之间情绪曲线看不出任何波动整个系统像坏了一样。原因先用错模型再用错词典。SnowNLP 对股市语料的识别力弱几乎所有句子都往中性靠而通用情感词典里缺少股市黑话“主力”“洗盘”“接飞刀”这些词在通用词典里根本查不到等于没做情感分析。解决换词典法并构建一个至少 50 条词的股票专属情感词表。把“拉升”“涨停”“吃肉”作为强正面词分值 2把“跌停”“套牢”“割肉”“退市”作为强负面词分值 -2。这步做完情感分数的方差会立刻变大情绪曲线开始有能看的波动。5.3 回测收益很高但实盘就亏信号全是“马后炮”现象回测资金曲线非常漂亮年化收益超过 50%但用小资金实盘试跑两周交易结果和回测严重不符。原因回测里用了未来数据。最常见的两个错误一是用当天的舆情分数和当天的收盘价生成信号然后计算当天的收益——这在现实中做不到因为收盘价出来之前你根本不知道能不能成交二是信号生成后没有做次日开盘价交易假设而是用了当天收盘价逻辑上自相矛盾。解决信号必须滞后一天。用第 T 天的舆情和行情数据生成信号后实际交易价用第 T1 天的开盘价并且把第 T1 天的涨跌幅记为本次交易的收益。在generate_signals里把信号列做一次shift(1)就能彻底消除未来函数的问题。这一步是大作业里最容易被扣分的点做对了回测的收益率才经得起追问。5.4 程序跑完没有把结果存下来答辩演示时拿不出干货现象程序运行结束后只在控制台打印了几行文字图表和统计结果都没有保存到本地。等到答辩现场系统运行时间太长没等结果或者网络波动导致数据抓取失败整场展示直接翻车。原因选手只关注代码逻辑没考虑交付。大作业的成果不是代码跑通的那一刻而是你手里有可展示的数据产物。解决在每个模块的出口都加保存逻辑。舆情采集存 CSV情感分析结果存 CSV最终信号和回测指标存 Excel 或 CSV图表存为 HTML 文件。答辩前把所有产出一口气运行出来用已有文件做展示网络环境不好时直接打开本地文件稳得很。5.5 代码换一台电脑就跑不起来环境问题毁掉现场演示现象在实验室电脑上运行正常的代码拿到教室演示时直接报ModuleNotFoundError或ImportError同学围观下场面十分尴尬。原因Python 环境不干净。项目依赖了requests、pandas、jieba、akshare、pyecharts等库但没做依赖锁定和版本约束换机器后装的库版本不一致或者干脆没装。解决项目根目录放一个requirements.txt把依赖库和版本号固定住比如pandas1.5.0,2.0.0。演示前先在新环境里跑一次pip install -r requirements.txt花两分钟验证环境可用性。另一个技巧是运行时统一用python main.py而不是依赖 IDE 的运行按钮确保命令行环境下代码也能正常工作。6. 三个进阶技巧让系统从“交作业”升级到“能说明白”第一个技巧是给系统加一个“相关性验证”模块。把每日情绪分和次日涨跌幅做pearsonr相关性检验输出相关系数和 P 值。哪怕结果相关性不高也没关系你可以诚实地说“短期相关性弱但情绪异动日后的 3 日累计收益有明显分化”这句话本身就是一个有价值的结论比硬吹系统赚钱可信得多。第二个技巧是做参数敏感性测试。把 RSI 阈值在 25/30/35 之间切换把情绪分过滤条件从“大于 0”改成“大于 0.2”分别跑回测对比信号数量和最终收益。结果用一张对比表格呈现告诉评委“参数在合理范围内波动时系统不会剧烈失效”这能证明你的系统不是调参凑出来的而是有鲁棒性的。第三个技巧是构建一个简单的“错误样本收集”机制。在情感分析模块里把模型打分与人工标注不一致的评论单独存到一个error_cases.csv文件里。答辩时展示这个文件说明你清楚系统的边界在哪并且有改进路径——这种“知道自己哪里不行”的坦诚反而比假装完美更让人信服。这套系统做完之后我自己的一个习惯是每次运行完先去看情绪异动日的事件日志再对比K线图上的信号位置。如果某个买入信号出现后三天内没有一根阳线我会回头检查是情感词典漏了词还是 RSI 和舆情过滤的优先级处理出了问题。做这类大作业最有价值的不是模型多高级而是你手里有一套能解释、能修改、能复现的完整链路。希望这套方案能帮你把作业做扎实答辩时也能多一份底气。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑