散户情绪不是玄学:Python 爬东方财富股吧并量化的方法
很多人一听到「散户情绪」就觉得是玄学仿佛只有盘面高手靠直觉才能感知。其实东方财富股吧里每天几百万条发帖就是最原始的散户情绪池子。帖子里有人喊「满仓干」有人骂「这票废了」有人发长长的复盘贴。把这些内容按条数抓下来再用一套简单的规则给每条打分散户情绪就能从感觉变成数字。举个真实的例子。某只票当天跌停股吧前排热帖大概率是一堆「割肉了」「被套牢」的抱怨这时候平均情绪分掉到负 0.6 以下很正常过两天出个利好公告热帖画风一转满屏「加仓」「看好反转」分数又能弹回正区间。你不需要读懂每一句只要把这种整体摆动量出来趋势就出来了。这篇文章就做两件事。第一用 Python 按你指定的条数精确抓取东方财富股吧的帖子抓满就停不浪费请求。第二用词典法给每条帖子算一个情绪分最后聚合成一个能看的情绪指标。代码里会带上类型注解、dataclass、日志记录和重试策略都是真正能跑的工程写法。先找到股吧的接口打开任意一只股票的股吧页面比如贵州茅台600519按 F12 打开开发者工具切到 Network 面板刷新页面筛选 XHR 请求。你会看到一个名为Get的接口大致长这样https://guba.eastmoney.com/api/Get?code600519page1page_size20sort0code是股票代码page是页码page_size是每页条数sort0表示按时间排序。返回的是一段 JSON帖子数组在list字段里每条包含post_id、post_content、post_publish_time、user_nickname等字段。拿到这个接口爬虫的骨头就出来了。有一点要提前说返回的post_content经常夹着 HTML 标签和图片占位符比如img src...、nbsp;之类。直接拿去打分会把噪声算进去。抓到内容后先做一次清洗把标签剥掉只留文字importredefclean_html(raw:str)-str:textre.sub(r[^],,raw)textre.sub(r[a-z];,,text)returntext.strip()清洗放在fetch_posts里塞进GubaPost.content之前这样后面所有环节拿到的都是纯文本情绪词典统计才准。还有个坑post_id在不同接口里有时是字符串有时是整数统一转成str能少踩不少 Equal 比较的坑。先把数据结构定好用 dataclass 把单条帖子框住后面无论是存盘还是打分都围绕这个结构转不至于在字典里乱翻 key。fromdataclassesimportdataclass,asdictfromtypingimportOptionaldataclassclassGubaPost:post_id:strstock_code:strnickname:strcontent:strpublish_time:strsentiment:float0.0defto_dict(self)-dict:returnasdict(self)sentiment字段先给个默认值 0.0等会儿打完分再回填。这样帖子模型和情绪计算解耦逻辑清楚。配置日志和代理爬取过程中如果不打日志出了问题你连哪页挂了都不知道。直接上标准库 logging别用一堆 print。importlogging logging.basicConfig(levellogging.INFO,format%(asctime)s [%(levelname)s] %(message)s,)loggerlogging.getLogger(guba_crawler)代理这块要单独说。股吧对高频访问不是完全没反应单 IP 猛抓几百页很容易被限流。做批量抓取时稳定的代理能省掉很多麻烦。我习惯用亿牛云的 HTTP 代理它走用户名密码鉴权代码里这样挂proxy_meta{host:http://proxy.16yun.cn,port:31000,user:你的亿牛云用户名,password:你的亿牛云密码,}proxy_urlfhttp://{proxy_meta[user]}:{proxy_meta[password]}{proxy_meta[host].split(//)[1]}:{proxy_meta[port]}proxies{http:proxy_url,https:proxy_url}把proxies透传给 requests 就行。亿牛云按量计费平时小规模抓几十页用不上真要跑几千条时它能把 IP 干净这件事兜住。抓之前还有个格式细节。东方财富的股票代码带市场前缀规则沪市主板是 60xxxx深市主板是 00xxxx创业板是 30xxxx科创板是 688xxx北交所是 8xxxxx。股吧接口认的就是这六位纯数字code前面不加 SH、SZ 那种前缀。要抓多只票把这些代码丢进一个列表循环调用fetch_posts即可每只票单独存一份 CSV后面拼表时按stock_code区分。按条数精准抓取核心需求是按条数抓而不是无脑翻到底。下面这个函数接收目标条数每翻一页把帖子累加够了就 break避免多抓浪费配额。每翻一页之间加一个随机间隔比固定 sleep 更像真人也能避免把请求节奏锤得太规律被识别。用random.uniform在 1 到 3 秒之间抖一下importrandomdeffetch_posts(stock_code:str,target_count:int,proxies:dict)-List[GubaPost]:posts:List[GubaPost][]page1page_size20whilelen(posts)target_count:params{code:stock_code,page:page,page_size:page_size,sort:0,}try:resprequests.get(BASE_URL,paramsparams,proxiesproxies,timeout10)resp.raise_for_status()itemsresp.json().get(list,[])exceptrequests.RequestExceptionasexc:logger.warning(第 %s 页抓取失败: %s,page,exc)breakifnotitems:logger.info(已经没有更多帖子第 %s 页为空,page)breakforiteminitems:iflen(posts)target_count:breakrawitem.get(post_content,)posts.append(GubaPost(post_idstr(item.get(post_id,)),stock_codestock_code,nicknameitem.get(user_nickname,),contentclean_html(raw),publish_timeitem.get(post_publish_time,),))logger.info(已抓取 %s/%s 条,len(posts),target_count)page1time.sleep(random.uniform(1,3))returnposts[:target_count]这里有个细节内层循环也判断了len(posts) target_count因为一页 20 条目标可能是 35 条第 2 页抓到 40 条时多出来的 5 条得切掉否则就超了。最后return posts[:target_count]再兜一层确保数量精确。另外注意content在入模前就过了clean_html前面说的标签噪声在这一步清掉后面打分拿到的全是纯文字。给请求加重试网络抖动、代理偶发超时都正常直接抛异常中断整个任务不划算。写个简单的重试装饰器失败就退避几秒再试。importtimefromfunctoolsimportwrapsfromtypingimportCallable,TypeVar TTypeVar(T)defretry(times:int3,delay:float2.0)-Callable:defdecorator(func:Callable[...,T])-Callable[...,T]:wraps(func)defwrapper(*args,**kwargs)-T:last_exc:ExceptionException(unknown error)forattemptinrange(1,times1):try:returnfunc(*args,**kwargs)exceptrequests.RequestExceptionasexc:last_excexc logger.warning(第 %s 次重试%s 秒后继续,attempt,delay)time.sleep(delay*attempt)raiselast_excreturnwrapperreturndecorator把retry()套到真正的请求函数上前一次示例里的requests.get单独抽出来即可。退避时间按delay * attempt递增避免瞬间疯狂重试把对面打毛。把情绪量化出来量化不一定要上深度学习。对股吧这种口语化、情绪浓的文本词典法又快又解释得清。先准备两份词表POS_WORDS[涨,利好,加仓,看好,抄底,拉升,反弹,盈利,赚,满仓]NEG_WORDS[跌,利空,割肉,看空,套牢,暴跌,亏损,雷,崩,清仓]defscore_sentiment(text:str)-float:possum(text.count(w)forwinPOS_WORDS)negsum(text.count(w)forwinNEG_WORDS)totalposnegiftotal0:return0.0returnround((pos-neg)/total,3)score_sentiment返回 -1 到 1 之间的数1 代表全是正面词负 1 代表全是负面词0 表示没命中任何词。用str.count而不是分词是为了轻量股吧帖子短、口语多逐字统计反而更稳。词典法有个绕不开的短板它认字不认语境。「不跌」「没利空」这种带否定的表达会被str.count当成正面算进去分数就飘了。帖子短、否定句占比不高整体指标不会被带偏太多但想更准可以加一层简单处理把内容按句号断句句子里同时出现否定词不、没、别和情绪词时把这条情绪词的权重翻负。改起来就几行NEG_MARKERS[不,没,别,无]defscore_sentiment_v2(text:str)-float:posneg0forsentinre.split(r[。\n],text):has_negany(minsentforminNEG_MARKERS)forwinPOS_WORDS:ifwinsent:pos-1ifhas_negelse1forwinNEG_WORDS:ifwinsent:neg-1ifhas_negelse1totalposnegiftotal0:return0.0returnround(pos/total,3)这么改之后「这不跌才怪」这种反讽还是会算错但那种属于人读都费劲的句子先放过它。工程上做到 80 分够用剩下的 20 分交给更大的语料和模型不在这篇文章的范围内。跑完抓取后回灌分数defenrich_sentiment(posts:List[GubaPost])-List[GubaPost]:forpostinposts:post.sentimentscore_sentiment(post.content)returnposts聚合成一个能看的指标单条分数没意义聚起来才有用。比如算平均情绪、正负帖占比再存成 CSV 方便后续画图或接进你自己的看板。importcsvfromstatisticsimportmeandefsummarize(posts:List[GubaPost],out_path:str)-dict:scores[p.sentimentforpinposts]avground(mean(scores),3)ifscoreselse0.0pos_ratioround(sum(1forsinscoresifs0)/len(scores),3)ifscoreselse0.0withopen(out_path,w,newline,encodingutf-8-sig)asf:writercsv.DictWriter(f,fieldnames[post_id,nickname,content,sentiment])writer.writeheader()forpinposts:writer.writerow(p.to_dict())logger.info(平均情绪分 %s正面帖占比 %s已存 %s,avg,pos_ratio,out_path)return{avg_sentiment:avg,pos_ratio:pos_ratio,count:len(posts)}utf-8-sig编码是为了让 Excel 直接打开中文不乱码这个坑踩过一次就记住了。avg_sentiment持续为正且走高说明散户整体偏乐观一直为负说明恐慌情绪在堆积。把这个值按天画折线你就能直观看到一只股票的情绪拐点比盯着单条帖子靠谱。把情绪分画出来CSV 躺在硬盘里还是数字画一张图才看得清走势。用 matplotlib 读 CSV按发布时间排序把每条帖子的sentiment点出来再叠一条当日均值线importcsvfromdatetimeimportdatetimeimportmatplotlib.pyplotaspltfrommatplotlib.datesimportdate2numdefplot_sentiment(csv_path:str)-None:times,scores[],[]withopen(csv_path,encodingutf-8-sig)asf:forrowincsv.DictReader(f):try:tdatetime.strptime(row[publish_time][:19],%Y-%m-%d %H:%M:%S)exceptValueError:continuetimes.append(date2num(t))scores.append(float(row[sentiment]))plt.scatter(times,scores,s12,alpha0.5,label单帖情绪)plt.axhline(sum(scores)/len(scores),colorred,label均值)plt.legend()plt.show()散点能看出当天情绪的离散程度点全挤在正值区说明一边倒看多点上下乱蹦说明多空分歧大这种日子往往对应放量震荡。均值红线往哪边偏就是当天散户的整体立场。把多天的数据按stock_code拼起来就能画出一只票的情绪曲线和 K 线叠在一起看常常比技术指标更早反映情绪拐点。把抓取定时跑起来单日快照只能看个截面情绪真正有价值的地方在变化。让脚本每天固定时间跑一次把当天的平均情绪分追加进同一张表时间一长就自然形成序列。不用上复杂调度框架一个无限循环加time.sleep就能先跑起来importtimefromdatetimeimportdatetimedefdaily_job(stock_code:str,target:int,out_csv:str)-None:whileTrue:postsfetch_posts(stock_code,target,proxies)postsenrich_sentiment(posts)summarysummarize(posts,out_csv)logger.info(%s 任务完成: %s,datetime.now().date(),summary)time.sleep(86400)正式环境建议交给系统的 cron 或任务计划程序比进程里死循环省心进程挂了也不会丢调度。跑之前记得把time.sleep的间隔、目标条数按你的代理配额定好别一觉醒来把当月流量吃完。为什么非要按条数抓最后回头说一句按条数这件事。很多人写爬虫习惯「抓到没有为止」对股吧这种信息流站点全量抓既没意义又烧代理。你做情绪面板每天同口径抓 200 条前后才可比今天抓 200 明天抓 5000两条均值摆在一起会自己骗自己。把target_count钉死等于给数据加了把尺子后面所有分析都站得住脚。几点实在的提醒抓取频率别太猛每页之间time.sleep一个一两秒的随机间隔配合代理基本不会被拦。词表建议按板块自己补比如新能源和白酒的「黑话」差很多通用词典打出来会偏。另外股吧数据只反映发言的那部分人沉默的大多数不在里面用它做参考可以拿来当买卖依据就过头了。这套流程跑通后你完全可以把多只股票并起来抓做成自己的散户情绪面板。代码量不大真正的工作量在后面维护词表和看数据但第一步把情绪变成数字事情就从玄学变成了可以聊的东西。

