#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 测试 B站 API 获取视频流 """ import asyncio import json from playwright.async_api import async_playwright async def test_video_stream(bvid): """测试获取视频流""" url = f"https://www.bilibili.com/video/{bvid}" async with async_playwright() as playwright: browser = await playwright.chromium.launch(headless=True) context = await browser.new_context() page = await context.new_page() print(f"正在测试视频: {url}") print("=" * 80) # 首先获取 aid 和 cid print("\n1. 获取视频基本信息...") try: api_url = "https://api.bilibili.com/x/web-interface/view" response = await page.request.get(api_url, params={'bvid': bvid}) data = await response.json() if data.get('code') == 0: video_data = data.get('data', {}) print(f" 标题: {video_data.get('title')}") aid = video_data.get('aid') cid = video_data.get('cid') print(f" aid: {aid}") print(f" cid: {cid}") else: print(f" ❌ 失败: {data.get('message')}") await browser.close() return except Exception as e: print(f" ❌ 异常: {e}") await browser.close() return # 尝试获取视频流 URL print("\n2. 尝试获取视频流 URL...") try: playurl_api = "https://api.bilibili.com/x/player/wbi/playurl" params = { 'bvid': bvid, 'cid': cid, 'qn': 80, # 清晰度:80=1080P 'fnval': 16, # 包含 DASH 格式 'fnver': 0, 'fourk': 1, } playurl_response = await page.request.get(playurl_api, params=params) print(f" 状态码: {playurl_response.status}") if playurl_response.ok: playurl_data = await playurl_response.json() print(f" 响应码: {playurl_data.get('code')}") if playurl_data.get('code') == 0: play_data = playurl_data.get('data', {}) print(f"\n 数据类型:") print(f" {json.dumps(list(play_data.keys()), indent=4, ensure_ascii=False)}") # 检查 DASH 格式 if 'dash' in play_data: dash = play_data['dash'] print(f"\n DASH 格式:") print(f" duration: {dash.get('duration')}s") print(f" video streams: {len(dash.get('video', []))}") print(f" audio streams: {len(dash.get('audio', []))}") # 显示视频流信息 print(f"\n 视频流列表:") for i, video_stream in enumerate(dash.get('video', [])[:3]): print(f" [{i+1}] id={video_stream.get('id')}, " f"bandwidth={video_stream.get('bandwidth')}, " f"codecs={video_stream.get('codecs')}") print(f" baseUrl: {video_stream.get('baseUrl', '')[:100]}...") print(f" backup_url: {len(video_stream.get('backup_url', []))} 个") # 显示音频流信息 print(f"\n 音频流列表:") for i, audio_stream in enumerate(dash.get('audio', [])[:3]): print(f" [{i+1}] id={audio_stream.get('id')}, " f"bandwidth={audio_stream.get('bandwidth')}, " f"codecs={audio_stream.get('codecs')}") print(f" baseUrl: {audio_stream.get('baseUrl', '')[:100]}...") # 尝试下载一小段测试 if dash.get('video'): first_video = dash['video'][0] base_url = first_video.get('baseUrl', '') if base_url: print(f"\n3. 测试下载视频流...") print(f" URL: {base_url}") # 添加必要的请求头 headers = { 'Referer': 'https://www.bilibili.com/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', } # 只下载前 1KB 测试 test_response = await page.request.get( base_url, headers=headers, timeout=30000 ) print(f" 下载状态: {test_response.status}") if test_response.ok: content_length = len(await test_response.body()) print(f" ✅ 可以下载!获取到 {content_length} 字节") print(f" Content-Type: {test_response.headers.get('content-type')}") else: print(f" ❌ 下载失败") else: print(f" ❌ API 错误: {playurl_data.get('message')}") print(f" 完整响应: {json.dumps(playurl_data, indent=4, ensure_ascii=False)[:500]}") else: print(f" ❌ HTTP 错误: {playurl_response.status}") except Exception as e: print(f" ❌ 异常: {e}") import traceback traceback.print_exc() # 尝试旧版 API print("\n4. 尝试旧版 playurl API...") try: playurl_api = "https://api.bilibili.com/x/player/playurl" params = { 'bvid': bvid, 'cid': cid, 'qn': 80, 'otype': 'json', } playurl_response = await page.request.get(playurl_api, params=params) print(f" 状态码: {playurl_response.status}") if playurl_response.ok: playurl_data = await playurl_response.json() print(f" 响应码: {playurl_data.get('code')}") if playurl_data.get('code') == 0: print(f" ✅ 旧版 API 可用") print(f" 数据: {json.dumps(list(playurl_data.get('data', {}).keys()), indent=4, ensure_ascii=False)}") else: print(f" ❌ API 错误: {playurl_data.get('message')}") except Exception as e: print(f" ❌ 异常: {e}") await browser.close() if __name__ == '__main__': bvid = "BV1KtFzzqEUG" asyncio.run(test_video_stream(bvid))