
简介面向Python爬虫学习者和有微博数据采集需求的开发者这份资源围绕微博平台信息自动化获取这一核心场景系统梳理了网络请求库、HTML与JSON解析、模拟登录、反爬机制应对、数据持久化等关键知识点并给出了从配置、抓取到入库的完整工程思路。压缩包共包含18个文件主体为13个Python脚本分别承担微博转发、评论抓取、用户搜索、任务创建和数据库检索等功能配套3个Markdown说明文档用于解释各脚本用途、请求构造方式和爬取流程另含一个依赖清单txt文件和一个子压缩包便于安装依赖与查阅项目说明。整个压缩包仅90KB结构紧凑、代码量小非常适合逐行研读与二次开发。内容还涉及多线程、异常处理以及数据库交互等实用技巧可帮助使用者规避常见反爬限制。已有335人学习访问适合具备一定Python基础、希望进阶掌握爬虫工程化及微博数据获取技巧的开发者。1. 微博数据爬取先解决「拿到能分析的数据」这件事去年帮某公司做舆情分析运营给了 30 个微博用户 ID要求把微博正文、发布时间、转发评论点赞数全部导出来。我第一版脚本直接抓网页版 HTML存下来打开全是 JS 渲染后的半成品根本没法做分词。后来重构成了这个 Python 项目用 requests 调微博移动端 JSON 接口Cookie 维持登录态按用户主页游标翻页BeautifulSoup 清洗文本最后统一落成 CSV 和 JSON。适合需要批量采集微博文本做词频、情感分析、传播指标统计的开发者也适合想研究移动端接口分页和反爬策略的人。2. 架构与技术选型requests 同步抓取为主浏览器渲染只兜底2.1 移动端接口才是主路径先交代结论这个项目的核心数据源是 m.weibo.cn 那套 JSON 接口不是桌面版 HTML。原因很直接——网页版是服务端渲染加大量 JS 动态加载直接用 requests 拿回来的 HTML 里正文经常被截断评论区是异步加载翻页要分析一堆参数。移动端接口返回结构化 JSON每个用户主页围绕 cards 数组展开字段覆盖稳定解析成本低。我一开始也试着抓桌面版 HTML两周后彻底放弃。前端改版一次CSS 选择器就要重写一轮正文里的「展开全文」在 HTML 里是拆开的拼回去很容易漏字。移动端接口里 mblog.text 会把整条正文一次性给出来最多多一些 HTML 标签和表情占位清洗规则相对固定。如果你的采集量在百万条以内单机同步请求完全够用不需要一上来就上 Scrapy 分布式把请求频率控制好比引入一套调度框架更省事。我也测试过 Selenium 无头浏览器方案结论是只适合做兜底。浏览器渲染路径要等待各种资源加载500 条数据能跑十几分钟而且内存占用会随页面积累持续上涨。requests 版本同样数据量两分钟内完成差距在数量级上。这个项目里 Selenium 只出现在 login_helper.py 的扫码登录兜底中主体采集绝不走浏览器。2.2 目录结构与模块分工项目解压后是典型的「请求、解析、存储」三层结构weibo_crawler/ ├── config.py # 请求头、Cookie、目标用户ID、间隔秒数 ├── login_helper.py # 扫码登录辅助自动刷新Cookie ├── fetcher.py # 请求层发请求、重试、翻页 ├── parser.py # 解析层cards - 普通dict ├── storage.py # 存储层CSV / JSON 落盘 ├── main.py # 入口串起全流程打印进度 ├── requirements.txt └── output/ # 运行结果输出目录config.py 放所有会变的变量包括 User-Agent、Cookie 占位、目标用户 ID 列表、两页之间的延时。fetcher.py 只做一件事把请求拿回来状态码不对就重试JSON 解析失败就记录日志这一层不关心数据长什么样。parser.py 反过来只做字段提取不关心请求细节。storage.py 是最后一道工序统一处理编码和字段顺序。这样拆的核心原因是换数据源时不用四处打补丁。比如要把「按用户 ID 爬时间线」改成「按关键字爬搜索结果」只需要在 fetcher.py 里换 URL 和参数parser 和 storage 基本不用动。main.py 用 argparse 解析参数默认按 fetch - parse - save 的顺序执行每完成一个阶段打印一行进度日志方便排查哪一步出错。2.3 落盘格式CSV 给运营JSON 给分析项目默认写两个文件output/weibo_年月日_时分秒.csv 和同名 .json。CSV 用 utf-8-sig 编码直接用 Excel 打开不乱码JSON 保留原始字段方便后续接 jieba 分词或者情感分析模型。每行数据字段如下字段类型说明idstr微博ID可用来去重author_namestr作者昵称created_atstr发布时间原始格式text_cleanstr清洗后的纯文本reposts_countint转发数comments_countint评论数attitudes_countint点赞数字段顺序固定保证多次运行导出的 CSV 表头一致。如果要接数据库storage.py 里加一个 to_mysql 函数用 pandas 的 to_sql 三行就能写完df.to_sql(weibo_posts, engine, if_existsappend, indexFalse)。注意两点一是 created_at 建议先转成字符串再入库否则 pandas 会自动推断成 datetime 类型可能产生时区偏移二是 text_clean 要确认长度上限微博最长几万字数据库字段别设成 VARCHAR(255)。3. 核心链路拆解Cookie、游标翻页、HTML 清洗三段代码3.1 Cookie 登录与请求头装饰微博不登录能看数据但接口会明显限流翻几页就返回错误码。项目里登录态收敛在 config.py运行前手动从浏览器复制 Cookie 填入。请求头用移动端 iPhone UA配合 Referer 指向 m.weibo.cn# config.py WEIBO_HEADERS { User-Agent: ( Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49 ), Referer: https://m.weibo.cn/, X-Requested-With: XMLHttpRequest, } # 从浏览器登录后复制注意是 m.weibo.cn 域名下的 Cookie COOKIE SUBxxx; SUBPxxx; WBUBIxxx发请求时用字典展开把 Cookie 拼进去requests.get(url, headers{**WEIBO_HEADERS, Cookie: COOKIE})。这里的 COOKIE 叫什么名字不重要重要的是必须来自 m.weibo.cn 域。接口校验的是 Cookie 里 SUB 字段的签名和过期时间如果你复制的是 www.weibo.cn 的 Cookie请求头带过去了但接口不认返回的 ok 字段永远是 0这类问题排查起来挺费时间。Cookie 有效期从几小时到几天不等取决于账号活跃度。项目里的 login_helper.py 是备用方案请求二维码图片地址60 秒内用手机微博扫码轮询等待回调拿到新 Cookie 后自动写回 config.py。这个功能当时是被运营同学「帮我再导出一次」逼出来的因为手动复制一次要两分钟扫码自动化后每次采集前能省不少等待时间。3.2 时间线翻页since_id 才是真正的页码移动端接口的翻页不是 page1、page2 这种数字页码而是游标式设计每一页响应里带一个 since_id把这个值传给下一页服务端才知道「接着上次的位置继续给」。如果自己维护数字页码翻到第 5 页左右接口就开始返回空 cards数据直接断掉。核心请求代码如下# fetcher.py import requests import time def fetch_user_timeline(uid, container_id, since_id, max_pages100): results [] for _ in range(max_pages): params { type: uid, value: uid, containerid: container_id, since_id: since_id, } resp requests.get( https://m.weibo.cn/api/container/getIndex, paramsparams, headers{**WEIBO_HEADERS, Cookie: COOKIE}, timeout10, ) data resp.json() if data.get(ok) ! 1: break cards data[data][cards] if not cards: break results.extend(cards) since_id data[data].get(since_id, ) if not since_id: break time.sleep(1.5) # 防止请求过快被限流 return results参数里 container_id 是用户主页的分类容器 ID常见格式是 107603 加用户 ID 拼接而成比如 1076031234567890它决定了接口返回的是「全部微博」还是「某一分类」。since_id 首次为空字符串服务端返回第一页之后每轮把上一轮响应里的 since_id 回传形成游标。time.sleep(1.5) 是项目里默认的节流值如果只爬几百条改成 1 秒问题不大爬几万条建议调到 2 秒以上这是被风控教育出来的经验值。3.3 文本清洗与 CSV 落盘mblog.text 字段不是纯文本里面混着br /、a href/n/xxx用户名/a、span classurl-icon这类 HTML 片段以及表情图片的占位。直接用正则抠容易把 人和表情搞碎项目里用 BeautifulSoup 统一清洗# parser.py from bs4 import BeautifulSoup def clean_html(html_text): if not html_text: return soup BeautifulSoup(html_text, html.parser) return soup.get_text( , stripTrue) def parse_mblog(card): if card.get(card_type) ! 9: return None mblog card[mblog] return { id: mblog[id], author_name: mblog[user][screen_name], created_at: mblog[created_at], text_clean: clean_html(mblog[text]), reposts_count: mblog[reposts_count], comments_count: mblog[comments_count], attitudes_count: mblog[attitudes_count], }clean_html 里的 get_text( , stripTrue) 会把标签全部剥离标签之间的空白用单个空格拼接这样 人、话题词、正文之间不会粘连。card_type 的判断很关键用户时间线里每页 10 到 20 张卡片除了微博正文卡片card_type9还有「header」「推荐关注」这些杂项卡片不过滤掉会把脏数据带进 CSV。存储层用 pandas 的 DataFrame 直接落盘# storage.py import pandas as pd def save_csv(rows, path): df pd.DataFrame(rows) df.to_csv(path, indexFalse, encodingutf-8-sig)编码用 utf-8-sig 而不是 utf-8是因为 Excel 打开无 BOM 的 UTF-8 文件时默认按 GBK 解码中文会全部乱掉。utf-8-sig 会在文件头写入 BOM 标记Excel 识别正确编码这是爬虫项目里的老常识但每次新手接手都会翻一次车。4. 从 zip 到跑通安装依赖、配置 Cookie、验证数据4.1 环境准备与依赖安装项目不挑系统Windows、macOS、Linux 都能跑前提是 Python 版本 3.8 以上。解压后在项目根目录执行cd weibo_crawler python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txtrequirements.txt 里主要就是三样requests、beautifulsoup4、pandas。pandas 是本项目里最重的依赖如果不想为几万行数据装它也可以改成 csv 标准库自己写 writer但 pandas 的 to_sql 和 DataFrame 清洗在二次开发时太方便了我建议保留。安装时如果在墙内遇到超时比较顺手的方式是换 pip 镜像源比如 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt这个细节在实际部署时经常能省下十分钟。装完可以用 python -c import requests, bs4, pandas 验证三个包都能正常导入再进入下一步配置。4.2 配置 Cookie 和目标用户打开 config.py 做两件事。第一把 COOKIE 换成自己账号登录后的值打开 m.weibo.cn 页面登录后在浏览器开发者工具的 Application 面板里找到对应域名下的 Cookie整段复制出来填进去。第二把 USER_IDS 数组改成你要爬的用户数字 ID一个 ID 一行用逗号分隔。注意不要在隐私模式窗口里复制 Cookie那个窗口一旦关闭 Cookie 立即失效。取 Cookie 的浏览器标签页要保持登录状态直到采集跑完。如果嫌手动复制麻烦可以在登录状态下运行 python login_helper.py脚本会打印一个二维码图片路径用手机微博扫码后自动把新 Cookie 写回 config.py。这个辅助脚本不是主路径但适合要长期、多次采集的场景比自己反复打开开发者工具省事。4.3 入口参数与运行日志main.py 用 argparse 接收参数最常见的运行方式python main.py --users 1234567890 9876543210 --max-pages 30 --output output/这会按顺序爬两个用户的时间线每个用户最多翻 30 页结果输出到 output 目录。运行过程中会看到类似这样的进度日志[fetch] user1234567890 page1 got 12 cards, since_id2025011012 [fetch] user1234567890 page2 got 10 cards, since_id2025011009 [fetch] user9876543210 page1 got 0 cards, stopped [save] output/weibo_20250110_143022.csv (22 rows)日志里有两个关键信号got 后面的数字是本页实际拿到的卡片数stopped 表示接口返回了非 1 的 ok 值或者空 cards。遇到某个用户 0 cards 立即停是正常的说明这个用户设置了「仅展示半年内微博」或者当前 Cookie 对这个用户不可见不是脚本 bug。4.4 数据验证抽样对比最稳跑完之后别急着交付数据至少要验证三件事。第一CSV 行数跟网页端该用户的微博总数对得上第二随机抽 3 条微博去微博搜索页对比转发数和点赞数确认字段映射没有错位第三检查 text_clean 列有没有明显的乱码或空行。如果第三条有问题多半是清洗逻辑漏了某种卡片类型回 parser.py 调整 card_type 判断。验证这步我建议写进交付流程而不是靠肉眼扫。哪怕是给自己用把 CSV 读进来跑一遍合法性检查——id 是否重复、时间字段能否解析、三个 count 字段是否为正整数——也比事后拿着表格被运营追着问要舒服。5. 避坑记录微博采集最容易翻车的 5 个点5.1 第一页就返回 ok: 0提示需要登录现象运行 main.py 后第一条请求就失败日志里所有用户都是 got 0 cards或者返回的 JSON 里出现登录相关提示。原因Cookie 没填对或已过期。最常见的填错方式是复制了 www.weibo.cn 的 Cookie 而不是 m.weibo.cn 的移动端接口校验的是 m 域下的登录态签名。解决重新打开 m.weibo.cn 登录确认地址栏域名确实是 m.weibo.cn再从开发者工具里复制整段 Cookie。复制完先跑一个单用户单页的小命令验证python main.py --users 一个ID --max-pages 1通了再放量。5.2 翻到第 5 页就开始重复数据现象前面几页数据正常后面每页返回的微博 ID 跟第一页高度重合CSV 里全是重复 id。原因用了 page 参数自增翻页而移动端接口的翻页游标是 since_id。当接口不认 page 时它默认返回第一页表现就是继续翻页但内容重复。另一种情况是上一次的 since_id 在服务端已经查不到对应位置游标回退到了首页。解决严格使用响应体里的 data.since_id 作为下一页参数如果返回的 since_id 为空或与上一轮相同立即停止。采集完成后对 id 列做一次去重统计重复率超过 5% 就要回头检查游标逻辑。5.3 文本清洗后 人 和话题词是碎的现象text_clean 里「用户名」只剩一半话题#xxx#中间被插入空格有的行直接是空字符串。原因BeautifulSoup 的 get_text( , stripTrue) 用空拼接标签内文本但微博正文里 人 和话题的 HTML 是嵌套 span空格拼接位置恰好落在标签边界上导致词被切断。另外长微博处于「全文」模式时mblog 里有 isLongText 字段正文被拆在 text 和 longText 两个字段里只清洗 text 会丢内容。解决parser.py 里对 isLongText 为 1 的卡片改取 mblog.longText 再清洗清洗时先合并标签内文本再去多余空白。调试时可以随机挑 20 条文本打印断词位置再决定分隔策略。5.4 生成 CSV 后 Excel 打开全是乱码现象CSV 文件用 VS Code 看正常中文用 Excel 双击打开后变成不可读字符。原因默认编码用了 utf-8 但没有 BOMExcel 在简体中文系统下按 GBK 解码中文全部错位。这个坑在 macOS Numbers 下不明显但公司里用 Windows Excel 的人一开就炸。解决统一用 encodingutf-8-sig 写 CSV。如果已有历史文件不想重新爬用 pandas 读进来重新另存为 utf-8-sig 编码几秒钟处理完。以后每次交付 CSV 之前都确认一次文件头有没有 BOM 标记。5.5 请求频率一高整段 IP 被临时限制现象持续爬了十几分钟后请求开始返回 418 或 503过一会儿浏览器访问微博也提示异常。原因单 IP 请求频率太高服务端做了 IP 级别限流。每页 sleep 1 秒看起来不慢但加上解析和落盘时间请求密度仍然偏高多用户时间线连爬时最容易触发。解决把请求间隔提高到 2 到 3 秒每个用户之间额外休息 5 到 10 秒。重试逻辑放在 fetcher.py遇到 418 先 sleep 60 秒再重试一次再失败就跳过这个用户不要死磕。长任务每完成一个用户打印一次计数观察整体速度而不是盯着单页。6. 二次开发改成命令行参数化工具加断点续爬兜底想真正把这个项目当工具用第一件事是把用户 ID 从配置文件改成命令行多值参数再把输出目录、最大页数全部参数化这样才能交给定时任务反复调用。main.py 里大致这样扩展import argparse parser argparse.ArgumentParser() parser.add_argument(--users, nargs, requiredTrue) parser.add_argument(--max-pages, typeint, default50) parser.add_argument(--output-dir, defaultoutput) args parser.parse_args()第二件事是加断点续爬。for 循环里每成功翻完一页就把当前用户 ID 和 since_id 写进 checkpoint.json下次启动时检测到该用户的 checkpoint直接从上一次的 since_id 继续不用从头爬。增量采集同理每天定时跑一次只爬最近一天的新微博然后 append 到历史 CSV。这个能力对舆情监控几乎是刚需因为隔几天全量重爬转发评论数已经变了历史数据就不准了。验证修改是否可靠我的做法是跑一个用户最近两页数据先正常跑一遍再加 checkpoint 并在第一页后手动中断重新启动对比两次输出的 id 集合是否连续。若中间有缺失就检查 checkpoint 写入的时机是否在 break 之前。那天我把写入位置写错了重启后每次漏一页数据排查了半个小时才意识到是时机问题。从那以后我每次加状态恢复功能都强制先写一遍「中断再续跑」的验证用例。希望帮到你。本文还有配套的精品资源点击获取