#!/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_subtitle_api(bvid): """测试字幕API""" 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("正在访问页面...") await page.goto(url, wait_until='networkidle', timeout=60000) await asyncio.sleep(3) # 方法1: 检查 __INITIAL_STATE__ 是否存在 print("\n=== 测试方法1: 检查 __INITIAL_STATE__ 结构 ===") try: initial_state = await page.evaluate('() => window.__INITIAL_STATE__') if initial_state: print(f"__INITIAL_STATE__ keys: {list(initial_state.keys())}") video_data = initial_state.get('videoData', {}) print(f"videoData keys: {list(video_data.keys())}") print(f"aid: {video_data.get('aid')}") print(f"cid: {video_data.get('cid')}") else: print("__INITIAL_STATE__ 不存在") except Exception as e: print(f"方法1失败: {e}") # 方法2: 从 HTML 中提取 print("\n=== 测试方法2: 从 HTML script 标签提取 ===") try: content = await page.content() soup = BeautifulSoup(content, 'lxml') script_tags = soup.find_all('script') for script in script_tags: if script.string and '__INITIAL_STATE__' in script.string: match = re.search(r'window\.__INITIAL_STATE__\s*=\s*({.+?});', script.string) if match: data = json.loads(match.group(1)) video_data = data.get('videoData', {}) print(f"aid: {video_data.get('aid')}") print(f"cid: {video_data.get('cid')}") print(f"subtitle: {video_data.get('subtitle')}") # 如果找到了 cid,尝试获取字幕 cid = video_data.get('cid') if cid: await test_subtitle_api_with_cid(page, bvid, cid) break except Exception as e: print(f"方法2失败: {e}") # 方法3: 使用 API 获取视频信息 print("\n=== 测试方法3: 使用 API 获取视频信息 ===") 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"aid: {video_data.get('aid')}") print(f"cid: {video_data.get('cid')}") print(f"title: {video_data.get('title')}") cid = video_data.get('cid') if cid: await test_subtitle_api_with_cid(page, bvid, cid) except Exception as e: print(f"方法3失败: {e}") await browser.close() async def test_subtitle_api_with_cid(page, bvid, cid): """使用 cid 测试字幕 API""" print(f"\n=== 使用 cid={cid} 获取字幕 ===") try: api_url = "https://api.bilibili.com/x/player/v2" response = await page.request.get(api_url, params={'bvid': bvid, 'cid': cid}) data = await response.json() print(f"Response code: {data.get('code')}") if data.get('code') == 0: player_data = data.get('data', {}) subtitle_info = player_data.get('subtitle', {}) print(f"Subtitle info:") print(f" allow_submit: {subtitle_info.get('allow_submit')}") print(f" subtitles count: {len(subtitle_info.get('subtitles', []))}") subtitles_list = subtitle_info.get('subtitles', []) if subtitles_list: print(f"\nFound {len(subtitles_list)} subtitles:") for i, sub in enumerate(subtitles_list[:3]): print(f" [{i+1}] {sub.get('id')} - {sub.get('lan_doc')}") # 获取第一个字幕内容 subtitle_url = subtitles_list[0].get('subtitle_url', '') print(f"\nFetching subtitle from: {subtitle_url}") full_url = f"https:{subtitle_url}" response = await page.request.get(full_url) if response.ok: sub_data = await response.json() print(f"First 3 subtitle items:") for i, item in enumerate(sub_data.get('body', [])[:3]): print(f" [{i+1}] [{item.get('from')} - {item.get('to')}] {item.get('content')}") else: print(f"Failed to fetch subtitle: {response.status}") else: print("No subtitles found") else: print(f"API error: {data.get('message')}") except Exception as e: print(f"Failed: {e}") if __name__ == '__main__': # 测试一个有字幕的视频 bvid = "BV1MnFNz5EDL" asyncio.run(test_subtitle_api(bvid))