尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Python微博数据爬取实战:从登录状态到JSON解析的完整工程
简介这是一份面向Python爬虫爱好者的微博数据抓取实战资源覆盖评论、转发、用户搜索三类典型采集任务既适合入门者理解爬虫原理也能为开发者提供可复用的代码范例。资源提供可直接运行的脚本以及项目说明和依赖清单从构造请求、解析返回数据、模拟登录到应对反爬机制均有代码示例。压缩包共18个文件以13个py脚本为主配合3个md文档梳理思路另附一个txt记录依赖库整体仅90KB轻量且易于迁移。资源按功能模块拆分例如评论采集、转发采集、用户搜索等适合边读代码边上手调试同时也可借助其中异步、代理、User-Agent配置等技巧理解常见的爬虫提速与封禁规避思路并兼顾了数据存储、异常处理和合规性提醒。目前已有335人学习下载对于刚接触网络数据采集、希望获得完整可运行案例的开发者是较为直接的参考资料。1. 用Python拿微博数据从一个真实抓取需求说起做数据分析的朋友常找我帮忙抓数据需求十有八九绕不开微博某品牌活动的舆情、某个热搜话题下的评论倾向、或者盯着某几个大V的动态做追踪。刚开始我用现成的第三方库翻车翻得相当狼狈——有的库改了签名有的被反爬策略盯上更常见的是返回的JSON字段和文档对不上。后来我把一套经过多次调优的爬取流程打包成了一个可以直接跑的Python项目也就是标题里这个Python微博数据爬取.zip。它不是一个花架子Demo而是能处理登录态、能解析复杂嵌套JSON、能应对基础反爬限制的完整工程。这个项目解决的核心问题很直接如何稳定地把微博网页端的数据结构变成干净的Excel或SQLite记录。它适合三类人需要批量拿公开数据进行课题研究的学生、做竞品或舆情分析的产品运营、以及想快速了解微博前端加密和请求签名机制的开发者。项目整体用requests库走HTTP请求配合必要的浏览器模拟登录做到了不开浏览器就能持续抓取。下面我会从技术选型讲到代码核心再到跑通它和二次改造按一线开发拆项目的顺序来。2. 技术栈与工程结构一个能落地的爬虫骨架2.1 为什么选requests而不是scrapy这个项目最初考虑过Scrapy框架但Scrapy的异步调度和中间件配置对新手来说是个黑匣子一旦出现微博反爬返回的异常页面排查链路会很深。而requests库上手快配合session对象维持登录态再用retry策略处理偶发失败足以支撑中小规模的数据抓取任务。微博网页端的接口虽然是动态渲染但很多数据其实藏在XHR请求里直接构造Ajax请求比渲染整个页面要轻量得多。项目里还有一个值得说道的设计数据抓取和数据处理分离。抓取模块只负责拿响应、校验状态码、解析字段处理模块负责清洗、去重、类型转换。这样做的好处是一旦微博改版导致某个字段缺失你只需要修改解析函数不用动存储逻辑。目录结构大概是这样weibo_spider/ ├── main.py # 入口文件调度各模块 ├── config.py # 所有配置参数集中地 ├── spider/ │ ├── login.py # 登录态管理二维码或Cookie注入 │ ├── fetcher.py # HTTP请求封装带重试和代理开关 │ └── parser.py # JSON与HTML解析字段抽取 ├── storage/ │ ├── excel_writer.py # 输出到Excel │ └── sqlite_writer.py # 输出到SQLite ├── utils/ │ └── logger.py # 统一日志输出 └── requirements.txt2.2 配置驱动一切config.py里的门道爬虫最忌讳把参数写死在代码里。这个项目的config.py集中管理了所有可变项目标用户的UID列表、抓取的时间范围、请求头的User-Agent池、每次请求的延时区间、以及是否启用代理。其中延时区间的设置是个关键细节——固定延时是最容易触发反爬的写法项目里用了random.randint(3, 7)这样的波动延时模拟真实操作节奏。# config.py 核心配置段 REQUEST_HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..., Referer: https://weibo.com/, Accept: application/json, text/plain, */*, } TIME_SLEEP_RANGE (3, 7) # 请求间隔秒数随机取值 MAX_RETRY 3 # 单次请求失败重试次数 PROXY_ENABLED False # 如需代理池置为True并配置代理列表 DB_PATH weibo_data.db # SQLite输出文件路径 EXCEL_PATH weibo_data.xlsx # Excel输出文件路径这里有三个参数对实际运行影响最大PROXY_ENABLED决定你是否走代理池很多办公网络直接连微博接口会被限制TIME_SLEEP_RANGE控制抓取频率调得太小容易被封MAX_RETRY则决定了网络抖动时任务能不能自愈。我一般会把重试逻辑写成指数退避第一次失败等2秒第二次等4秒第三次等8秒连续失败超过三次就写入日志并跳过当前目标。3. 核心模块拆解一个请求从进入到返回的完整链路3.1 登录态管理Cookie注入与二维码扫码的取舍微博的数据接口大部分需要登录Cookie特别是访问用户主页的完整微博列表。项目提供两种登录方式手动Cookie注入和二维码扫码。手动Cookie适合服务器环境——你从浏览器里复制Cookie粘贴到配置文件中二维码扫码适合本地开发机——程序调用系统浏览器展示二维码扫码后自动截取Cookie。# spider/login.py 中二维码登录的核心片段 import qrcode from selenium import webdriver def login_by_qrcode(): driver webdriver.Chrome() driver.get(https://passport.weibo.com/signin/login) # 等待页面加载出二维码图片元素 qr_img driver.find_element(css selector, img[src*qr_code]) qr_path qrcode.png qr_img.screenshot(qr_path) # 本地终端打印出二维码使用qrcode库从图片内容重新生成 qr_data driver.execute_script(return document.querySelector(img[class*code]).src) qr qrcode.QRCode() qr.add_data(qr_data) qr.print_ascii() # 轮询等待登录成功后的Cookie for _ in range(60): cookies driver.get_cookies() if any(c[name] SUB for c in cookies): return {c[name]: c[value] for c in cookies} time.sleep(2) raise TimeoutError(二维码登录超时)这段逻辑里值得说明的是二维码图片本身可以从页面元素截图获得但更稳妥的方式是直接读取图片的URL地址再转成终端可打印的ASCII码。SUB这个Cookie是微博登录态的核心凭证只要它没过期后续请求都能带上。如果你不想用selenium也可以手动登录后从浏览器开发者工具里复制Cookie放到config.py的COOKIE_STRING变量里。3.2 请求封装与JSON解析避开高频封禁的写法爬虫的命门在请求层。fetcher.py里对requests.Session做了一个薄封装统一处理超时、重试、异常捕获。一个常见坑是requests的get方法默认不会抛出异常而是把错误状态码放在resp.status_code里。如果忽略这一步后续解析拿到的就是空数据或登录跳转页。# spider/fetcher.py 请求重试与状态校验 import time import requests from config import REQUEST_HEADERS, MAX_RETRY, TIME_SLEEP_RANGE class Fetcher: def __init__(self, cookiesNone): self.session requests.Session() self.session.headers.update(REQUEST_HEADERS) if cookies: self.session.cookies.update(cookies) def get_json(self, url, paramsNone): for attempt in range(MAX_RETRY): try: resp self.session.get(url, paramsparams, timeout10) if resp.status_code 200: return resp.json() # 418或414说明被限流等待更长时间 if resp.status_code in (418, 414): time.sleep(30) except requests.RequestException as e: print(f第{attempt 1}次请求失败: {e}) time.sleep(TIME_SLEEP_RANGE[0] (TIME_SLEEP_RANGE[1] - TIME_SLEEP_RANGE[0]) * attempt) return None这里把418和414单独列出来是有原因的微博在识别到异常高频访问时不会直接返回403而是给一个418Im a teapot的玩笑状态码。如果你在日志里频繁看到这个状态码说明IP已经被标记光靠降速还不够。常见的做法是等一段时间或切换代理IP。解析层的核心是定位到微博接口返回的JSON结构。用户主页的时间线数据通常藏在data.list里每条微博有id、text_raw正文、created_at发布时间、reposts_count转发数等字段。需要特别注意的是created_at是刚刚、5分钟前这类相对时间项目里会统一转换成绝对时间戳。# spider/parser.py 微博字段提取与时间归一化 import re import datetime def parse_weibo_item(item): text_raw item.get(text_raw, ) or # 去除HTML标签和nbsp;等实体 clean_text re.sub(r[^], , text_raw).replace(nbsp;, ) # 相对时间转绝对时间 created_at item.get(created_at, ) if created_at.endswith(分钟前): minutes int(created_at.replace(分钟前, )) publish_time datetime.datetime.now() - datetime.timedelta(minutesminutes) elif created_at.endswith(小时前): hours int(created_at.replace(小时前, )) publish_time datetime.datetime.now() - datetime.timedelta(hourshours) else: # 形如2024-01-15 10:30的绝对时间 publish_time datetime.datetime.strptime(created_at, %Y-%m-%d %H:%M) return { weibo_id: item.get(id), content: clean_text, publish_time: publish_time.strftime(%Y-%m-%d %H:%M:%S), reposts: item.get(reposts_count), comments: item.get(comments_count), likes: item.get(attitudes_count), source: item.get(source, ), user_name: item.get(user, {}).get(screen_name, ), }这段代码有三个细节决定了抓取质量第一text_raw字段如果不存在就默认空字符串避免后续拼接时报错第二相对时间转换依赖本地服务器时间如果服务器时区不是北京时间会出错我一般在部署服务器上先执行timedatectl set-timezone Asia/Shanghai做校准第三user字段可能为None如果某个微博被删除或用户私密化这个字段会缺失所以用了item.get(user, {})来防御。3.3 翻页逻辑游标还是页码微博接口的特殊性微博网页端的翻页不是简单的page2换page3而是基于since_id游标。如果你直接改page参数最多翻几页就会被重定向到登录页。项目里实现了一个迭代器风格的取数函数利用上一页返回的since_id拼接下一页的请求。def fetch_all_weibos(fetcher, uid, max_pages50): url https://weibo.com/ajax/statuses/mymblog since_id page_count 0 while page_count max_pages: params {uid: uid, since_id: since_id} data fetcher.get_json(url, paramsparams) if not data or not data.get(data): break since_id data[data].get(since_id, ) for item in data[data].get(list, []): yield parse_weibo_item(item) page_count 1 if not since_id: break注意这个接口的uid参数必须和目标用户的uid一致而不是你自己的登录uid。如果返回的data为空通常是Cookie过期或uid拼写错误。我在试跑时遇到过一个很隐蔽的问题某个账号设置了仅半年可见翻到半年前的微博时接口返回的list为空但since_id依然有值导致死循环。解决方案是记录连续空页次数超过3次就主动终止。4. 从零跑通环境配置、依赖安装和第一次执行4.1 环境准备与requirements.txt这个项目对Python版本要求不苛刻3.8到3.11都能跑。建议先建一个虚拟环境避免污染全局Python。我的习惯是用venv而不是conda因为venv创建更轻量且项目依赖量不大。python -m venv weibo_env source weibo_env/bin/activate # Windows下执行 weibo_env\Scripts\activate pip install -r requirements.txtrequirements.txt里的核心依赖有requests、selenium用于模拟登录、qrcode终端二维码、pandas数据清洗、openpyxlExcel输出。如果你不需要图形界面登录可以注释掉selenium和qrcode这两行项目依然能靠手动Cookie方式正常运行。这也是项目设计上的一个弹性依赖尽量按模块拆分。4.2 首次运行配置清单运行前必须确认三件事当前网络能否直连微博域名、目标用户的UID是否填写正确、Cookie是否已生效。你可以先用一段简单的验证脚本测试Cookie# quick_test.py import requests from config import REQUEST_HEADERS, COOKIE_STRING session requests.Session() session.headers.update(REQUEST_HEADERS) # COOKIE_STRING形如 SUBxxx; SUHByyy session.cookies.update( dict(item.split(, 1) for item in COOKIE_STRING.split(; ) if in item) ) resp session.get(https://weibo.com/ajax/statuses/mymblog, params{uid: 你的目标UID, since_id: }) print(resp.status_code) print(resp.text[:500])如果返回的JSON里包含data且list是数组说明Cookie和UID配置都没问题。如果返回的是登录页面HTML或者pincode相关字段说明Cookie已失效。我写过最多的一次坑就是从浏览器复制的Cookie里包含了逗号分隔的多个Set-Cookie片段直接用分号分割会漏掉一部分导致登录态不完整。4.3 数据入库与导出项目默认把抓取结果同时写入SQLite和Excel。SQLite适合后续用SQL查询聚合数据Excel方便业务人员直接打开看。在main.py里你可以通过命令行参数控制输出方式python main.py --uid 1234567890 --output sqlite python main.py --uid 1234567890 --output excel python main.py --uid 1234567890 --output bothExcel导出用pandas的to_excel方法需要注意的一点是微博正文里可能包含特殊字符如换行符、制表符在写入Excel前要替换成空格否则生成的表格格式会错乱。SQLite写入则用executemany批量插入避免逐条插入导致的性能瓶颈。5. 避坑指南微博爬虫的五个经典问题5.1 状态码200但数据为空现象接口返回HTTP 200body里的JSON结构完整但data.list为空数组。原因这类情况多半是Cookie过期但未触发重定向微博静默返回空数据。还有一种可能是用户设置了内容可见范围如仅粉丝可见。解决先用quick_test.py验证Cookie状态如果Cookie失效就重新扫码登录如果Cookie正常换一个公开账号测试。如果目标账号本身就限制了可见范围那属于数据源问题不是爬虫问题。5.2 到了某个页数就被重定向到passport登录页现象前10页正常第11页开始拿到的不是JSON而是一段HTML脚本且包含passport字样。原因微博对单次会话的请求页数有频率限制短时间翻太多页触发了风控。解决在翻页循环中加入自适应延时每翻5页后休息30秒。如果还是被重定向最稳妥的方案是暂停10分钟让IP冷却。这个坑让我养成了一个习惯高耗时抓取任务一定要中间状态落盘别把结果只存在内存里。5.3 微博正文里的HTML实体没有完全清除现象解析出来的正文包含quot;、amp;等字符或者半角标签br /变成了文字。原因微博的text_raw字段保留部分HTML标签但另有text字段是纯文本。如果只取text_raw需要更全面的清洗正则。解决建议优先使用text字段它已经是去标签的纯文本如果某些字段为空再回退到text_raw清洗。清洗时先用html.unescape()处理实体字符再移除残留标签。5.4 相对时间转换偏差导致排序错乱现象同一时刻抓到的微博有的显示刚刚有的显示3分钟前转成绝对时间后部分记录比实际时间晚了几分钟。原因服务器时间和本地时间存在毫秒级偏差刚刚被归零处理实际可能差几十秒。解决项目里保留了两个时间字段——raw_time用于展示原始字符串publish_time用于排序。如果对时间精度要求高可以改用接口返回的created_at原始时间戳毫秒级但这个字段经常被隐藏需要额外字段映射。5.5 多线程加速导致IP直接被封现象用ThreadPoolExecutor并发请求跑了不到100条就被微博封禁所有接口返回418。原因微博的风控系统对同一IP的并发连接数有严格限制即使设置了延时并发请求也会被识别为异常。解决单线程加随机延时是最保守但最稳的方式。如果一定要加速要么接入代理池轮换IP要么改用服务端API如果有授权。我的经验是抓取1万条以下数据单线程的耗时完全可以接受没必要冒险上并发。6. 二次开发思路让这个爬虫变成你的数据管线6.1 从单用户抓取扩展成关键词搜索项目目前以抓取指定用户的时间线为主但很多场景需要按关键词搜索匹配微博。这需要一个搜索接口的适配。搜索接口的路径是https://weibo.com/ajax/statuses/search参数从uid换成keyword分页逻辑同样是since_id。你可以参考已有的fetch_all_weibos函数新增一个fetch_search_results方法。def fetch_search_results(fetcher, keyword, max_pages30): url https://weibo.com/ajax/statuses/search since_id for page in range(max_pages): params {keyword: keyword, since_id: since_id} data fetcher.get_json(url, paramsparams) if not data or not data.get(data): break since_id data[data].get(since_id, ) for item in data[data].get(list, []): yield parse_weibo_item(item)一个需要注意的地方搜索接口返回的微博可能来自不同用户因此解析函数里user_name字段不要依赖固定UID。如果后续想做舆情分析可以把这个函数和Excel导出串联让搜索结果直接生成带关键词的CSV文件方便导入可视化工具。6.2 定时增量抓取与断点续跑爬虫跑久了最怕中断后全部重来。我给项目加了一个简单的时间水位功能每次入库前记录MAX(publish_time)下次抓取时只取大于这个时间戳的新微博。这个方案有精度限制因为微博接口不支持按时间过滤只能翻页后过滤但至少能减少重复抓取。SQLite里建一个metadata表存上次抓取位置比读写本地文件更可靠。def get_last_sync_time(conn): cur conn.execute(SELECT value FROM metadata WHERE keylast_sync) row cur.fetchone() return row[0] if row else 1970-01-01 00:00:00增量逻辑放在main.py的调度器里每次抓完一轮就执行UPDATE metadata SET value... WHERE keylast_sync。如果你的目标是持续追踪某个话题的热度变化建议把调度器接到系统crontab上每小时跑一次。从那以后我每次搭数据爬虫都会强制过一遍这个设计能不能断点续跑中间状态有没有落盘如果数据量到十万级数据库索引和去重策略也要提前想好。6.3 扩展反爬应对能力如果遇到更严格的封禁策略可以从两个方向改造。第一是升级到代理池在fetcher里随机挑选代理IP并定期测试代理可用性。第二是引入浏览器指纹扰动每次请求随机调整User-Agent和Accept-Language但这会增加请求失败的不确定性。我觉得对个人开发者而言与其和风控对抗不如降低抓取频率、优化数据质量。毕竟爬虫的价值在于稳定拿到干净的数据而不是挑战平台的防御边界。说回实际场景我最近用这个项目抓了一批竞品账号分析出他们一周内发布互动最高的三类内容方向配合简单的情感分析给运营团队提供了很有价值的参考。希望你拿到这个项目后也能根据自己的需求做点有意思的事。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Claude Code编程实战:从快速上手到高效工作流

