Python实战:绕过B站人机校验与验证码,实现视频下载自动化

张开发
2026/4/14 0:19:23 15 分钟阅读

分享文章

Python实战:绕过B站人机校验与验证码,实现视频下载自动化
1. B站视频下载的技术挑战最近在做一个B站视频批量下载的项目时发现平台的反爬机制越来越严格。每次批量下载十几个视频后就会弹出人机校验页面要求输入验证码。更麻烦的是有时候还会遇到视频突然下架的情况。B站的视频下载主要面临两个技术难点一是视频资源地址的获取二是反爬机制的突破。视频资源分为两种格式老式的FLV格式和新式的DASH格式。FLV格式的视频和音频是合并的而DASH格式则是音视频分离的需要分别下载后再合并。我测试过多个视频下载工具发现大多数都无法稳定绕过B站的人机校验。有些工具刚开始能用但用几次就被封了IP。经过反复尝试终于摸索出一套相对稳定的解决方案下面分享具体实现方法。2. 视频地址解析实战2.1 接口分析与请求构造B站的视频接口返回的数据结构比较复杂首先需要通过浏览器开发者工具分析网络请求。在视频播放页按F12打开控制台搜索playinfo关键词可以找到核心的接口响应数据。关键代码示例import requests def get_video_info(bvid): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: fhttps://www.bilibili.com/video/{bvid} } api_url fhttps://api.bilibili.com/x/player/playurl?bvid{bvid}qn80 response requests.get(api_url, headersheaders) return response.json()这个接口返回的数据中data字段包含视频的详细信息。对于DASH格式的视频音视频流是分开的视频流地址playinfo[data][dash][video]音频流地址playinfo[data][dash][audio]而对于老式FLV格式视频地址在playinfo[data][durl]中。实际开发中需要先判断视频格式再分别处理。2.2 清晰度选择与参数解析B站支持多种清晰度对应的quality值如下1080P60帧1161080P80720P64480P32360P16在请求接口时可以通过qn参数指定想要的清晰度。但要注意不是所有视频都支持最高清晰度需要检查接口返回的accept_quality列表。3. 突破人机校验机制3.1 验证码触发条件当下载请求频率过高时B站会返回人机校验页面。我测试发现连续请求10个以上视频就很可能触发验证。验证码有两种形式普通字符数字验证码滑块验证码较少出现关键是要识别出何时触发了验证以及如何自动处理。通过分析网络请求发现验证码相关接口是获取验证码https://sec.bilibili.com/captcha/get提交验证https://sec.bilibili.com/captcha/check3.2 验证码自动识别方案对于字符验证码可以采用OCR技术识别。这里推荐使用百度OCR API准确率较高且稳定。实现代码如下from aip import AipOcr def recognize_captcha(image_base64): 使用百度OCR识别验证码 APP_ID 你的APP_ID API_KEY 你的API_KEY SECRET_KEY 你的SECRET_KEY client AipOcr(APP_ID, API_KEY, SECRET_KEY) result client.basicGeneral(image_base64) return result[words_result][0][words] if result[words_result] else 获取到验证码后需要连同token一起提交到校验接口def submit_captcha(token, code): url https://sec.bilibili.com/captcha/check payload ftoken{token}code{code} headers { Content-Type: application/x-www-form-urlencoded, Referer: https://www.bilibili.com/ } response requests.post(url, headersheaders, datapayload) return response.json()3.3 请求频率控制策略为了避免频繁触发验证码需要控制请求频率。我的经验是单个IP每分钟不超过5次请求每次下载间隔随机2-5秒使用代理IP轮询可以使用time.sleep()添加随机延迟import time import random def random_delay(): time.sleep(random.uniform(2, 5))4. 视频下载与合并4.1 分片下载优化B站的视频经常是分片的特别是高清视频。下载时需要先发送OPTIONS预检请求再发送GET请求获取数据def download_chunk(url, headers): session requests.Session() session.options(url, headersheaders) response session.get(url, headersheaders) return response.content4.2 使用FFmpeg合并音视频对于DASH格式的视频下载完音视频后需要用FFmpeg合并。推荐使用subprocess调用FFmpegimport subprocess def merge_av(video_path, audio_path, output_path): cmd [ ffmpeg, -i, video_path, -i, audio_path, -c:v, copy, -c:a, copy, output_path ] subprocess.run(cmd, checkTrue)4.3 断点续传实现对于大文件下载建议实现断点续传功能。可以通过检查本地文件大小在请求时添加Range头def download_with_resume(url, file_path, headers): if os.path.exists(file_path): downloaded os.path.getsize(file_path) headers[Range] fbytes{downloaded}- else: downloaded 0 response requests.get(url, headersheaders, streamTrue) mode ab if downloaded else wb with open(file_path, mode) as f: for chunk in response.iter_content(1024): f.write(chunk)5. 完整实现与注意事项5.1 项目结构设计一个健壮的下载工具应该包含以下模块视频信息获取模块验证码处理模块下载控制模块文件处理模块日志记录模块5.2 异常处理要点在实际运行中需要特别注意以下异常情况视频下架返回404或提示视频不见了账号被封禁所有请求返回403网络波动导致的下载中断磁盘空间不足5.3 法律与道德考量虽然技术可以实现视频下载但需要注意仅下载个人观看的视频不要大规模爬取侵犯版权尊重平台的服务条款不要将下载内容用于商业用途经过多次迭代优化这套方案已经可以稳定下载B站视频。最关键的是控制好请求频率合理使用OCR服务处理验证码。如果遇到新的反爬机制需要及时调整策略。

更多文章