ARTICLE DETAIL

资讯详情

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

Python微博热搜词云分析:从数据清洗到加权可视化

Python微博热搜词云分析:从数据清洗到加权可视化 简介本资源是一套面向Python数据采集与可视化初学者的微博热搜话题分析实践项目聚焦社交媒体舆情洞察场景解决从数据获取到词云生成的完整技术闭环问题。压缩包共7个Python脚本文件总大小仅11KB涵盖热搜爬取requests反爬处理、关键词清洗jieba分词停用词过滤、多时段词云图绘制wordcloudmatplotlib及热搜指数统计等核心功能模块代码结构清晰、注释充分适合作为NLP入门与Web数据抓取的轻量级练手案例。目前已有2205人学习下载读者可直接复用爬虫逻辑对接微博热搜接口快速生成动态词云图掌握文本预处理、频率统计与可视化呈现的关键步骤并通过多个‘头条热搜词云图’脚本理解时间维度对比分析的设计思路。1. 用 Python 快速解析微博热搜榜生成可交互词云不是做图而是挖语义信号“近期微博热搜话题榜词云分析.rar”这个标题背后不是一张静态图片的生成任务而是一套轻量级舆情信号捕获流程从原始热搜数据通常是 HTML 或 JSON 格式中精准提取话题文本、过滤广告/运营词、归一化实体如“王宝强”和“宝强”合并、计算加权频次考虑热度值、停留时长、上升趋势最后用可导出、可缩放、带悬停信息的 SVG 或 HTML 词云呈现。它面向的是运营岗快速复盘当日热点、内容编辑预判选题方向、市场人员监测竞品声量——不需要部署服务不依赖微博官方 API已限流单机 Python 脚本 本地数据文件即可闭环。关键不在“词云好看”而在“词频可信”热搜榜本身含噪声如“爆”“沸”标签、平台置顶词条、重复话题变体直接丢进jiebawordcloud会严重失真。本文就拆解这个.rar文件最可能封装的真实工作流解压 → 解析结构化数据 → 清洗 → 加权统计 → 可视化每一步都给出可验证的代码、参数依据和避坑点。2. 解压与数据结构识别先确认.rar里藏的是什么格式的热搜快照微博热搜榜数据源有明确规律网页端 DOM 结构稳定div classhot-list包裹a href/weibo?qxxx标签移动端 API 返回 JSON含realtime_list字段而导出的.rar压缩包通常包含三类典型内容——HTML 页面存档、JSON 格式抓取结果、或 CSV 表格列名常为rank,topic,hot_num,link。不能盲目解压后直接读取必须先探测数据形态否则后续清洗逻辑全错。2.1 用rarfile安全解压并检查文件列表import rarfile import os # 检查 rar 是否可用避免用户未装 unrar try: rf rarfile.RarFile(近期微博热搜话题榜词云分析.rar) file_list [f.filename for f in rf.filelist] print(压缩包内文件, file_list) # 输出示例[weibo_hot_20240520.html, README.md] except rarfile.RarCannotExec: print(系统未安装 unrar请执行sudo apt install unrarUbuntu或 brew install unrarmacOS) exit(1) except Exception as e: print(f解压失败{e}) exit(1)提示rarfile库本身不自带解压引擎依赖系统unrar命令。若报错RarCannotExec说明环境缺失底层工具需按提示安装。Windows 用户可下载UnRAR.exe放入 PATH或改用py7zr支持 rar但需额外处理编码。2.2 自动识别数据格式HTML / JSON / CSV 三路分支判断import json import pandas as pd from bs4 import BeautifulSoup def detect_data_format(filepath): 根据文件扩展名和内容特征判断数据类型 ext os.path.splitext(filepath)[1].lower() if ext in [.html, .htm]: with open(filepath, r, encodingutf-8) as f: content f.read(1000) # 读前1KB足够判断 if !DOCTYPE html in content or div classhot-list in content: return html elif ext .json: try: with open(filepath, r, encodingutf-8) as f: json.load(f) # 尝试加载不报错即为有效 JSON return json except (json.JSONDecodeError, UnicodeDecodeError): pass elif ext in [.csv, .txt]: try: df pd.read_csv(filepath, nrows5, encodingutf-8) # 检查是否含热搜典型字段 if any(col in df.columns for col in [topic, 热词, 关键词]) and hot_num in df.columns: return csv except Exception: pass return unknown # 示例对解压出的第一个数据文件做探测 sample_file rf.filelist[0].filename rf.extract(sample_file, path./temp/) detected_type detect_data_format(f./temp/{sample_file}) print(f检测到数据格式{detected_type}) # 输出html / json / csv / unknown2.2.1 HTML 格式解析定位a标签中的真实话题文本微博热搜 HTML 中话题链接a的href参数q后是 URL 编码的话题名text内容可能含“新”“爆”等角标需剥离with open(f./temp/{sample_file}, r, encodingutf-8) as f: soup BeautifulSoup(f, html.parser) topics [] for a_tag in soup.select(a[href*/weibo?q]): href a_tag.get(href, ) # 提取 q 后的值并解码 import urllib.parse topic urllib.parse.unquote(href.split(q)[1].split()[0]) # 清洗移除【】括号内运营标注、数字序号、emoji import re clean_topic re.sub(r[【】\d\s\U0001F300-\U0001F64F\U0001F680-\U0001F6FF], , topic).strip() if clean_topic: # 非空才加入 topics.append(clean_topic) print(提取的原始话题前5, topics[:5]) # 输出示例[华为Pura70发布会, 高考作文题, 端午节放假安排, 特斯拉股价大跌, 周杰伦演唱会门票]2.2.2 JSON 格式解析直取realtime_list中的word和num微博官方 API 返回 JSON 中热搜条目通常在data.realtime_list数组每个元素含word话题词、num热度值、icon_desc标签with open(f./temp/{sample_file}, r, encodingutf-8) as f: data json.load(f) # 兼容不同 JSON 结构尝试多级路径 topics [] for item in data.get(data, {}).get(realtime_list, []) or \ data.get(realtime_list, []) or \ data.get(data, []): word item.get(word) or item.get(topic) or item.get(keyword) num item.get(num) or item.get(hot_num) or item.get(score, 0) if word and isinstance(num, (int, float)): topics.append({topic: word, hot_num: int(num)}) # 构建 DataFrame 便于后续加权 df pd.DataFrame(topics) print(JSON 解析结果热度降序\n, df.sort_values(hot_num, ascendingFalse).head(3))topichot_num端午节旅游攻略987654高考数学难度876543华为鸿蒙NEXT7654322.2.3 CSV 格式解析强制指定列名并校验数据完整性若检测为 CSV但列名混乱如标题,热度,链接需映射为标准字段df pd.read_csv(f./temp/{sample_file}, encodingutf-8) # 定义列名映射表覆盖常见中文/英文别名 col_mapping { topic: [标题, 话题, 热词, 关键词, word], hot_num: [热度, hot_num, num, score, 搜索指数], link: [链接, url, href] } standard_df pd.DataFrame() for std_col, possible_names in col_mapping.items(): for name in possible_names: if name in df.columns: standard_df[std_col] df[name] break else: if std_col hot_num: standard_df[std_col] 1000 # 默认热度后续需人工校准 else: standard_df[std_col] # 过滤空话题 standard_df standard_df[standard_df[topic].str.strip() ! ].copy() print(CSV 标准化后行数, len(standard_df))3. 热搜话题清洗与加权为什么“苹果”不能和“苹果手机”一起计数直接统计词频会淹没关键信号热搜中“苹果”可能指水果、公司、手机品牌“华为”和“华为Mate60”应归并“爆”“沸”标签需剔除平台置顶词条如“微博之夜”应降权。清洗不是删词而是构建语义层级——用规则词典简单 NLP 实现低成本归一。3.1 基础清洗移除干扰符号、统一空格、过滤无效词import re def basic_clean(topic): 基础清洗去噪、标准化 # 移除【新】【爆】【沸】等角标 topic re.sub(r【[^】]】, , topic) # 移除末尾数字序号如“罗永浩 1”→“罗永浩” topic re.sub(r\s\d$, , topic) # 合并连续空格去首尾空格 topic re.sub(r\s, , topic).strip() # 过滤纯数字、单字、过短词2字符 if len(topic) 2 or topic.isdigit(): return None return topic # 应用清洗 cleaned_topics [basic_clean(t) for t in topics if basic_clean(t)] print(清洗后话题数, len(cleaned_topics)) print(清洗示例, cleaned_topics[:3]) # [华为Pura70发布会, 高考作文题, 端午节放假安排]3.2 实体归并用前缀匹配合并长尾词无需训练模型热搜中高频出现“华为”“华为手机”“华为Mate70”——它们应归为同一实体。采用前缀树Trie思想按长度倒序排序后匹配def merge_by_prefix(topics, min_ratio0.6): 归并前缀词若A是B的前缀且len(A)/len(B) min_ratio则B归并到A 例如华为 是 华为Mate70 的前缀且 2/6 0.6 → 归并 # 按长度降序排列确保长词先被处理 sorted_topics sorted(set(topics), keylen, reverseTrue) merged {} for long_topic in sorted_topics: found_base False for base in merged.keys(): if long_topic.startswith(base) and len(base)/len(long_topic) min_ratio: merged[base] 1 found_base True break if not found_base: merged[long_topic] 1 return merged # 示例对清洗后的 topics 归并 merged_dict merge_by_prefix(cleaned_topics) print(归并后实体频次 top5, sorted(merged_dict.items(), keylambda x: x[1], reverseTrue)[:5]) # 输出[(华为, 3), (高考, 2), (端午节, 2), (特斯拉, 1), (周杰伦, 1)]3.3 热度加权融合排名、热度值、停留时长三维度仅用hot_num会忽略位置效应——第1名和第50名热度值可能接近但传播力差异巨大。引入加权公式最终权重 hot_num × rank_decay × duration_factor其中rank_decay 1 / log2(rank 1)模拟注意力衰减duration_factor来自历史数据若提供“连续上榜天数”字段则乘以该值否则默认为1import numpy as np # 假设 df 已含 topic, hot_num 列且按排名顺序index0 是第1名 df[rank] df.index 1 df[rank_decay] 1 / np.log2(df[rank] 1) df[duration_factor] df.get(days_on_list, 1) # 若无此列则用1 df[final_weight] df[hot_num] * df[rank_decay] * df[duration_factor] # 归一化到 0-100 区间便于词云渲染 df[weight_norm] ((df[final_weight] - df[final_weight].min()) / (df[final_weight].max() - df[final_weight].min() 1e-8)) * 100 print(加权后数据含归一化权重\n, df[[topic, hot_num, rank, final_weight, weight_norm]].head())topichot_numrankfinal_weightweight_norm华为Pura70发布会9876541987654.0100.0高考作文题8765432619812.562.8端午节放假安排7654323482101.248.84. 生成高信息密度词云支持悬停查看热度、导出 SVG、规避字体缺失wordcloud库默认输出 PNG无法交互、缩放失真、中文显示常乱码。改用pyecharts生成 HTML 词云或d3py输出 SVG——本文选择pyecharts因其零配置支持中文、内置热度悬停、一键导出 SVG/PNG/HTML4.1 安装与基础配置解决中文字体和渲染后端问题pip install pyecharts2.0.4 # 固定版本避免新版 breaking change # 下载思源黑体免费可商用并指定路径 wget https://github.com/adobe-fonts/source-han-sans/raw/release/SubsetOTF/SOURCEHANSANS-REGULAR.TTFfrom pyecharts import options as opts from pyecharts.charts import WordCloud from pyecharts.render import make_snapshot from snapshot_selenium import snapshot # 设置全局字体关键否则中文显示方块 import os os.environ[PYECHARTS_FONT_PATH] ./SOURCEHANSANS-REGULAR.TTF # 构造词云数据[(topic, weight), ...] word_weights [(row[topic], round(row[weight_norm], 1)) for _, row in df.iterrows()] # 创建词云图 wc ( WordCloud() .add(, word_weights, word_size_range[12, 60], # 字体大小范围避免小词不可读 shapecircle, # 可选 circle,cardioid,diamond width100%, height600px) .set_global_opts( title_optsopts.TitleOpts(title微博热搜话题词云加权热度), tooltip_optsopts.TooltipOpts(is_showTrue, formatter{b}: {c}分), # 悬停显示 legend_optsopts.LegendOpts(is_showFalse) ) )4.2 导出为 SVG保留矢量清晰度支持浏览器缩放# 渲染为 HTML可直接打开 wc.render(weibo_hot_wordcloud.html) # 导出为 SVG需安装 selenium chromedriver try: from pyecharts.render import make_snapshot from snapshot_selenium import snapshot make_snapshot(snapshot, wc.render(), weibo_hot_wordcloud.svg) print(✅ SVG 导出成功weibo_hot_wordcloud.svg双击用浏览器打开无限缩放) except ImportError: print(⚠️ selenium 未安装跳过 SVG 导出。可手动打开 HTML 文件截图。) print( 安装命令pip install selenium 下载 chromedriver 匹配 Chrome 版本)4.3 关键参数调优表解决词云常见失真问题参数作用推荐值失效场景word_size_range[12, 60]控制最小/最大字体[10, 70]小词看不清大词挤出画布shapecircle词云形状cardioid心形更紧凑star会导致边缘词截断mask_imageNone蒙版图像传入 numpy array 二值图PNG 蒙版需 alpha 通道否则白底失效rotation_step45旋转角度步长30减少重叠设为0强制水平牺牲多样性font_path./SOURCEHANSANS-REGULAR.TTF中文字体路径绝对路径勿用相对路径字体文件不存在时显示方块注意mask_image若启用需确保蒙版为灰度图且背景为黑色值为0、前景为白色值为255否则词云会填充到错误区域。调试时先设mask_imageNone确认基础效果。5. 验证词云可信度用三个命令快速交叉检验数据质量生成词云只是终点验证才是专业分水岭。不靠肉眼用三条 Shell/Python 命令完成数据可信度快检——覆盖完整性、一致性、合理性。5.1 检查原始数据完整性确认无空话题、无重复行# 统计原始 CSV/JSON 中空话题行数Linux/macOS awk -F, {if($1 ~ /^ *$/ || $1 ~ /^ *$/) print NR} weibo_hot.csv | wc -l # 输出 0 表示无空话题 # 检查重复话题忽略大小写和空格 awk -F, {gsub(/^[ \t]|[ \t]$/, , $1); print tolower($1)} weibo_hot.csv | sort | uniq -d | wc -l # 输出 0 表示无重复5.2 验证加权逻辑一致性用 Pandas 一行命令核对权重分布# 检查 weight_norm 是否严格在 [0,100] 区间 assert df[weight_norm].min() 0 and df[weight_norm].max() 100, 权重越界检查归一化公式 # 检查 top3 权重是否递减符合 rank_decay 逻辑 top3_weights df.nsmallest(3, rank)[weight_norm].tolist() assert top3_weights[0] top3_weights[1] top3_weights[2], 排名靠前但权重未更高rank_decay 失效 print(✅ 权重逻辑验证通过, top3_weights)5.3 人工抽样比对用head -n 5直接查看原始 vs 清洗后效果# 原始话题假设存于 raw_topics.txt每行一个 head -n 5 raw_topics.txt # 输出 # 【爆】华为Pura70发布会 # 高考作文题【新】 # 端午节放假安排 # 特斯拉股价大跌【沸】 # 周杰伦演唱会门票 # 清洗后话题cleaned_topics.txt head -n 5 cleaned_topics.txt # 输出 # 华为Pura70发布会 # 高考作文题 # 端午节放假安排 # 特斯拉股价大跌 # 周杰伦演唱会门票提示抽样比对必须人工执行——自动化无法替代对语义合理性的判断。重点看三点① 角标是否清除干净② “华为Pura70发布会”未被错误切分为“华为 Pura70 发布会”说明未用 jieba 分词正确③ “周杰伦演唱会门票”未被归并为“周杰伦”说明前缀归并阈值min_ratio0.6合理避免过度合并。词云不是终点而是起点。当weibo_hot_wordcloud.svg在浏览器中放大至 400% 仍清晰显示“华为Pura70发布会”时你已越过数据搬运工的门槛——下一步把weight_norm列接入告警脚本当“某竞品词”权重单日增幅超 200% 时自动钉钉通知这才是词云该有的生产力。本文还有配套的精品资源点击获取
返回列表