在数据分析、市场调研或粉丝互动的场景中,B站(Bilibili)的评论区往往蕴含着巨大的价值。
本文将详细解析一套基于 bilibili-api-python 库编写的爬虫程序。
该程序不仅能遍历指定UP主的所有视频,还能深入抓取制定日期之后的主评论及其子回复(楼中楼),并利用正则表达式自动提取用户的邮箱地址,最终导出为Excel表格。
🛠️ 技术栈与准备工作
- 核心库:
bilibili_api (异步API封装), pandas (数据存储), asyncio (异步控制)
第一阶段:获取通行证 (Cookie)
B站的数据接口对未登录用户有严格限制。第一步是通过扫码获取 Credential(凭证)。
代码解析
代码利用了 login_v2 模块实现终端二维码登录。
from bilibili_api import login_v2, sync
import time
asyncdefmain() -> None:
# 1. 实例化二维码登录组件,指定平台为WEB
qr = login_v2.QrCodeLogin(platform=login_v2.QrCodeLoginChannel.WEB)
# 2. 生成并打印二维码(在终端中显示字符画或URL)
await qr.generate_qrcode()
print(qr.get_qrcode_terminal())
# 3. 轮询检测扫码状态
whilenot qr.has_done():
print(await qr.check_state())
time.sleep(1)
# 4. 核心:获取Cookie字典
print(qr.get_credential().get_cookies())
💡 关键点: 运行此脚本后,会在屏幕上出现一个巨大的二维码,如果你是在命令行中运行的,可以通过按住Ctrl+鼠标滚轮的方式进行缩小。
然后使用B站app进行扫码登陆
登陆成功后,控制台会输出 SESSDATA, bili_jct, buvid3 等关键字段。你需要将这些长字符串复制下来,填入爬虫主程序的配置区域。
第二阶段:全自动爬虫架构解析
获取凭证后,进入主程序。这部分代码采用了 asyncio 异步编程模型以提高效率,同时配合 sleep 防止触发反爬风控。
1. 配置与初始化
程序首先定义了目标UP主的UID、截止日期以及凭证信息。
UP_UID = ***************# 目标UP主UID
END_TIME_STR = '2025-10-20'# 设定爬取的时间界限
CREDENTIAL = Credential( # 填入第一阶段获取的Cookie
sessdata="...",
bili_jct="...",
buvid3="...",
dedeuserid="..."
)
2. 视频列表遍历 (外层循环)
使用 user.User 对象获取UP主的视频列表。这里使用了 while 循环配合页码 page_pn 进行翻页。
u = user.User(UP_UID, CREDENTIAL)
while is_working:
# 获取第 page_pn 页的视频
videos_data = await u.get_videos(pn=page_pn)
vlist = videos_data['list']['vlist']
ifnot vlist: break# 如果列表为空,说明爬取完毕
for video in vlist:
# 获取视频的 bvid 和 aid (API调用通常需要aid)
aid = bvid2aid(video['bvid'])
# ...进入评论爬取流程...
3. 主评论流的“懒加载”处理
B站评论区采用“懒加载”模式(瀑布流)。代码使用 comment.get_comments_lazy 接口,并配合 OrderType.TIME(按时间排序)来实现高效过滤。
时间过滤策略: 由于评论是按时间倒序排列的,一旦检测到某条评论的时间早于 END_TIME_STR,程序会直接标记 video_finished = True 并跳出循环,避免无效爬取历史久远的数据。
c = await comment.get_comments_lazy(
oid=aid,
type_=CommentResourceType.VIDEO,
offset=offset, # 控制翻页游标
order=OrderType.TIME, # 按发布时间倒序
credential=CREDENTIAL
)
4. 核心难点:子回复(楼中楼)爬取
这是整套代码中最具技术含量的部分。普通的评论接口只返回主评论,若主评论下有回复(rcount > 0),需要单独请求子回复接口。
修正逻辑: 代码通过实例化一个新的 Comment 对象来专门处理某一条主评论下的子回复列表。
# 如果存在子回复
if rcount > 0:
root_id = rep['rpid'] # 根评论ID
# 实例化当前这条评论的对象
current_comment_obj = Comment(
oid=aid,
type_=CommentResourceType.VIDEO,
rpid=root_id, # 关键:指定根评论ID
credential=CREDENTIAL
)
# 循环翻页获取所有子回复
whileTrue:
sub_res = await current_comment_obj.get_sub_comments(page_index=sub_page)
# ...处理数据...
await asyncio.sleep(0.8) # 子回复翻页延时
5. 数据清洗与正则提取
在 process_data 函数中,利用正则表达式从混乱的评论文本中精准提取邮箱。
# 强大的正则匹配模式
email_pattern = r'[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}'
emails = re.findall(email_pattern, message, re.IGNORECASE)
6. 数据持久化
所有抓取的数据被暂存在内存列表 all_data 中,最后统一使用 pandas 导出为 Excel 文件。
df = pd.DataFrame(all_data)
df.to_excel(OUTPUT_FILE, index=False)
🛡️ 代码中的“防封”智慧
在爬虫开发中,安全性比速度更重要。这套代码在多个环节植入了保护措施:
- 点评:虽然这会降低爬取速度,但能极大降低被B站封禁IP或账号的风险。
- 在主评论流和子回复流中均包裹了
try...except,确保单个请求失败(如网络波动)不会导致整个程序崩溃。
- 利用
OrderType.TIME 结合时间戳比对,避免无意义地爬取数年前的数据,减少服务器请求量。
代码获取
关注公众号易派森,输入关键词“B站评论区爬虫”即可获得完整代码
📊 总结
这套代码是一个功能完备的垂直领域爬虫。它不仅仅是简单的接口调用,更处理了复杂的嵌套评论结构(Recursion/Nested Comments)和分页逻辑。
适用场景:
- 线索收集:从评论区收集用户留下的联系方式(如邮箱)。
⚠️ 法律与道德提示:
- 请务必在 Bilibili 平台规则允许的范围内使用。
- 爬取到的邮箱等个人隐私信息请严格保密,严禁用于非法买卖或骚扰推广。
- 建议使用小号运行爬虫,以防账号因高频请求被风控限制。
本文基于真实代码案例分析,旨在分享Python异步编程与网络爬虫技术。