相关新闻

2026年河南公证办理官方渠道推荐:证天下小程序破解传统办理痛点

2026年河南公证办理官方渠道推荐:证天下小程序破解传统办理痛点

一、河南传统公证办理的普遍痛点长久以来,河南市民及企业办理各类公证业务,大多依赖线下公证处实体窗口办理。这种传统办理模式流程繁琐、限制较多,在实际办事过程中极易出现各类问题,耗费大量时间与精力,各类核心办事…

2026/7/30 8:29:30 阅读更多 →
单细胞测序发现“角化细胞在说什么”,PCF观察“谁在它身边”

单细胞测序发现“角化细胞在说什么”,PCF观察“谁在它身边”

单细胞测序最擅长捕捉细胞的表达语言:某类细胞上调了哪些基因,处于什么样的分化轨迹,可能通过哪些配体-受体通路与其他细胞沟通。但单细胞测序通常需要组织解离,细胞离开了原来的空间位置之后,我们虽然获得了“细胞在说…

2026/7/30 8:28:29 阅读更多 →
FigmaCN:3分钟让Figma变中文,设计师的翻译神器

FigmaCN:3分钟让Figma变中文,设计师的翻译神器

FigmaCN:3分钟让Figma变中文,设计师的翻译神器 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma的英文界面头疼吗?每天面对"Componen…