Claude Code编程实战:从快速上手到高效工作流

1. 从一个问题开始:Claude Code到底能帮我做什么很多开发者第一次接触Claude Code的时候,心里其实就一个疑问:这玩意儿和我直接在网页上跟AI聊天有什么区别?我最初也是这么想的——网页上能写代码、能解释代码、能生成注释&#x…

📅 2026/10/21 13:17:14
从零构建机器人地图模块:2D激光雷达、栅格地图与粒子滤波定位实践

从零构建机器人地图模块:2D激光雷达、栅格地图与粒子滤波定位实践

1. 先聊聊 lingbot-map 到底在解决什么问题1.1 机器人没有地图,就像人没有方向感做机器人的朋友应该都遇到过这个场景:底盘能跑、电机能转、遥控能走,但一旦你下达“去厨房门口等我”这种带位置的指令,它就傻在当场。原因很简单—…

📅 2026/10/21 13:17:14
Docker+MySQL+WordPress搭建个人博客:配置、部署与备份全指南

Docker+MySQL+WordPress搭建个人博客:配置、部署与备份全指南

开篇先聊几句掏心窝的话。我见过不少人兴冲冲想搭个人博客,结果卡在“安装环境”这一步就放弃了。WordPress安装包下好其实很容易,难的是之后那一串连锁反应:PHP版本不对、MySQL连不上、Nginx配置改错一处就白屏,折腾一晚上&#…

