朋友让我帮忙分析张雪峰微博下面的公众反馈,我的方案很简单:先用Python爬虫把他公开发过的微博抓下来,再用AI情感分析给每条内容打分,最后用词云可视化把高频话题摆到一张图里。这里的张雪峰不是陌生人,就是那位长期聊高考志愿、考研规划和就业方向的教育博主,微博内容自带讨论度和对立情绪,拿来做文本分析样本再合适不过。
开始之前朋友问了一句:这活不是人工也能干吗?我说能干,但你翻不到两百条就想放弃,而且靠肉眼判断情绪比例很容易出现“看什么都像骂他”的主观偏差。今天这篇内容,我不打算只贴代码,还会把每个环节为什么这样处理讲清楚,包括接口选型、清洗逻辑、情感模型的选择依据和踩坑过程,希望能帮到正在学爬虫又不知道能做什么完整项目的朋友。
1. 为什么拿张雪峰微博当训练场:三类数据各有各的用途
这类项目最忌讳的事,就是吭哧吭哧把几千条微博抓下来,最后只生成一张谁都能拍脑袋画出来的图。既然花了时间写爬虫,就得让采集回来的每个字段都有出口。
1.1 微博正文是分析主料,但不是唯一主料
很多人一想到爬微博,脑子里只有“正文”。实际上正文只能回答“博主说了什么”,回答不了“网友为什么买账”。所以我采集时会连带保存发布时间、点赞数、评论数、转发数和微博ID,后几个字段在做内容分析时能帮上大忙。
我拿张雪峰的内容做实验时,发现一个特别明显的现象:单纯看正文字数,很多微博写得轻描淡写,但转发数忽然飙到几千。这时候如果只有正文,你根本不知道这条微博是引爆了什么话题。把互动数据带上以后,你可以很自然地把“高互动微博”单独筛出来,看看它和普通微博在情绪倾向上有没有差异。
1.2 技术选型没有新花样,组合起来才是练手重点
这个项目本质上就是把四样东西串成一条流水线:requests负责抓取,pandas负责清洗和聚合,SnowNLP负责情感打分,jieba加wordcloud负责词云输出。每一块单独拎出来都不算难,难的是它们在真实网页环境里会互相牵扯。
例如requests抓下来的内容带着一堆HTML标签和表情符号,这部分脏数据如果不处理,pandas清洗时会正常,但到了SnowNLP阶段可能直接拉低情感分析的准确率,最后进词云时又会冒出一堆“展开全文”和“网页链接”。所以每一步怎么处理上一步留下的坑,就是这项目真正的学习价值。
准备环境时我多说一句:如果你电脑上还没有Python,安装时记得勾选“Add python.exe to PATH”,否则命令行里敲python会提示找不到命令。装完以后执行pip install requests pandas snownlp jieba wordcloud matplotlib beautifulsoup4,基本就齐了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 微博公开微博抓取:我为什么绕开网页版而走移动端接口
写爬虫的第一步是搞清楚数据从哪来。很多新手上来就对微博网页版发起请求,然后用BeautifulSoup解析HTML,结果发现返回的内容要么是登录框,要么是验证码。我在这个项目里没走那条路,直接用了微博移动端的JSON接口。
2.1 网页版反爬强度高,移动端接口更“敞亮”
这里先说明一句:我抓的是账号公开发布的微博内容,而且请求频率压得很低,只用于个人学习演示。如果你想把数据拿去做商用产品,必须先评估授权问题,这是底线。
微博网页版之所以难爬,不是因为它用了多高级的加密,而是因为HTML结构里混入了大量动态模块。你以为你看到的是正文,实际渲染出来的DOM节点可能是前端二次请求后拼接的。相比之下,移动端m.weibo.cn有一套接口,直接返回结构化JSON,省去了大量解析工作。
2.2 第一步是拿到目标用户的containerid
先用手机浏览器打开张雪峰的微博主页,地址栏会显示一串纯数字UID,例如m.weibo.cn/u/后面跟的那串数字。每个微博用户都有自己独特的containerid,它决定了接口返回的是这个账号的哪一类内容。
我们可以先访问“type=uid”接口,让服务器根据UID返回第一版信息,其中会包含cardlistInfo.containerid字段。这个字段格式通常像“107603”加UID,拿到以后,后续翻页请求都要带上它。
python复制import requests
import time
import random
import re
from bs4 import BeautifulSoup
import pandas as pd
UID = "替换成你在m.weibo.cn/u/后面看到的数字"
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
"Referer": "https://m.weibo.cn/",
"X-Requested-With": "XMLHttpRequest"
})
BASE_URL = "https://m.weibo.cn/api/container/getIndex"
def get_first_container_and_cards(uid):
params = {"type": "uid", "value":
