为什么你的B站数据获取总是403终极指南掌握新版B站API评论获取的正确姿势【免费下载链接】bilibili-api哔哩哔哩常用API调用。支持视频、番剧、用户、频道、音频等功能。原仓库地址https://github.com/MoyuScript/bilibili-api项目地址: https://gitcode.com/gh_mirrors/bi/bilibili-api作为一名Python开发者和数据分析师你是否经常遇到这样的困境精心编写的B站爬虫突然开始返回403错误无论怎么更换IP、修改请求头都无济于事昨天深夜小王就经历了这样的煎熬——他的B站评论数据采集工具突然失效而项目deadline就在眼前。如果你也面临类似的挑战那么这篇文章就是你的救星。我们将深入探讨bilibili-api库中的核心技术特别是如何高效、稳定地获取B站评论数据彻底告别403错误的困扰。 问题根源为什么B站API接口会频繁返回403在深入解决方案之前让我们先理解问题的本质。B站作为一个日活数亿的平台拥有完善的反爬虫机制。当你使用传统的分页接口时服务器会检测到异常的请求模式从而触发403防护。bilibili-api库提供了两种评论获取接口它们的差异决定了你的爬虫能否稳定运行。旧接口get_comments()采用传统分页模式这种模式容易被B站的反爬系统识别。而新接口get_comments_lazy()采用了现代Web应用中常见的懒加载机制通过offset参数实现连续数据获取这种方式更接近真实用户行为因此更不容易触发反爬机制。 技术原理解析新版API接口如何工作要理解为什么新接口更稳定我们需要深入其技术实现。get_comments_lazy()接口采用了cursor-based pagination游标分页机制这是现代API设计的标准实践。核心机制游标分页 vs 传统分页传统分页使用页码page_index作为参数每次请求都从第一页开始计算偏移量容易被识别为爬虫行为游标分页使用offset偏移量作为参数每次请求的offset来自上一次响应更接近真实用户的滚动加载行为B站前端投票模块的代码结构展示了数据绑定机制评论系统采用了类似的实现逻辑资源类型与ID映射bilibili-api支持多种内容类型的评论获取每种类型都有对应的资源ID获取方法from bilibili_api.comment import CommentResourceType # 视频评论使用视频的AV号 video_oid 418788911 video_type CommentResourceType.VIDEO # 专栏文章评论使用专栏的CV号 article_oid 9762979 article_type CommentResourceType.ARTICLE # 动态评论使用动态ID dynamic_oid 116859542 dynamic_type CommentResourceType.DYNAMIC # 音频评论使用音频AU号 audio_oid 13998 audio_type CommentResourceType.AUDIO每种资源类型都有对应的获取方法具体可以参考评论模块源码bilibili_api/comment.py 实战解决方案3步搞定新版评论获取第一步环境准备与认证配置在开始之前确保你已经正确安装了bilibili-api库pip install bilibili-api为了提高请求成功率建议配置认证信息。你可以通过以下方式获取认证信息from bilibili_api import Credential # 创建认证对象可选但推荐 credential Credential( sessdata你的sessdata, bili_jct你的bili_jct, buvid3你的buvid3 )关于如何获取这些认证信息可以参考认证模块文档docs/get-credential.md第二步核心代码实现下面是一个完整的新版评论获取实现import asyncio from bilibili_api import comment, sync, Credential async def fetch_comments_safely(video_aid: int, max_pages: int 10): 安全获取视频所有评论 Args: video_aid: 视频AV号 max_pages: 最大获取页数安全限制 Returns: 评论列表 # 可选的认证信息显著提高成功率 credential Credential( sessdata你的sessdata, bili_jct你的bili_jct, buvid3你的buvid3 ) all_comments [] offset # 初始偏移量为空字符串 page_count 0 while True: try: # 使用新版懒加载接口 result await comment.get_comments_lazy( oidvideo_aid, type_comment.CommentResourceType.VIDEO, offsetoffset, credentialcredential # 添加认证信息 ) # 提取评论数据 replies result.get(replies, []) if replies: all_comments.extend(replies) print(f✅ 第{page_count 1}页获取到{len(replies)}条评论) # 获取下一次请求的偏移量 cursor result.get(cursor, {}) pagination_reply cursor.get(pagination_reply, {}) next_offset pagination_reply.get(next_offset, ) # 检查是否还有更多数据 if not next_offset or cursor.get(is_end, False): print( 所有评论已获取完毕) break # 更新偏移量继续获取 offset next_offset page_count 1 # 安全限制避免无限循环 if page_count max_pages: print(f⚠️ 已达到最大页数限制{max_pages}页) break # 添加适当延迟避免请求过快 await asyncio.sleep(0.8) # 建议0.5-1秒的延迟 except Exception as e: print(f❌ 获取评论时出错{str(e)}) # 指数退避重试 wait_time min(2 ** page_count, 30) # 最大等待30秒 print(f⏳ {wait_time}秒后重试...) await asyncio.sleep(wait_time) return all_comments # 使用示例 async def main(): # 获取视频AV418788911的所有评论 video_comments await fetch_comments_safely(418788911) # 分析评论数据 print(f\n 数据分析报告) print(f总评论数{len(video_comments)}) # 统计点赞数最高的前5条评论 top_comments sorted(video_comments, keylambda x: x.get(like, 0), reverseTrue)[:5] print(\n 热门评论Top 5) for i, cmt in enumerate(top_comments, 1): user cmt[member][uname] content cmt[content][message] like_count cmt[like] print(f{i}. {user}: {content[:50]}... ( {like_count})) # 运行程序 sync(main())第三步数据处理与分析获取到评论数据后你可以进行各种分析def analyze_comments(comments): 分析评论数据 if not comments: return {} # 基础统计 total_comments len(comments) total_likes sum(cmt.get(like, 0) for cmt in comments) avg_likes total_likes / total_comments if total_comments 0 else 0 # 用户活跃度分析 users {} for cmt in comments: uid cmt[member][mid] users[uid] users.get(uid, 0) 1 top_users sorted(users.items(), keylambda x: x[1], reverseTrue)[:5] # 时间分布分析如果有时间戳 # 这里假设评论数据中包含ctime字段 time_comments {} for cmt in comments: timestamp cmt.get(ctime, 0) if timestamp: # 转换为小时 hour (timestamp % 86400) // 3600 time_comments[hour] time_comments.get(hour, 0) 1 return { total_comments: total_comments, total_likes: total_likes, average_likes: round(avg_likes, 2), unique_users: len(users), top_active_users: top_users, hourly_distribution: dict(sorted(time_comments.items())) } # 使用分析函数 analysis_result analyze_comments(video_comments) print(f 评论分析结果{analysis_result}) 进阶技巧分享提升数据获取效率技巧1并发获取多个视频的评论如果你需要获取多个视频的评论可以使用异步并发来大幅提升效率import asyncio from bilibili_api import comment, sync async def fetch_multiple_videos_comments(video_ids, max_concurrent3): 并发获取多个视频的评论 semaphore asyncio.Semaphore(max_concurrent) async def fetch_with_limit(video_id): async with semaphore: return await fetch_comments_safely(video_id) tasks [fetch_with_limit(vid) for vid in video_ids] results await asyncio.gather(*tasks, return_exceptionsTrue) # 处理结果 all_results {} for video_id, result in zip(video_ids, results): if isinstance(result, Exception): print(f❌ 视频{video_id}获取失败{result}) all_results[video_id] [] else: all_results[video_id] result print(f✅ 视频{video_id}获取到{len(result)}条评论) return all_results # 使用示例 video_list [418788911, 418788912, 418788913] results sync(fetch_multiple_videos_comments)(video_list)技巧2智能重试与错误处理网络请求总是不稳定的添加智能重试机制可以显著提高成功率from bilibili_api.exceptions import NetworkException, ResponseCodeException import random async def robust_fetch_comments(oid, type_, max_retries5): 带智能重试的评论获取 for attempt in range(max_retries): try: return await comment.get_comments_lazy(oid, type_) except NetworkException as e: if attempt max_retries - 1: # 指数退避 随机抖动 base_delay 2 ** attempt jitter random.uniform(0, 1) wait_time base_delay jitter print(f 网络错误{wait_time:.1f}秒后重试...) await asyncio.sleep(wait_time) else: raise e except ResponseCodeException as e: if e.code 403: print(f 403错误尝试更换策略...) # 可以在这里添加更换代理、更换认证信息等逻辑 await asyncio.sleep(3) else: raise e 最佳实践指南避免常见陷阱实践1合理设置请求频率B站对API请求有频率限制过度频繁的请求会导致IP被封。以下是一些建议单次请求间隔0.5-1秒批量请求间隔每10个请求后休息3-5秒每日请求上限根据账号等级不同建议不超过10000次/天实践2认证信息管理认证信息是获取完整数据的关键获取认证信息使用B站账号登录后获取sessdata、bili_jct等定期更新认证信息会过期建议每周检查一次多账号轮换如果需要大量数据使用多个账号轮换请求实践3数据缓存策略对于不经常变化的数据实施缓存策略可以大幅减少请求import json import hashlib import os from datetime import datetime, timedelta class CommentCache: 评论数据缓存管理器 def __init__(self, cache_dircomment_cache): self.cache_dir cache_dir os.makedirs(cache_dir, exist_okTrue) def _get_cache_key(self, oid, type_): 生成缓存键 key_str f{oid}_{type_} return hashlib.md5(key_str.encode()).hexdigest() def get_cached_comments(self, oid, type_, max_age_hours24): 获取缓存的评论数据 cache_key self._get_cache_key(oid, type_) cache_file os.path.join(self.cache_dir, f{cache_key}.json) if os.path.exists(cache_file): # 检查缓存是否过期 file_mtime datetime.fromtimestamp(os.path.getmtime(cache_file)) if datetime.now() - file_mtime timedelta(hoursmax_age_hours): with open(cache_file, r, encodingutf-8) as f: return json.load(f) return None def save_comments(self, oid, type_, comments): 保存评论数据到缓存 cache_key self._get_cache_key(oid, type_) cache_file os.path.join(self.cache_dir, f{cache_key}.json) with open(cache_file, w, encodingutf-8) as f: json.dump({ oid: oid, type: type_, comments: comments, cached_at: datetime.now().isoformat() }, f, ensure_asciiFalse, indent2)❓ 常见问题解答FAQQ1为什么我获取的评论只有20条A未登录状态下B站API只返回前20条评论。这是平台的安全限制。解决方案是添加有效的认证信息Credential。Q2offset参数应该怎么使用Aoffset是游标分页的核心参数第一次请求时使用空字符串offset后续请求使用上次响应中的next_offset值当next_offset为空或is_end为True时表示已获取所有数据Q3如何处理403错误A403错误通常由以下原因引起请求频率过高降低请求频率增加延迟认证信息失效更新sessdata、bili_jct等认证信息IP被封禁更换IP地址或使用代理使用旧接口切换到get_comments_lazy()接口Q4如何获取不同类型的评论A使用不同的CommentResourceType枚举# 视频评论 comment.CommentResourceType.VIDEO # 专栏文章评论 comment.CommentResourceType.ARTICLE # 动态评论 comment.CommentResourceType.DYNAMIC # 音频评论 comment.CommentResourceType.AUDIO # 课程评论 comment.CommentResourceType.CHEESEQ5如何获取子评论回复A使用Comment类的get_sub_comments()方法from bilibili_api import Comment # 创建评论对象 cmt Comment(rpid123456, oid418788911, type_comment.CommentResourceType.VIDEO) # 获取子评论 sub_comments await cmt.get_sub_comments() 快速上手指南如果你只想快速开始这里有一个最简化的示例from bilibili_api import comment, sync async def quick_start(): # 获取视频的第一页评论未登录状态最多20条 result await comment.get_comments_lazy( oid418788911, # 视频AV号 type_comment.CommentResourceType.VIDEO, offset # 初始偏移量 ) # 打印评论 for reply in result.get(replies, []): user reply[member][uname] content reply[content][message] likes reply[like] print(f {user}: {content[:50]}... ( {likes})) # 获取下一页的偏移量 next_offset result[cursor][pagination_reply][next_offset] print(f\n 下一页偏移量{next_offset}) sync(quick_start()) 后续学习路径掌握了基础的评论获取后你可以进一步学习1. 深入学习bilibili-api其他模块视频模块bilibili_api/video.py - 获取视频信息、弹幕、播放量等用户模块bilibili_api/user.py - 获取用户信息、投稿、关注等动态模块bilibili_api/dynamic.py - 获取用户动态2. 查看更多示例代码项目提供了丰富的示例代码可以参考示例代码目录docs/examples/3. 探索高级功能异步并发处理使用asyncio.gather并发获取多个资源数据持久化将获取的数据保存到数据库或文件实时监控定时获取数据并监控变化4. 参与社区贡献如果你在使用过程中发现问题或有改进建议欢迎参与项目贡献查看项目源码结构阅读开发文档提交Issue或Pull Request 立即行动现在就开始你的B站数据分析之旅安装库pip install bilibili-api获取认证按照docs/get-credential.md获取认证信息运行示例从最简单的示例开始逐步深入应用到项目将评论获取功能集成到你的数据分析项目中分享经验在社区分享你的使用心得和遇到的问题记住技术总是在不断演进。保持学习的态度及时更新你的知识库就能在技术的浪潮中立于不败之地。现在就去尝试获取你的第一条B站评论数据吧Bilibili API项目Logo一个基于Python的B站API调用库支持视频、番剧、用户、频道、音频等功能重要提示在使用bilibili-api进行数据获取时请务必遵守B站的使用条款不要过度频繁请求尊重平台服务器压力仅将数据用于学习和研究目的。【免费下载链接】bilibili-api哔哩哔哩常用API调用。支持视频、番剧、用户、频道、音频等功能。原仓库地址https://github.com/MoyuScript/bilibili-api项目地址: https://gitcode.com/gh_mirrors/bi/bilibili-api创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考