ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

微博舆情分析系统:爬虫+NLP+可视化全链路实践

微博舆情分析系统:爬虫+NLP+可视化全链路实践 简介本资源是一套面向高校大数据与Web开发初学者的完整微博舆情分析实战项目适用于课程设计、期末作业及NLP入门实践。项目基于Python与Flask框架构建覆盖微博数据爬取、清洗、存储、情感分析、可视化全流程融合爬虫工程、MySQL数据库操作、文本预处理、词云与折线图可视化等核心技能。压缩包共243个文件含52个Python源码如spiders/main.py爬虫主程序、model/yuqing.py舆情分析模块、23个CSV数据文件含commentsDataAll.csv等真实评论数据、21个HTML/JS/CSS前端页面支撑Flask Web界面展示以及SQL建库脚本和多张分析结果PNG/JPG图表整体大小30.25MB。已有95人学习下载提供开箱即用的完整环境配置说明、数据库初始化步骤、User-Agent与Cookie适配提示以及清晰的模块化目录结构便于理解系统分层逻辑与快速调试运行。1. 这不是个“爬完微博就出图”的玩具项目而是一套可落地的舆情分析闭环系统你可能试过用requestsBeautifulSoup抓几条微博评论再用jieba分词、TextBlob算个正负向——但真正跑通一个完整舆情分析流程会卡在至少三个地方微博反爬策略升级后 Cookie 失效、千万级评论导入 MySQL 时主键冲突或字符集报错、NLP 模型在 Flask 请求中加载耗时导致接口超时。这个期末作业项目恰恰把这三类坑都踩实了并给出了可复现的绕过路径它用 Selenium 模拟登录获取动态 Cookie而非静态抓包数据库建表时显式指定utf8mb4字符集和InnoDB引擎模型层将SnowNLP加载逻辑移至应用启动时缓存而非每次请求重建。项目结构清晰分层spiders → model → views → static所有模块通过config.py统一管理数据库连接与 NLP 参数适合高校课程设计复现也适合作为企业轻量级舆情监控原型快速迭代——只要你能接受它不依赖任何商业 API纯靠开源栈完成从数据采集到情感热力图渲染的全链路。2. 爬虫模块深度解析为什么必须用 Selenium 而非 requests微博自 2023 年起对/weibo/status/接口实施了更严格的 Referer 校验与动态 Token 验证仅靠requests构造 Headers 已无法稳定获取评论列表。本项目采用selenium ChromeDriver 实现真实浏览器环境模拟核心在于规避 JS 渲染拦截与行为指纹识别。2.1 登录态维持机制Cookie 与 User-Agent 的协同策略项目要求用户手动登录微博后提取 Cookie其本质是复用浏览器会话凭证。关键点在于Cookie 必须包含SUB、SUHB、ALF三项缺一不可其中SUB是长期有效的登录态标识User-Agent 需与当前 Chrome 版本严格匹配如Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36否则服务器返回 403禁用 headless 模式options.add_argument(--headless)会导致部分微博页面拒绝渲染必须保留 GUI 环境。# spiders/main.py 关键片段 from selenium import webdriver from selenium.webdriver.chrome.options import Options def init_driver(): options Options() options.add_argument(--no-sandbox) options.add_argument(--disable-dev-shm-usage) options.add_argument(--disable-gpu) # 注意此处不启用 headless options.add_argument(--user-data-dir/tmp/chrome_user_data) # 复用已登录配置 return webdriver.Chrome(optionsoptions) driver init_driver() driver.get(https://weibo.com/login.php) # 手动扫码登录后driver.cookies 即可被后续请求复用提示--user-data-dir参数指向本地 Chrome 用户数据目录Windows 路径为%LOCALAPPDATA%\Google\Chrome\User Data可避免重复登录。若需自动化登录需配合undetected-chromedriver替代原生 ChromeDriver但本项目未集成该方案以降低部署复杂度。2.2 评论爬取逻辑分页控制与防封策略微博评论接口返回 JSON 数据但每页仅限 20 条且存在滚动加载限制。项目采用「滚动到底部触发 AJAX 加载」「等待新 DOM 元素出现」的双重判断# spiders/main.py 中的 load_more_comments 函数 def load_more_comments(driver, max_pages5): for page in range(max_pages): # 滚动到底部触发加载 driver.execute_script(window.scrollTo(0, document.body.scrollHeight);) time.sleep(2) # 等待网络请求 # 检查是否出现“没有更多评论”提示 try: no_more driver.find_element(By.XPATH, //div[contains(text(), 没有更多评论)]) if no_more.is_displayed(): break except: pass # 提取当前页所有评论 comments driver.find_elements(By.CSS_SELECTOR, div[node-typecomment_list] div[node-typecomment]) for comment in comments: content comment.find_element(By.CSS_SELECTOR, div[node-typereply_text]).text.strip() user_name comment.find_element(By.CSS_SELECTOR, a[namenickName]).text yield {user: user_name, content: content}表爬虫参数配置表需在spiders/config.py中修改参数名默认值说明修改建议MAX_COMMENT_PAGES5单条微博最大爬取页数生产环境建议设为 3避免触发风控SLEEP_BETWEEN_REQUESTS3每次请求间隔秒数若 IP 被限频需提升至 8~10CHROME_DRIVER_PATHchromedriverChromeDriver 可执行文件路径Linux 下需chmod x chromedriverWEIBO_LOGIN_URLhttps://weibo.com/login.php微博登录入口 URL若域名变更需同步更新2.3 数据落库MySQL 字符集与主键设计避坑指南wb.sql文件中建表语句明确指定CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci这是支持 emoji 和生僻汉字的必要条件。若忽略此设置插入含 或 “” 字的评论时会报错Incorrect string value。-- doc/wb.sql 片段 CREATE TABLE comments ( id bigint(20) NOT NULL AUTO_INCREMENT, weibo_id varchar(32) NOT NULL COMMENT 微博ID, user_id varchar(32) NOT NULL COMMENT 用户ID, content text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_weibo_id (weibo_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;注意执行wb.sql前需确认 MySQL 服务已启用innodb_file_per_tableON否则大表导入时可能因 ibdata1 文件膨胀导致磁盘满。3. NLP 与舆情建模SnowNLP 情感分析的本地化适配项目未调用百度/阿里云等商业 NLP 接口而是基于SnowNLP实现轻量级中文情感分析。其优势在于无需网络请求、响应快但原始版本对微博短文本含表情、缩写、网络用语准确率偏低。本项目通过自定义词典与规则增强进行了针对性优化。3.1 情感词典扩展覆盖微博高频表达model/yuqing.py中加载了dict/sentiment_words.txt该文件包含 1276 条微博特有情感词例如正向词yyds,绝绝子,awsl,破防了负向词绷不住了,麻了,栓Q,退钱程度副词超,巨,贼,离谱用于放大情感极性# model/yuqing.py 片段 from snownlp import SnowNLP import jieba # 加载自定义词典 jieba.load_userdict(dict/sentiment_words.txt) def analyze_sentiment(text): # 移除微博常见干扰符号 clean_text re.sub(r[#。], , text) s SnowNLP(clean_text) # 基于 SnowNLP 原始得分做二次校准 base_score s.sentiments if base_score 0.7: return positive elif base_score 0.3: return negative else: return neutral表情感分析结果映射逻辑model/yuqing.pySnowNLP 原始得分区间项目判定标签触发条件示例文本[0.75, 1.0]positive含 ≥2 个正向词 程度副词“这个新品绝绝子超爱”[0.0, 0.25]negative含 ≥1 个负向词 感叹号 ≥2“绷不住了退钱”[0.25, 0.75]neutral无明确情感词或矛盾修饰“今天天气还行吧。”3.2 主题聚类TF-IDF KMeans 实现热点话题发现针对commentsDataAll.csv中的百万级评论项目采用sklearn.feature_extraction.text.TfidfVectorizer提取特征sklearn.cluster.KMeans进行无监督聚类最终输出前 5 大主题关键词# model/yuqing.py 中的 topic_cluster 函数 from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.cluster import KMeans import pandas as pd def topic_cluster(comments_df, n_clusters5): # 文本预处理去停用词、标点、数字 stop_words open(dict/stopwords.txt).read().splitlines() vectorizer TfidfVectorizer( max_features10000, stop_wordsstop_words, ngram_range(1, 2), # 支持二元词组如“苹果手机” min_df5, # 词频低于5次的忽略 max_df0.95 # 出现在95%文档中的词忽略 ) tfidf_matrix vectorizer.fit_transform(comments_df[content]) kmeans KMeans(n_clustersn_clusters, random_state42) labels kmeans.fit_predict(tfidf_matrix) # 提取每类关键词 order_centroids kmeans.cluster_centers_.argsort()[:, ::-1] terms vectorizer.get_feature_names_out() for i in range(n_clusters): print(fCluster {i}:) for ind in order_centroids[i, :10]: print(f {terms[ind]})提示n_clusters不宜设为固定值。实际部署时应结合silhouette_score自动选择最优聚类数代码中已预留calculate_optimal_k()函数占位但未启用——这是留给进阶用户的调优入口。4. Flask 后端与可视化集成如何让分析结果真正“活”起来Flask 应用并非简单返回 JSON而是构建了完整的 Web 交互界面首页展示实时情感分布饼图、评论热词云、话题聚类桑基图所有图表均通过ECharts渲染数据由/api/analysis接口按需提供。4.1 路由设计与数据流控制app.py中定义了三条核心路由/渲染templates/index.html初始化 ECharts 实例/api/analysis调用model/yuqing.py中的分析函数返回结构化 JSON/api/export生成 CSV 下载链接支持导出清洗后数据。# app.py 片段 app.route(/api/analysis) def get_analysis(): # 从数据库读取最新 10000 条评论 conn get_db_connection() df pd.read_sql(SELECT content FROM comments ORDER BY created_at DESC LIMIT 10000, conn) conn.close() # 执行情感分析与聚类 sentiment_result batch_sentiment_analysis(df[content].tolist()) topic_result topic_cluster(df) return jsonify({ sentiment: sentiment_result, topics: topic_result, total_comments: len(df) })4.2 前端图表联动ECharts 配置要点static/js/main.js中初始化饼图时关键参数如下// 初始化情感分布饼图 const chartDom document.getElementById(sentiment-pie); const myChart echarts.init(chartDom); myChart.setOption({ tooltip: { trigger: item }, legend: { top: 5%, left: center }, series: [{ type: pie, radius: [40%, 70%], avoidLabelOverlap: false, itemStyle: { borderRadius: 10, borderColor: #fff, borderWidth: 2 }, label: { show: false }, // 关闭默认标签用视觉编码替代 emphasis: { label: { show: true, fontSize: 16 } }, data: [ { value: positive_count, name: 正面, itemStyle: { color: #52c418 } }, { value: negative_count, name: 负面, itemStyle: { color: #f5222d } }, { value: neutral_count, name: 中性, itemStyle: { color: #faad14 } } ] }] });注意itemStyle.color直接绑定语义色绿色正面红色负面避免用户误解颜色含义radius设置为[40%, 70%]形成环形图比传统饼图更节省空间且利于移动端显示。4.3 数据导出功能CSV 生成与下载控制/api/export接口不直接返回文件而是生成带时效性的临时下载链接防止恶意刷取# app.py 片段 import tempfile import os app.route(/api/export) def export_data(): conn get_db_connection() df pd.read_sql(SELECT * FROM comments WHERE created_at DATE_SUB(NOW(), INTERVAL 7 DAY), conn) conn.close() # 生成临时文件 temp_dir tempfile.gettempdir() filename fweibo_export_{int(time.time())}.csv filepath os.path.join(temp_dir, filename) df.to_csv(filepath, indexFalse, encodingutf-8-sig) # utf-8-sig 兼容 Excel 中文 # 返回下载链接有效期 10 分钟 return jsonify({ download_url: f/download/{filename}, expires_in: 600 })/download/filename路由通过send_from_directory安全返回文件且检查filename是否存在于temp_dir中杜绝路径遍历攻击。5. 部署与性能调优让 Flask 在生产环境扛住并发请求本地开发用flask run即可但上线必须替换为gunicornnginx组合。本项目已预留gunicorn.conf.py配置文件关键参数需根据服务器资源调整。5.1 Gunicorn 启动参数实战配置gunicorn.conf.py中的核心设置# gunicorn.conf.py import multiprocessing bind 127.0.0.1:8000 bind_ssl None workers multiprocessing.cpu_count() * 2 1 worker_class sync worker_connections 1000 timeout 30 keepalive 2 max_requests 1000 max_requests_jitter 100 preload True # 预加载应用避免 worker fork 时重复加载模型workers设为CPU核心数×21是经验公式4 核服务器即设为 9preload True至关重要它确保SnowNLP模型在主进程加载一次子进程继承内存镜像避免每个 worker 重复初始化耗时 2~3 秒max_requests 1000防止内存泄漏累积worker 处理 1000 个请求后自动重启。5.2 MySQL 连接池优化避免“Too many connections”config.py中数据库配置启用了SQLAlchemy连接池SQLALCHEMY_DATABASE_URI mysqlpymysql://root:password127.0.0.1:3306/wb?charsetutf8mb4 SQLALCHEMY_POOL_SIZE 10 SQLALCHEMY_POOL_RECYCLE 3600 SQLALCHEMY_MAX_OVERFLOW 20POOL_SIZE 10保持 10 个空闲连接POOL_RECYCLE 3600连接存活 1 小时后强制回收防止 MySQLwait_timeout断连MAX_OVERFLOW 20瞬时并发超 10 时最多额外创建 20 个连接总上限 30。5.3 一个立竿见影的提速技巧NLP 模型缓存到 Redis若服务器已部署 Redis可将SnowNLP分析结果缓存 5 分钟大幅降低 CPU 占用# model/yuqing.py 新增缓存逻辑 import redis r redis.Redis(hostlocalhost, port6379, db0) def cached_sentiment(text): cache_key fsentiment:{hashlib.md5(text.encode()).hexdigest()} result r.get(cache_key) if result: return result.decode() score SnowNLP(text).sentiments label positive if score 0.7 else negative if score 0.3 else neutral r.setex(cache_key, 300, label) # 缓存 5 分钟 return label提示首次部署时需运行pip install redis并启动 Redis 服务。该技巧可使/api/analysis接口平均响应时间从 1.2s 降至 0.3s实测 1000 QPS 场景。本文还有配套的精品资源点击获取
返回列表