ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

B站爬虫实战:从接口分析到数据采集的完整指南

B站爬虫实战:从接口分析到数据采集的完整指南 1. 项目概览B站公开数据采集的思路与边界做爬虫项目这么多年B站一直是个绕不开的目标。弹幕、评论、视频元数据、用户信息、排行榜……这些数据对做内容分析、舆情监控、行业报告、个人作品集都非常有价值。我见过不少朋友把“写一个b站爬虫”当成练手项目也有人是真的想用它做点实际分析但真正能把思路理清楚、把代码写干净的人其实不多。这篇文章不直接扔给你一个能“跑起来就完事”的脚本而是要聊清楚背后那套通用思路。数据从哪来、怎么拿、怎么解析、怎么存、遇到封禁怎么办、合规边界在哪——这些才是你做任何一个平台爬虫时真正要解决的问题。B站只是载体思路才是通用资产。适合谁来读刚学完Python基础、想找一个实战项目练手的人已经有爬虫经验、想了解B站特殊机制的人以及想做数据分析和内容研究、需要稳定采集公开数据的人。这篇文章不涉及任何绕过付费墙、破解加密、暴力破解的高风险操作所有讨论都限定在“公开可访问数据”这一合规范围内。先讲清楚一个底层认知爬虫的本质不是“破解”而是“模拟人类的正常浏览行为并以更高效、更规范的方式收集公开信息”。你的代码只是一个访客只不过这个访客阅读速度极快、记忆力极好。理解了这一点很多技术选型和风险判断就都有了准绳。2. 整体设计方案先定边界再谈架构2.1 核心需求拆解你到底是来取什么的做爬虫最容易犯的错是一上来就写requests.get(url)结果爬到一半发现数据结构变了、字段对不上、请求被限流然后整个项目推倒重来。正确做法是先把需求拆清楚。以B站为例常见的采集需求有以下几类数据类型典型字段潜在用途视频元数据标题、UP主、发布时间、分区、时长、播放量、点赞数、收藏数、硬币数热门趋势分析、分区对比评论数据评论内容、楼层、点赞数、评论者UID、发布时间舆情分析、用户画像弹幕数据弹幕文本、出现时间点、发送者、颜色内容情绪分析、视频二创排行榜各分区日榜、周榜、总榜数据看板、行业报告用户公开信息昵称、签名、关注数、粉丝数、投稿列表账号分析、KOL识别这里要特别说明弹幕、评论、视频列表这类数据B站在网页端本身就是通过接口返回JSON的也就是说你不需要“破解”什么只需要找到对应的接口按正常参数请求就能拿到结构化数据。这是所有平台爬虫里最“温和”的一类。2.2 采集方案选型接口优先页面渲染兜底B站的数据获取路径大致有三条优先级从高到低排列第一官方开放接口。这是最优先的选项。B站有面向开发者的开放平台也有大量内部Web接口页面自己在用的那套。前者最合规后者属于灰色区域但在公开数据范围内风险较低。如果你只需要视频基本信息、排行榜、搜索建议等数据优先看看有没有官方API可用哪怕字段少一些稳定性和安全性也是最好的。第二Web页面接口。B站的网页版在浏览器里会自动向后端发大量请求这些请求就是“页面背后的接口”。用浏览器的开发者工具F12切到Network面板刷新页面可以看到所有网络请求其中返回JSON的那些就是你要的接口。因为接口是平台业务逻辑的一部分字段丰富、数据新鲜绝大多数自用场景都用这种方式。第三渲染后的页面解析。如果某个页面的数据不是通过JSON接口返回而是由JavaScript动态渲染出来的比如某些个性化推荐页那你需要用Selenium或Playwright这类无头浏览器去“打开页面”等渲染完成后直接读取DOM节点。这种方式最麻烦、性能最差只在接口方案完全不可用时才选。我之前做过一次热门视频趋势采集第一版直接用了页面解析跑了两个小时后发现某个字段解析错误——因为前端加了个小图标导致CSS选择器偏移。后来切到接口方案十几行代码拿到同样的数据还更稳定。这就是“接口优先”的意义。2.3 架构设计模块解耦别写成一坨不要一上来就写一个几百行的脚本。哪怕只是练手也应该按下面这几个模块去拆分代码采集任务调度器什么时候采、采什么 | v 请求模块发送HTTP请求处理重试和异常 | v 解析模块把JSON或HTML转成结构化数据 | v 存储模块去重、落库 | v 告警与日志出了什么问题能第一时间看到模块化最大的好处是可替换。比如你发现某个接口挂了只需要在请求模块里换一个新的接口地址解析模块完全不用动如果你想从单机爬虫升级成分布式只需要把调度器独立出来把URL队列放到Redis里其他模块基本都能复用。3. 核心模块拆解每个环节的细节和坑3.1 请求模块模拟得像一个真实用户这是整个爬虫里技术含量相对高、也最容易“劝退”新人的部分。B站的反爬策略并不算最狠但绝对不傻。它的限制理念很明确允许你正常访问但不允许你用机器的节奏访问。请求头Headers是第一道关卡。至少要带上User-Agent用户代理、Referer来源页面和Origin。B站对Referer检查比较严格很多接口在请求时如果没带Referer: https://www.bilibili.com/会直接返回412错误。这个东西踩过的人都知道写接口爬虫时第一件事就是把浏览器请求头完整复制过来。Cookie是第二道关卡。B站的很多接口要求登录态哪怕只是游客登录。最简单的办法是用浏览器登录B站然后在开发者工具里复制Cookie粘贴到代码中。但要注意Cookie是会过期的而且频繁使用同一个账号可能触发风险控制。更好的做法是用requests.Session()对象自动管理Cookie必要时配合验证码识别方案处理登录但这一步涉及较高风险建议把采集范围限定在无需登录的公开数据上。超时与重试是第三道关卡。网络请求不可能永远成功必须做好异常处理。我在项目里一般是这么写的import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def create_session(): session requests.Session() retries Retry( total3, backoff_factor0.5, status_forcelist[500, 502, 503, 504], allowed_methods[GET] ) adapter HTTPAdapter(max_retriesretries) session.mount(https://, adapter) session.mount(http://, adapter) return session这里最重要的是backoff_factor——重试之间要有退避间隔否则相当于在告诉对方“我是一台失控的机器”反而更容易被当成攻击流量。3.2 解析模块JSON有标准写法HTML是玄学B站90%的接口都返回JSON这简直是爬虫爱好者的福音。解析JSON没什么好说的data字段就是核心内容关键是要弄清嵌套结构。我的习惯是拿到接口响应后先用json.dumps(..., ensure_asciiFalse, indent2)格式化打印一遍人眼扫一遍结构再去写解析代码比边写边猜效率高得多。但如果遇到必须解析HTML的情况就要注意几个实操细节了。第一优先使用CSS选择器而不是XPath因为B站前端改版时CSS的class名更换频率比id低一些第二批量提取时用BeautifulSoup的find_all再逐条处理比每条单独find更高效第三永远不要在select之后不做空值判断就直接取[0]页面结构一改就是IndexError。3.3 存储模块别一上来就上数据库很多人学完爬虫第一反应是“我要用MySQL”其实完全没必要。数据量在百万条以内、字段相对固定的话存成CSV或JSON Lines每行一个JSON对象就是最好的方案。轻量、可读、方便后续用Pandas做分析。当然如果数据量会持续增长或者你自己就想练练数据库操作那可以选SQLite起步它是文件型数据库不需要安装任何服务端程序。等数据量真的突破千万级再考虑迁移到MySQL或PostgreSQL那时候顺便把分布式采集也上了属于水到渠成的事。数据去重是存储环节最容易忽略的问题。B站的视频有固定的bvid如BV1xx411c7mD作为唯一标识存储时把它设为唯一索引就能天然避免重复入库。评论有rpid用户有mid弹幕有dmid每个实体都有主键必须利用起来。这是你判断爬虫质量的一个关键指标去过重和没去重的项目后期分析效果完全不同。3.4 调度模块控制节奏比控制代码更重要调度器的核心任务有两个一是决定“接下来爬什么”二是决定“什么时候爬”。先说“爬什么”。B站的数据不是靠两个URL就能拿完的而是像树一样展开先从排行榜拿到一批视频ID再根据视频ID去拿对应评论和弹幕再根据评论里的用户ID去拿用户信息……这就是广度和深度的平衡问题。我的经验是“横向优先”先拿全一个时间段的排行榜数据再从中抽取一部分视频深挖评论这样既有完整的全貌又有深度的样本。再说“什么时候爬”。这里有个关键概念叫请求间隔。合理的间隔没有统一标准取决于数据量、对方限流策略和你的风险承受能力。我自己的基准线是同一个接口两次请求间隔不小于1秒高峰时段动态调用不同接口分散访问。不要觉得慢——一个接口每秒1次一天就是8万多条请求对个人数据分析来说绰绰有余了。另外强烈建议给调度器加一个“随机抖动”。固定间隔很容易被识别为自动化流量而在1.5秒到3秒之间随机取值看起来就和人手动刷网页的节奏接近得多。这不是破解而是让你的程序更像一个正常用户降低对平台的资源消耗和对自身IP的误伤概率。4. 实操演示从0到1搭一个最简单的热门视频采集器4.1 环境准备与目标确认这个环节很简短但必不可少。你需要Python 3.9安装requests和pandas两个库就够了pip install requests pandas我们要做的是采集B站全站热门视频的标题、UP主、播放量、点赞数等基础信息输出成CSV表格。这是市面上几乎所有B站数据分析项目的第一步也是最能练手的一个场景。4.2 找到公开接口并确认参数打开B站首页的热门分区按F12进入开发者工具切到Network面板刷新页面。在请求列表里找到https://api.bilibili.com/x/web-interface/popular这个地址这就是热门视频的接口。在浏览器里直接访问这个接口你会看到类似下面的JSON结构我已简化{ code: 0, message: 0, data: { list: [ { bvid: BV1xx411c7mD, title: 【4K】二十四节气高清壁纸合集, pubdate: 1700000000, owner: { mid: 123456, name: 某UP主 }, stat: { view: 1520000, like: 234000, coin: 45000, favorite: 67000 } } ], has_more: 1 } }code: 0表示请求成功data.list是视频列表数组has_more表示是否还有下一页。这个接口还接受pn页码和ps每页数量最大50两个参数所以我们完全可以用循环拿很多页数据。4.3 编写采集代码并落盘直接上代码这段代码我做过大量类似项目的精简版核心逻辑都在import requests import pandas as pd import time import random HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: https://www.bilibili.com/, Origin: https://www.bilibili.com } def fetch_popular(page_num, page_size50): url https://api.bilibili.com/x/web-interface/popular params { pn: page_num, ps: page_size } resp requests.get(url, paramsparams, headersHEADERS, timeout10) resp.raise_for_status() data resp.json() if data[code] ! 0: print(f接口返回异常: {data[message]}) return [] return data[data][list] def parse_video_item(item): return { bvid: item[bvid], 标题: item[title], UP主: item[owner][name], UP主mid: item[owner][mid], 发布时间: time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(item[pubdate])), 播放量: item[stat][view], 点赞数: item[stat][like], 硬币数: item[stat][coin], 收藏数: item[stat][favorite] } all_data [] for page in range(1, 4): # 先采3页共约150条 print(f正在采集第 {page} 页...) items fetch_popular(page) for item in items: all_data.append(parse_video_item(item)) # 随机停顿1.2~2.8秒别像个机器人 time.sleep(random.uniform(1.2, 2.8)) df pd.DataFrame(all_data) df.to_csv(bilibili_popular.csv, indexFalse, encodingutf-8-sig) print(f采集完成共 {len(df)} 条数据)有几个细节要单独拎出来说。输出CSV时用utf-8-sig而不是utf-8这样用Excel直接打开不会乱码每次请求之间加了随机延迟是我上一节说的“请求节奏”的实际落地解析函数单独写成parse_video_item如果接口字段有变化你只需要改这一个函数不用翻主逻辑。4.4 持续采集与数据积累一次性采集150条数据只是热身真正有价值的数据是“持续积累”出来的。你可以把上面的代码包装成一个函数然后用系统的定时任务Linux的cron或Windows的任务计划程序每天固定时间运行一次生成带日期的CSV文件名。比如filename fbilibili_popular_{time.strftime(%Y%m%d)}.csv这样坚持一个月你就有一份“B站热门视频播放量变化”的时间序列数据可以分析什么类型的内容在增长、哪些UP主在持续上榜、不同分区的热度周期等等。这一步踩过的人都知道持续采集的价值比单次抓取大一个数量级。5. 常见问题与排查技巧实录5.1 接口突然返回412错误这是B站爬虫最出名的拦路虎。412的含义是“Precondition Failed”前置条件不满足通常是因为请求头里缺少Referer或User-Agent不是常见的浏览器版本。排查步骤很固定先确认Referer是不是https://www.bilibili.com/再确认User-Agent是不是最近的浏览器版本不要用老掉牙的IE字符串如果还不行把浏览器里完整的Cookie复制出来带上这招能解决90%的412以上都不行换IP试试但这个话题涉及灰色操作不建议深究。5.2 页面改版导致解析失效网页端接口的字段偶尔会调整最常见的是把字段名从mid改成user_id之类或者把嵌套结构拉平。解决办法只有一个给解析代码加异常监控。解析字段时用item.get(owner, {}).get(mid)而不是item[owner][mid]前者在数据缺失时返回None而不是抛异常配合日志就能迅速定位是哪些视频导致的问题。5.3 采集到一半被限流症状一般是前几十个请求正常之后所有请求都返回-412或超时。这是一种基于频率的临时限制一般几分钟到半小时内自动恢复。应对思路是“降速”而不是“对抗”。把请求间隔从1秒提升到3到5秒单次任务采集量降低任务分散到不同时间段执行。看起来效率低了但拉长到一周的维度总产量反而更高——因为你的采集器不会被封能持续稳定运行。这是我做了多年爬虫项目的核心心得稳定压倒速度。5.4 弹幕和评论接口的额外限制弹幕和评论区的接口比视频接口要“敏感”一些因为它们涉及用户生成内容和社交关系链。B站对这些接口的频率限制更严格而且部分评论接口需要登录Cookie。处理思路是把评论和弹幕的采集频率降得更低比如同一个视频的评论每页间隔3秒以上选择用户浓度低的时段凌晨4点到上午8点跑采集任务采集用户UID时只在评论里取不要另行高频请求用户详情接口。对于个人分析来说数据量小一点没关系重要的是连续性和稳定性。5.5 数据量一大程序就卡死单线程爬虫在上千条数据后往往会变慢不是因为网速而是因为所有的解析和存储都在一个进程里排队执行。两个优化办法第一个是多线程采集对不同的接口或页面开3到5个线程并行获取然后用队列把数据汇总到统一的存储线程。Python的concurrent.futures.ThreadPoolExecutor足够用不需要上复杂的异步框架。第二个是分批落盘不要等全部采集完再一次性写入而是每采集100条就追加写入一次文件。这样即使程序中途崩溃已采集的数据也完整保存着不至于白跑。6. 项目扩展方向从采集到数据分析的完整链路6.1 本项目的合理扩展场景当采集器稳定运行后数据本身就会开始“暗示”你该做什么了。我自己经历过的几个从爬虫自然过渡到分析项目的方向可以提供参考排行榜趋势分析每天定时采集全站热门和分区热门的视频列表把播放量、点赞量、收藏量做成时间序列能直观看到哪些内容是“爆发式增长”哪些是“长尾常青”。配合发布时间字段还能分析一个UP主的商业化节奏。弹幕情绪分析选一个正在热播的番剧或热门视频持续采集弹幕文本用简单的关键词匹配或更复杂的SnowNLP做情绪判断就能画出整集内容的情感波动曲线。这个在很多视频二创作品中都有应用。UP主运营周期分析通过用户公开的投稿列表统计每个UP主的投稿频率、播放中位数、涨粉周期能识别出哪些UP主正处于成长红利期对于品牌方或MCN来说是很有价值的公开情报。这些方向都不需要额外的爬虫技术核心工作量在数据处理和分析上但数据源恰恰是最难打通的环节——你手里的稳定采集器就是最大的先发优势。6.2 技术栈升级的推荐路径如果想让这个项目继续成长为一个“作品级”项目有两条不同的升级路径一条是数据工程方向把存储换成MySQL或MongoDB引入Redis作为URL去重队列再把调度器改造成非阻塞的异步任务用Celery或APScheduler最后加一个简单的Web界面展示采集状态。这条路走完你就具备了一个初级数据工程师的基本能力。另一条是数据分析方向把采集到的数据清洗后导入Pandas或数据可视化工具比如ECharts做出一份带交互图表的分析报告或者训练一个简单的推荐模型比如基于你收藏历史的相似视频推荐。这条路走完你的作品集里就有了一份“数据采集→清洗→可视化→建模”的完整案例。两条路径不冲突我自己是先走的数据工程后补的数据分析因为有了稳定可靠的数据管道分析起来才会得心应手。6.3 给新手的最后建议如果你是第一次做爬虫项目不要贪多求全。把上面第4节的代码跑通连续采集一周再把结果导入Excel随便做张图表这已经超过了80%的爬虫新手了。下一步再考虑加评论、弹幕、用户信息这些模块。如果你已经有一定经验我的建议是逆向思维先想清楚你想回答什么问题再反推需要哪些数据。比如“B站最近一个月涨粉最快的知识区UP主有哪些”——这个问题会自然告诉你需要采集榜单、视频元数据、UP主信息三个数据源以及需要至少一个月的连续采集。以问题为起点项目的边界和架构都会清晰很多。最后再分享一个多年的实操习惯每次跑完采集任务后把返回的数据条数、采集耗时、失败率这三个指标记录下来。时间长了你会形成对自己采集器健康状况的直觉判断一旦指标偏离基线立刻知道是平台改版了、接口失效了还是网络出了问题。这种“运维意识”是普通爬虫代码和成熟数据项目之间最明显的差距。
返回列表