2026/7/30 8:28:29 阅读更多 →

最新新闻

英雄联盟智能助手完全指南:基于LCU API的数据查询与游戏辅助工具

英雄联盟智能助手完全指南:基于LCU API的数据查询与游戏辅助工具

英雄联盟智能助手完全指南:基于LCU API的数据查询与游戏辅助工具 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine Seraphine是一款基于英雄联盟官方LCU API开发的智能游戏助手,专为英雄…

2026/7/30 8:42:34 阅读更多 →
2026年深圳搬家首选:口碑载道的帮搬团队揭秘

2026年深圳搬家首选:口碑载道的帮搬团队揭秘

随着城市化进程的不断推进,越来越多的人选择在深圳这座繁华的城市安家落户。然而,搬家过程中的种种烦恼却让人头疼不已。今天,我们就来揭秘一家在深圳口碑极佳的搬家服务公司——深圳芝麻理想家家政服务有限公司(以下简称“深圳芝…

2026/7/30 8:42:34 阅读更多 →
【小白入门】一张项目结构图搞懂 SpringBoot 后端目录!每个文件夹到底干啥用?再也不懵!

【小白入门】一张项目结构图搞懂 SpringBoot 后端目录!每个文件夹到底干啥用?再也不懵!

文章目录前言一、先看整体项目树二、根目录文件逐个讲解1. pom.xml ⭐【整个项目最重要文件】2. target 文件夹 🚨【千万不要在这里写代码!】3. mvnw / mvnw.cmd4. .gitignore5. .idea三、src目录:后端开发主战场3.1 src/main/java 【Java代码…

2026/7/30 8:42:34 阅读更多 →
5分钟实现B站视频智能转录:bili2text技术架构与应用实践

5分钟实现B站视频智能转录:bili2text技术架构与应用实践

5分钟实现B站视频智能转录:bili2text技术架构与应用实践 【免费下载链接】bili2text Bilibili视频转文字,一步到位,输入链接即可使用 项目地址: https://gitcode.com/gh_mirrors/bi/bili2text bili2text是一个专为Bilibili视频设计的智…

2026/7/30 8:42:34 阅读更多 →
STM32-LOW POWER

STM32-LOW POWER

一、低功耗是什么低功耗的目标是降低集成电路的能量消耗。STM32 上电后默认处于运行模式。运行模式下,CPU、时钟系统、外设等模块正常工作,功耗相对较高。当内核不需要持续运行时,可以让芯片进入低功耗模式,以减少电流消耗。STM32…

2026/7/30 8:42:34 阅读更多 →
DownKyi:B站8K视频下载的终极解决方案与安全指南

DownKyi:B站8K视频下载的终极解决方案与安全指南

DownKyi:B站8K视频下载的终极解决方案与安全指南 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等&#xff09…

2026/7/30 8:41:33 阅读更多 →

日新闻

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您是否曾因Windows系统盘空间不足而烦恼?是否遇到过设…

2026/7/30 0:00:13 阅读更多 →
如何3步掌握Video Download Helper:网页视频下载的完整实战指南

如何3步掌握Video Download Helper:网页视频下载的完整实战指南

如何3步掌握Video Download Helper:网页视频下载的完整实战指南 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 你是否曾经在浏览…

2026/7/30 0:00:13 阅读更多 →
“双减”后首个AI备课压力测试报告:覆盖32所中小学的176节AI辅助课,暴露4大隐性增负节点

“双减”后首个AI备课压力测试报告:覆盖32所中小学的176节AI辅助课,暴露4大隐性增负节点

更多请点击: https://intelliparadigm.com 第一章:AI 教师备课辅助 AI 教师备课辅助系统正逐步成为教育数字化转型的核心支撑工具,它并非替代教师,而是通过语义理解、知识图谱与多模态生成能力,将教师从重复性劳动中解…

2026/7/30 0:00:13 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/29 22:18:20 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/29 15:00:03 阅读更多 →

月新闻