批量下载b站番剧弹幕

查看 75|回复 9
作者:罗木魄   
用油猴脚本一集一集的下载b站的弹幕太麻烦了,索性用ai写了一个输入ss号下载每一集弹幕的Python脚本
ss号就是这种链接中ss后面的数字,搜索到想看番剧后,直接点“立即观看”进去,就能看到有ss号的链接


wechat_2025-08-18_192507_124.png (4.1 KB, 下载次数: 1)
下载附件
b站迷宫饭链接
2025-8-18 19:25 上传

[Python] 纯文本查看 复制代码import requests
import os
import time
def get_episode_info(season_id):
    """根据ss号(season_id)获取番剧所有剧集的信息"""
    api_url = f"https://api.bilibili.com/pgc/web/season/section?season_id={season_id}"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/116.0.0.0",
        "Referer": f"https://www.bilibili.com/bangumi/play/ss{season_id}"
    }
   
    try:
        response = requests.get(api_url, headers=headers)
        response.raise_for_status()
        data = response.json()
        
        if data.get("code") != 0:
            print(f"API请求失败: {data.get('message', '未知错误')}")
            return []
        
        result_data = data.get("result", {})
        episode_list = []
        
        # 解析分节和剧集信息
        sections = result_data.get("sections", [])
        
        # 如果sections为空,尝试main_section
        if not sections and "main_section" in result_data:
            main_section = result_data["main_section"]
            sections = [main_section] if isinstance(main_section, dict) else main_section
        
        # 解析每集信息
        for section in sections:
            if not isinstance(section, dict):
                continue
               
            episodes = section.get("episodes", [])
            for episode in episodes:
                ep_id = episode.get("id")
                aid = episode.get("aid")
                cid = episode.get("cid")
                title = episode.get("title")
                if ep_id:
                    play_url = f"https://www.bilibili.com/bangumi/play/ep{ep_id}"
                    episode_list.append({
                        "ep_id": ep_id,
                        "aid": aid,
                        "cid": cid,
                        "url": play_url,
                        "title": title
                    })
        
        return episode_list
   
    except Exception as e:
        print(f"获取剧集信息失败: {e}")
        return []
def get_cid_from_ep(ep_id):
    """通过ep_id获取番剧单集的cid"""
    url = f"https://api.bilibili.com/pgc/view/web/season?ep_id={ep_id}"
    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/"
    }
   
    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        data = response.json()
        
        if data.get("code") == 0:
            # 获取当前季所有剧集
            episodes = data.get("result", {}).get("episodes", [])
            # 遍历找到与当前ep_id匹配的剧集
            for episode in episodes:
                if str(episode.get("id")) == str(ep_id):
                    return episode.get("cid")
            
            print(f"未找到ep_id为{ep_id}的剧集信息")
            return None
        else:
            print(f"获取cid失败: {data.get('message')}")
            return None
    except Exception as e:
        print(f"获取cid时发生错误: {e}")
        return None
def get_cid_from_aid(aid):
    """通过aid获取普通视频的cid"""
    url = f"https://api.bilibili.com/x/web-interface/view?aid={aid}"
    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/"
    }
   
    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        data = response.json()
        
        if data.get("code") == 0:
            return data.get("data", {}).get("cid")
        else:
            print(f"获取cid失败: {data.get('message')}")
            return None
    except Exception as e:
        print(f"获取cid时发生错误: {e}")
        return None
def get_danmaku(cid):
    """通过cid获取弹幕XML数据"""
    url = f"https://comment.bilibili.com/{cid}.xml"
    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/"
    }
   
    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        response.encoding = "utf-8"
        return response.text
    except Exception as e:
        print(f"获取弹幕时发生错误: {e}")
        return None
def save_danmaku(danmaku_xml, filename):
    """保存弹幕为XML文件"""
    try:
        with open(filename, "w", encoding="utf-8") as f:
            f.write(danmaku_xml)
        print(f"弹幕已保存到: {filename}")
        return True
    except Exception as e:
        print(f"保存弹幕失败: {e}")
        return False
def download_episode_danmaku(episode, index, save_dir="danmaku"):
    """下载单集的弹幕"""
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
   
    ep_id = episode["ep_id"]
    cid = episode["cid"]
    title = episode["title"]
    url = episode["url"]
   
    print(f"\n处理第{index}集: {title} (ep_id: {ep_id})")
    print(f"视频地址: {url}")
   
    # 如果获取剧集信息时已经拿到cid,就直接使用
    if not cid:
        print("未从剧集信息中获取到cid,尝试通过ep_id获取...")
        cid = get_cid_from_ep(ep_id)
   
    if not cid:
        print("未获取到有效的cid,无法下载弹幕")
        return False
   
    print(f"获取到cid: {cid}")
    time.sleep(3)  # 避免请求过于频繁
   
    danmaku_xml = get_danmaku(cid)
    if danmaku_xml:
        # 使用两位数编号作为文件名
        filename = os.path.join(save_dir, f"{index:02d}.xml")
        return save_danmaku(danmaku_xml, filename)
    else:
        print("未获取到弹幕数据")
        return False
def main():
    print("B站番剧弹幕批量下载工具")
    print("------------------------")
   
    # 获取用户输入的ss号
    season_id = input("请输入番剧的ss号: ").strip()
   
    # 验证输入是否为数字
    if not season_id.isdigit():
        print("错误:ss号必须是数字")
        return
   
    print(f"正在获取ss{season_id}的剧集信息...")
    episodes = get_episode_info(season_id)
   
    if not episodes:
        print("未获取到任何剧集信息,程序退出")
        return
   
    print(f"成功获取到{len(episodes)}集信息,开始下载弹幕...")
   
    # 逐一下载每集的弹幕
    success_count = 0
    for index, episode in enumerate(episodes, start=1):
        if download_episode_danmaku(episode, index):
            success_count += 1
   
    print(f"\n所有操作完成,成功下载{success_count}/{len(episodes)}集弹幕")
    print(f"弹幕文件保存在 {os.path.abspath('danmaku')} 目录下")
if __name__ == "__main__":
    main()

剧集, 弹幕

stong123   

好用好用
LQ789   

收藏学习,谢谢大佬
bye214   

用了一次挺好用,有意思
提拉米苏子冉   

大佬,能否写个不是番剧的弹幕
Yiqisong   

感谢大佬,这是通用的吗,其他类型的视频能不能用
hanamaru521   

正好需要这种批量下载的,感谢分享
ke6204   

感谢大佬,确实解决了现在下载软件的痛处,试试先
a33300   

太好了,正缺这个东西呢?太感谢楼主了!!!
wushengli   

感谢分享不太会用。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部