📅 2026/10/21 13:17:14
MORE NEWS

更多资讯

📰

USB分析仪实战:HID设备偶发丢包的定位思路与排查方法

打开协议分析仪软件的时候,我心里其实还在打鼓:这个“偶发丢HID包”的问题已经拖了三天,软件层日志翻了几遍,报告序号就是有缺口,可谁也说不清是在哪一段丢的。直到把USB分析仪串进链路,抓了不到二十分钟的…

📰

GeoScene异步GP服务调用实战:从超时到高并发稳定运行

1. 从一次超时说起:为什么必须搞懂异步GP服务做过GIS项目的人大概率都遇到过这样的场景:前端点一下“分析”按钮,页面转圈转了半分钟,最后弹出一个超时错误,后台日志显示地理处理任务其实还在跑。这不是代码写错了&…

📰

企业级AI Agent如何安全接入遗留系统与数据孤岛

前几天,我们内部代号 OpenClaw 的 AI Agent 试验项目,差点把生产环境给点了。原因是运营部想让它自动拉取一批经营数据,结果它顺着一条看起来人畜无害的旧接口,连续触发了三次对账批处理,核心业务表锁了大半天。复盘会…

📰

ArtCraft:可复现的创作方法论与参数化过程实践

1. 项目概述:ArtCraft 不是“艺术手作”的简单拼贴,而是一套可落地的创意生产方法论ArtCraft 这个词乍看像英文组合词,拆开是 Art(艺术)和 Craft(工艺/手艺),但放在当下内容生态里&a…

📰

Portal认证实战:组网模式、认证流程与配置避坑指南

1. 从一次会议室断网说起:Portal认证到底在解决什么问题很多人第一次接触Portal认证,是因为遇到了一个很具体的场景:公司会议室来了访客,对方问WiFi密码,你把密码告诉了他,然后他连上了,但打开浏…

📰

程序化艺术工作流artcraft:从随机生成到可控创作

"artcraft"这个名字挂在项目仓库里很久了。一开始它就两个词拼在一起:art 和 craft,我连 README 都没写。后来真把它做成一套能被自己和其他创作者反复使用的程序化艺术工作流,我才明白这名字其实起对了——艺术负责表达&#xff0…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