微博作为国内最大的社交媒体平台之一,其话题评论数据蕴含丰富的用户观点和舆情价值。本文将手把手教你使用Python多线程技术高效爬取微博话题评论数据,仅需30行核心代码,轻松解决传统爬虫效率低、易被封IP的问题。
本次使用DrissionPage库来爬取数据,不会这个库的同学可以去官网看一下文档。这个库是一个国人写的爬虫库,使用起来简单易上手,该库提供很多强大的功能,是一个很好的爬虫库。
通过该文章你将学会:
1、DrissionPage实现多话题下的多文章下的多评论自动爬取
2、DrissionPage与多线程的结合使用
3、微博评论的基本爬取思路。
一、环境准备
安装DrissionPage实现浏览器控制,DataRecorder实现高效数据存储。这两个库的组合完美解决了传统爬虫的三大痛点:
1. 反爬破解(浏览器模拟)
2. 数据监听(API捕获)
3. 存储性能(批量写入)
pip install DrissionPage # 无头浏览器控制
pip install DataRecorder # 数据存储神器
二、核心流程解析
需求:根据用户输入的话题,爬取该话题下面所有文章的所有评论。
实现思路:使用Drissionpage模拟操作浏览器,循环遍历用户输入的话题,打开对应的话题后,获取到该话题下面所有的文章原文详情页链接,并保存为列表。
# 获取用户输入的话题(多个话题用英文逗号分隔)
input_str = input('请输入你要爬取的话题:(注意多个话题直接用英文","隔开)\n')
# 将输入的字符串按逗号分割为列表
input_list = input_str.split(',')
# 遍历每个话题进行爬取
for i in input_list:
print(f'====================正在爬取:{i}============================')
# 初始化浏览器实例(显示界面)
browser = Chromium()
# 获取当前最新标签页对象
tab = browser.latest_tab
# 构造微博搜索URL(%23是#的URL编码)
# 示例:https://s.weibo.com/weibo?q=%23AI技术%23
tab.get(f'https://s.weibo.com/weibo?q=%23{i}%23')
# 使用XPath定位微博卡片的链接
# 解析逻辑:
# 1. id="pl_feedlist_index" - 微博列表容器
# 2. action-type="feed_list_item" - 单条微博卡片
# 3. class="from" - 来源链接区域
# 4. a[1] - 第一个超链接(微博详情页)
card_wrap_links = tab.eles(
'x://div[@id="pl_feedlist_index"]//div[@action-type="feed_list_item"]//div[@class="from"]/a[1]'
).links # 直接获取所有匹配元素的链接列表
代码运行效果:
三. 多线程爬取详情页的评论
上面我们已经获取到啦每个原文详情页的连接,接下来就开始打开每个详情页来爬取评论,Dressionpage爬虫库提供啦一个很强大优雅的功能-----监听接口,我们可以使用F12打开浏览器的控制台,来刷新页面观察评论是从哪个接口返回的。
微博网页端的评论接口为:https://www.weibo.com/ajax/statuses/buildComments?is_reload=1&id=5176024913414298&is_show_bulletin=2&is_mix=0&count=10&uid=1635717035&fetch_level=0&locale=zh-CN
我们只需要使用Drissonpage的监听功能监听该接口即可获取到对应的评论数据,并且需要翻页来实现多页评论的爬取。对应代码如下:
def fetch_comments(url):
# 新开一个标签页访问目标微博详情页
new_tab = browser.new_tab(url)
# 等待1秒确保页面加载基础元素
new_tab.wait(1)
# 开始监听AJAX请求(评论数据接口)
new_tab.listen.start("https://weibo.com/ajax/statuses/buildComments")
# 刷新页面以触发评论加载
new_tab.refresh()
# 等待2秒确保评论数据加载完成
new_tab.wait(2)
# 开始无限滚动加载评论
while True:
try:
# 等待并捕获评论数据接口的响应
# timeout=5 表示最多等待5秒,超时则抛出异常
rp = new_tab.listen.wait(timeout=5).response.body
# 提取评论数据列表(通常在 "data" 字段中)
datas = rp.get('data')
# 遍历每条评论数据
for data in datas:
# 用户昵称(从 user.screen_name 中提取)
nickname = data.get('user').get('screen_name')
# 用户主页地址(从 source 字段提取)
user_url = data.get('source')
# 评论内容(原始文本,可能包含HTML转义字符)
text = data.get('text')
# 评论时间(需格式化为标准时间格式)
created_at = format_weibo_time(data['created_at'])
# 用户签名(来自 user.description)
description = data['user']['description']
# 打印调试信息(可选)
print(f"昵称:{nickname}\n评论内容:{text}\n评论时间:{created_at}\n用户地址:{user_url}\n用户签名:{description}\n")
# 构建结构化数据字典
data_dictionary = {
'昵称': nickname,
'评论内容': text,
'评论时间': created_at,
'用户地址': user_url,
'用户签名': description
}
# 保存数据到CSV文件
sava_to_csv(data_dictionary)
# 判断是否已加载完所有评论
# max_id=0 表示没有更多数据
if rp.get('max_id') == 0:
print("当前没有数据啦!")
break
# 滚动到页面底部触发加载更多评论
new_tab.scroll.to_bottom()
# 等待5秒(规避反爬策略)
new_tab.wait(5)
except Exception as e:
print(f"抓取失败: {e}")
break
运行效果:
三、多线程爬评论(核心技巧)
接下来实现多线程爬取,上面我们定义啦一个爬取详情页评论的方法,接下来可以使用ThreadPoolExecutor库来进行多线程爬取,每次爬取多个文章的评论。代码如下:
# 开启2个线程 不要多开线程,否则容易出现数据丢失
with ThreadPoolExecutor(max_workers=2) as executor:
executor.map(fetch_comments, card_wrap_links)
最后看结果:
每次打开两个页面,分别获取对应下面的评论数据。
数据结果:
教程到此结束,有什么不懂得可以在评论问我。