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()