e0a2b323d9
- obsidian-kb: Add OCR processors (easyocr, tesseract) - obsidian-kb: Fix subtitle detection with test files - obsidian-kb: Add cookie verification script - Add find-skills skill for discovering capabilities - Add video processing scripts - Update clawhub lock file
220 lines
9.8 KiB
Python
220 lines
9.8 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
深度测试B站字幕提取 - 尝试所有可能的方法
|
|
"""
|
|
import asyncio
|
|
import json
|
|
import re
|
|
from playwright.async_api import async_playwright
|
|
from bs4 import BeautifulSoup
|
|
|
|
async def test_all_methods(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)
|
|
|
|
# 等待页面完全加载
|
|
print("\n1. 访问页面...")
|
|
await page.goto(url, wait_until='networkidle', timeout=60000)
|
|
await asyncio.sleep(3)
|
|
|
|
# 获取基本信息
|
|
print("\n2. 获取视频基本信息...")
|
|
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')}")
|
|
print(f" aid: {video_data.get('aid')}")
|
|
print(f" cid: {video_data.get('cid')}")
|
|
cid = video_data.get('cid')
|
|
aid = video_data.get('aid')
|
|
else:
|
|
print(f" ❌ 获取基本信息失败: {data.get('message')}")
|
|
await browser.close()
|
|
return
|
|
except Exception as e:
|
|
print(f" ❌ 异常: {e}")
|
|
await browser.close()
|
|
return
|
|
|
|
# 方法1: 使用标准 API(官方 CC 字幕)
|
|
print("\n3. 方法1: 官方 CC 字幕 API...")
|
|
try:
|
|
player_url = "https://api.bilibili.com/x/player/v2"
|
|
player_response = await page.request.get(player_url, params={'bvid': bvid, 'cid': cid})
|
|
player_data = await player_response.json()
|
|
|
|
if player_data.get('code') == 0:
|
|
subtitle_info = player_data.get('data', {}).get('subtitle', {})
|
|
subtitles_list = subtitle_info.get('subtitles', [])
|
|
|
|
if subtitles_list:
|
|
print(f" ✅ 找到 {len(subtitles_list)} 个官方字幕")
|
|
for i, sub in enumerate(subtitles_list):
|
|
print(f" [{i+1}] {sub.get('lan_doc')} (id={sub.get('id')})")
|
|
|
|
# 获取第一个字幕内容
|
|
subtitle_url = subtitles_list[0].get('subtitle_url', '')
|
|
if subtitle_url:
|
|
full_url = f"https:{subtitle_url}"
|
|
print(f" URL: {subtitle_url}")
|
|
sub_response = await page.request.get(full_url)
|
|
if sub_response.ok:
|
|
sub_data = await sub_response.json()
|
|
body = sub_data.get('body', [])
|
|
print(f" ✅ 获取成功,共 {len(body)} 条字幕")
|
|
print(f" 示例: {body[0] if body else '无'}")
|
|
else:
|
|
print(" ❌ 没有找到官方 CC 字幕")
|
|
print(f" Subtitle info: {json.dumps(subtitle_info, indent=8, ensure_ascii=False)}")
|
|
except Exception as e:
|
|
print(f" ❌ 异常: {e}")
|
|
|
|
# 方法2: 尝试 AI 字幕 API
|
|
print("\n4. 方法2: AI 自动生成字幕...")
|
|
try:
|
|
# B站 AI 字幕可能在另一个 API
|
|
ai_subtitle_url = "https://api.bilibili.com/x/player/wbi/v2/playurl"
|
|
# 这个通常用于视频流,但也可能包含字幕信息
|
|
ai_params = {
|
|
'bvid': bvid,
|
|
'cid': cid,
|
|
'qn': 80, # 清晰度
|
|
'fnval': 16, # 包含字幕的标志
|
|
}
|
|
ai_response = await page.request.get(ai_subtitle_url, params=ai_params)
|
|
ai_data = await ai_response.json()
|
|
|
|
if ai_data.get('code') == 0:
|
|
print(f" AI API 响应: {json.dumps(list(ai_data.get('data', {}).keys()), indent=8, ensure_ascii=False)}")
|
|
|
|
# 检查是否有字幕信息
|
|
if 'subtitle' in ai_data.get('data', {}):
|
|
subtitle = ai_data['data']['subtitle']
|
|
print(f" ✅ 找到 AI 字幕信息")
|
|
print(f" {json.dumps(subtitle, indent=8, ensure_ascii=False)}")
|
|
except Exception as e:
|
|
print(f" ❌ 异常: {e}")
|
|
|
|
# 方法3: 从页面脚本标签中提取(可能包含字幕配置)
|
|
print("\n5. 方法3: 从页面 HTML 中提取字幕配置...")
|
|
try:
|
|
content = await page.content()
|
|
soup = BeautifulSoup(content, 'lxml')
|
|
script_tags = soup.find_all('script')
|
|
|
|
found_subtitle = False
|
|
for script in script_tags:
|
|
if script.string and ('subtitle' in script.string or 'cc_subtitle' in script.string):
|
|
# 提取包含字幕配置的 JSON
|
|
matches = re.findall(r'window\.__(?:playinfo|INITIAL_STATE|subtitle__)\s*=\s*({.+?});', script.string)
|
|
for match in matches:
|
|
try:
|
|
data = json.loads(match)
|
|
# 查找字幕相关字段
|
|
if 'subtitle' in str(data) or 'subtitles' in str(data):
|
|
print(f" ✅ 找到字幕配置")
|
|
print(f" {json.dumps(data, indent=8, ensure_ascii=False)[:500]}")
|
|
found_subtitle = True
|
|
break
|
|
except:
|
|
pass
|
|
if found_subtitle:
|
|
break
|
|
|
|
if not found_subtitle:
|
|
print(" ❌ 页面中没有找到字幕配置")
|
|
except Exception as e:
|
|
print(f" ❌ 异常: {e}")
|
|
|
|
# 方法4: 尝试不同的播放器 API 端点
|
|
print("\n6. 方法4: 尝试其他 API 端点...")
|
|
endpoints = [
|
|
f"https://api.bilibili.com/x/player/wbi/v2/player?bvid={bvid}&cid={cid}",
|
|
f"https://api.bilibili.com/x/player/v2?bvid={bvid}&cid={cid}",
|
|
f"https://api.bilibili.com/x/player/playurl?bvid={bvid}&cid={cid}&qn=80&fnval=16",
|
|
]
|
|
|
|
for endpoint in endpoints:
|
|
try:
|
|
print(f" 测试: {endpoint}")
|
|
response = await page.request.get(endpoint)
|
|
if response.ok:
|
|
data = await response.json()
|
|
# 检查响应中是否有字幕信息
|
|
json_str = json.dumps(data, ensure_ascii=False)
|
|
if 'subtitle' in json_str.lower():
|
|
print(f" ✅ 可能包含字幕信息")
|
|
# 只显示相关部分
|
|
if 'data' in data and 'subtitle' in str(data['data']):
|
|
print(f" {json.dumps(data.get('data', {}).get('subtitle', {}), indent=12, ensure_ascii=False)}[:500]")
|
|
else:
|
|
print(f" 状态码: {response.status}")
|
|
except Exception as e:
|
|
print(f" 异常: {e}")
|
|
|
|
# 方法5: 尝试使用 aid 而不是 cid
|
|
print("\n7. 方法5: 尝试使用 aid 参数...")
|
|
try:
|
|
if aid:
|
|
player_url = "https://api.bilibili.com/x/player/v2"
|
|
response = await page.request.get(player_url, params={'aid': aid, 'bvid': bvid})
|
|
data = await response.json()
|
|
print(f" 响应码: {data.get('code')}")
|
|
if data.get('code') == 0:
|
|
subtitle_info = data.get('data', {}).get('subtitle', {})
|
|
subtitles_list = subtitle_info.get('subtitles', [])
|
|
if subtitles_list:
|
|
print(f" ✅ 使用 aid 找到 {len(subtitles_list)} 个字幕")
|
|
else:
|
|
print(f" ❌ 使用 aid 也没有找到字幕")
|
|
except Exception as e:
|
|
print(f" ❌ 异常: {e}")
|
|
|
|
# 方法6: 检查视频是否有多 P(分集)
|
|
print("\n8. 方法6: 检查是否为分集视频...")
|
|
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:
|
|
pages = data.get('data', {}).get('pages', [])
|
|
print(f" 共 {len(pages)} 个分集")
|
|
for i, p in enumerate(pages):
|
|
print(f" [{i+1}] cid={p.get('cid')}, page={p.get('page')}, title={p.get('part')}")
|
|
|
|
# 如果有多个分集,尝试每个分集的字幕
|
|
if len(pages) > 1:
|
|
print(f"\n 尝试获取第1个分集的字幕...")
|
|
first_cid = pages[0].get('cid')
|
|
player_url = "https://api.bilibili.com/x/player/v2"
|
|
response = await page.request.get(player_url, params={'bvid': bvid, 'cid': first_cid})
|
|
data = await response.json()
|
|
subtitle_info = data.get('data', {}).get('subtitle', {})
|
|
subtitles_list = subtitle_info.get('subtitles', [])
|
|
if subtitles_list:
|
|
print(f" ✅ 第1个分集有 {len(subtitles_list)} 个字幕")
|
|
else:
|
|
print(f" ❌ 第1个分集也没有字幕")
|
|
except Exception as e:
|
|
print(f" ❌ 异常: {e}")
|
|
|
|
await browser.close()
|
|
|
|
if __name__ == '__main__':
|
|
bvid = "BV1KtFzzqEUG"
|
|
asyncio.run(test_all_methods(bvid))
|