# 不用官方API,我写了个Python工具采集微博数据
> 零成本、高灵活度的微博数据采集方案,附完整代码解析
做舆情分析或社交媒体研究时,微博数据是很重要的信息源。官方API不仅申请门槛高,调用限制也多。今天分享一个基于 **DrissionPage** 的采集方案,无需付费接口,就能按关键词和时间范围稳定获取数据。
—
## 一、这个工具能做什么?
简单来说,它支持两种采集模式:
模式一:按关键词搜索帖子
输入任意关键词,设定采集天数,工具会自动按天拆分、逐页翻取搜索结果。每条帖子会记录:`mid`、昵称、发布时间、来源设备、正文内容、转发/评论/点赞数。
模式二:采集指定微博的评论
拿到某条微博的ID后,可以递归抓取全部评论——包括楼中楼(子评论)。每条评论包含:评论时间、楼层、用户信息(性别、位置、粉丝数等)、评论内容、点赞数。
两种模式可以单独使用,也可以串起来:先用模式一筛出目标帖子,再用模式二深挖评论。
## 二、技术选型:为什么用 DrissionPage?
常规爬虫面对微博有三道坎:**登录鉴权**、**反爬机制**、**动态渲染**。
这个方案的核心依赖是 `DrissionPage`,一个融合了浏览器控制和HTTP请求的Python库。它最大的好处是**既能像Selenium一样操控真实浏览器,又能像requests一样发协议请求**。
具体来说:
| 环节 | 使用的模块 | 原因 |
|------|-----------|------|
| 获取Cookie | `ChromiumPage` | 手动扫码登录,绕过风控 |
| 搜索列表采集 | `SessionPage` | 纯HTTP请求,速度更快 |
| 评论接口采集 | `SessionPage` | Ajax接口直接返回JSON |
一旦拿到登录后的Cookie,后续全部走 `SessionPage` 发请求,效率远高于全程模拟浏览器。
—
## 三、核心实现拆解
### 3.1 Cookie的获取与转换
登录是第一步。代码启动一个真实的Chrome窗口,让用户手动扫码登录:
```python
def get_cookies():
page = ChromiumPage()
page.get(‘https://weibo.com/’)
input(‘请登录后按回车’)
cookies = page.cookies()
page.quit()
return cookies
```
拿到的Cookie是列表格式,需要转成字典供后续请求使用:
```python
def convert_cookies_to_dict(cookies_list):
cookies_dict = {}
for cookie in cookies_list:
if ‘name’ in cookie and ‘value’ in cookie:
cookies_dict[cookie[‘name’]] = cookie[‘value’]
return cookies_dict
```
其中 `XSRF-TOKEN` 这个字段,在评论采集的请求头中会单独取出使用。
### 3.2 关键词搜索:按天拆分 + 逐页翻取
微博搜索页的时间筛选通过 `timescope` 参数控制,格式是 `custom:2025-05-01:2025-05-01`。因此代码做了两层循环:
```python
for day_offset in range(1, current_day_number + 1):
target_date = datetime.date.today() - datetime.timedelta(days=day_offset)
date_str = target_date.strftime(“%Y-%m-%d”)
timescope_value = f"custom:{date_str}:{date_str}"
for page_num in range(1, 51):
params = {
“q”: keyword,
“timescope”: timescope_value,
“page”: f"{page_num}"
}
发起请求并解析…
```
这样设计有两个好处:一是避免单次请求数据量过大被限制;二是日期维度天然对齐,后续分析更方便。
页面解析部分,利用 `DrissionPage` 的元素定位能力,直接从DOM中提取微博卡片:
```python
items = page.ele(‘@id=pl_feedlist_index’).ele(‘@class=m-filtertab’, index=1)\
.next(‘t:div’).eles(‘@class=card-wrap’)
```
每条卡片的 `mid` 属性、昵称、正文、转发/评论/点赞数都被结构化提取,写入 `DataRecorder` 管理的Excel文件。
### 3.3 评论采集:递归处理楼中楼
微博的评论接口是 `/ajax/statuses/buildComments`,返回JSON格式。核心逻辑是**翻页 + 递归**:
```python
def parse(data, recorder):
max_id = data[‘max_id’]
下一页的游标
items = data[‘data’]
for item in items:
解析当前评论…
recorder.add_data(result)
if item[‘comments’]:
存在子评论
parse_comment(item[‘comments’])
递归采集
return max_id, total_number, flag
```
翻页通过 `max_id` 游标驱动,每次请求带上上一页返回的 `max_id`,直到接口不再返回新的游标值。
遇到楼中楼时,`item[‘comments’]` 字段不为空,递归调用 `parse_comment` 进行解析,确保评论链条完整。
### 3.4 HTML内容清洗
部分返回的文本字段包含HTML标签(如 `` 链接、`` 换行),代码用 `BeautifulSoup` 统一清洗:
```python
from bs4 import BeautifulSoup
soup = BeautifulSoup(text, ‘html.parser’)
text = soup.get_text()
```
这样就可以拿到干净的纯文本内容。
—
## 四、完整使用流程
第一步:环境准备
```bash
pip install DrissionPage DataRecorder loguru beautifulsoup4
```
第二步:运行脚本,获取Cookie
程序启动后会弹出一个Chrome窗口,导航到微博首页。此时手动扫码或输入账号密码登录,完成后在终端按回车,Cookie会自动保存。
第三步:选择采集模式
输入关键词和采集天数,启动模式一
或者传入微博ID,启动模式二
数据会自动写入同目录下的Excel文件,每100条缓存一次,既保证数据不丢失,又兼顾写入效率。
—
## 五、几个需要注意的细节
1. 请求频率控制
代码中多处加了 `time.sleep(random.randint(2, 3))` 和 `random.uniform(1, 2)` 的随机延迟。这不是多余的——稳定采集的核心就是控制节奏,频率过高很容易触发风控。
2. 页面解析的容错
微博的DOM结构有时会因A/B测试或版本更新而微调。代码中广泛使用 `try/except` 包裹解析逻辑,比如设备来源、正文位置可能在不同帖子里结构不同:
```python
try:
content = content_element.s_ele(‘@class=txt’, index=2).text
except:
content = content_element.s_ele(‘@class=txt’, index=1).text
```
这种防御性写法能有效降低因个别字段缺失导致整条数据丢弃的概率。
3. 性别字段的中文映射
评论接口返回的性别是 `m` / `f`,代码做了映射转换,让导出数据更直观:
```python
if gender == ‘m’:
gender = ‘男’
else:
gender = ‘女’
```
—
## 六、总结
这套方案的优势在于**完全绕过官方API的限制**,关键词、时间范围、采集量都由自己控制。`DrissionPage` 的混合模式设计,既解决了登录难题,又保证了采集效率。
当然,它本质上还是爬虫,使用时需要遵守网站的robots协议,合理控制频率,仅用于合法的研究场景。
完整代码我已整理好,如果需要可以在后台回复关键词获取。
—
**工具虽好,且用且珍惜。** 频率太快不仅伤服务器,也容易被封号。建议大家把延迟设得宽松一些,细水长流才是真。
—
*本文涉及的代码仅用于技术学习交流,请勿用于非法用途。*