8163c37e83
- 删除 bilibili_extractor.py 及相关文档和配置 - 删除 bilibili_venv 虚拟环境 - 删除测试脚本和生成的B站笔记 - 以后使用 skills/obsidian-kb 提供的B站提取功能
234 lines
6.4 KiB
Markdown
234 lines
6.4 KiB
Markdown
# B站提取器实现 - Checkpoint 3 完成报告
|
||
|
||
## 任务完成情况
|
||
|
||
✅ 所有任务已完成
|
||
|
||
## 实现的功能
|
||
|
||
### 1. 创建了 B站提取器类
|
||
- 文件路径:`/home/admin/.openclaw/workspace/skills/obsidian-kb/src/extractors/bilibili_extractor.py`
|
||
- 继承自 `src/extractors/base.py` 的 `Extractor` 基类
|
||
- 实现了 `extract(source_id: str)` 方法,返回字典结构
|
||
|
||
### 2. 核心功能实现
|
||
|
||
#### 输入格式支持
|
||
- ✅ BV号:`BV1MnFNz5EDL`
|
||
- ✅ 完整URL:`https://www.bilibili.com/video/BV1MnFNz5EDL`
|
||
- ✅ 短链接:`https://b23.tv/xxx`(框架已实现,需额外解析)
|
||
|
||
#### 返回数据结构
|
||
```python
|
||
{
|
||
'metadata': {
|
||
'title': '视频标题',
|
||
'author': 'UP主名称',
|
||
'bvid': 'BV号',
|
||
'aid': 'AV号',
|
||
'duration': '12:38',
|
||
'pubtime': '2026-02-02 17:49:13',
|
||
'tags': '标签列表',
|
||
'mid': 'UP主ID',
|
||
},
|
||
'stats': {
|
||
'view': 播放量,
|
||
'like': 点赞数,
|
||
'coin': 投币数,
|
||
'favorite': 收藏数,
|
||
'share': 分享数,
|
||
'danmaku': 弹幕数,
|
||
'reply': 评论数,
|
||
},
|
||
'subtitle': '字幕内容(如果有)',
|
||
'description': '视频描述',
|
||
}
|
||
```
|
||
|
||
#### 配置支持
|
||
- ✅ 使用配置中的 `bilibili_headless`(默认 True)
|
||
- ✅ 使用配置中的 `bilibili_timeout`(默认 30 秒)
|
||
|
||
### 3. 提取策略
|
||
|
||
采用双策略提取方案:
|
||
|
||
1. **API优先策略**(推荐)
|
||
- 直接调用 B站 API:`https://api.bilibili.com/x/web-interface/view`
|
||
- 优点:快速、稳定、资源消耗少
|
||
- 缺点:可能受 API 限制影响
|
||
|
||
2. **页面备用策略**
|
||
- 使用 Playwright 访问完整页面
|
||
- 支持多种提取方法:
|
||
- JavaScript 变量提取(`window.__INITIAL_STATE__`)
|
||
- HTML 元素提取
|
||
- API 回退
|
||
- 支持 stealth 模式(可配置)
|
||
|
||
### 4. Playwright 集成
|
||
|
||
- 使用 Playwright 的 `async_api` 实现异步操作
|
||
- 支持无头模式(headless)和有头模式
|
||
- 配置了反检测参数(User-Agent、Referer、Locale 等)
|
||
- 可选 stealth 模式(使用 `undetected-playwright`)
|
||
|
||
## 测试结果
|
||
|
||
### 测试用例
|
||
|
||
使用真实视频 BV号 `BV1MnFNz5EDL` 进行测试:
|
||
|
||
#### 测试 1:BV号格式
|
||
```
|
||
输入: BV1MnFNz5EDL
|
||
结果: ✅ 成功
|
||
```
|
||
|
||
#### 测试 2:完整URL格式
|
||
```
|
||
输入: https://www.bilibili.com/video/BV1MnFNz5EDL
|
||
结果: ✅ 成功
|
||
```
|
||
|
||
### 提取结果示例
|
||
|
||
```json
|
||
{
|
||
"metadata": {
|
||
"title": "【老戴】用了几天 Clawdbot,我最担心的事开始发生了",
|
||
"author": "老戴Donald",
|
||
"bvid": "BV1MnFNz5EDL",
|
||
"aid": 116000406116354,
|
||
"duration": "12:38",
|
||
"pubtime": "2026-02-02 17:49:13",
|
||
"tags": "",
|
||
"mid": 3493075691243699
|
||
},
|
||
"stats": {
|
||
"view": 59074,
|
||
"like": 3292,
|
||
"coin": 2354,
|
||
"favorite": 1692,
|
||
"share": 587,
|
||
"danmaku": 482,
|
||
"reply": 506
|
||
},
|
||
"subtitle": "",
|
||
"description": "用了几天 Clawdbot——是的,它很不稳定,很不成熟,很糙。\n我关注的并不是它能干多少事,而是:\n当未来 AI 的能力和资源不可避免地走向集中,\n数据的主权,还会不会掌握在大众手里。\n如果垄断不可避免,开源可能就是最后的防线。"
|
||
}
|
||
```
|
||
|
||
## 代码关键部分
|
||
|
||
### 1. 类定义和初始化
|
||
|
||
```python
|
||
class BilibiliExtractor(Extractor):
|
||
"""B站视频信息提取器"""
|
||
|
||
def __init__(self, config=None):
|
||
self.config = config
|
||
self.headless = getattr(config, 'bilibili_headless', True)
|
||
self.timeout = getattr(config, 'bilibili_timeout', 30) * 1000
|
||
```
|
||
|
||
### 2. extract 方法实现
|
||
|
||
```python
|
||
def extract(self, source_id: str) -> Dict[str, Any]:
|
||
"""提取视频信息"""
|
||
try:
|
||
# 解析 source_id 获取 BV 号
|
||
bvid = self._parse_source_id(source_id)
|
||
if not bvid:
|
||
raise ExtractionError(f"无法解析 source_id: {source_id}", source_id)
|
||
|
||
# 运行异步提取
|
||
result = asyncio.run(self._extract_async(bvid))
|
||
|
||
if not result:
|
||
raise ExtractionError(f"提取失败: {source_id}", source_id)
|
||
|
||
return result
|
||
|
||
except ExtractionError:
|
||
raise
|
||
except Exception as e:
|
||
self._handle_error(e, source_id)
|
||
```
|
||
|
||
### 3. 双策略提取
|
||
|
||
```python
|
||
async def _extract_video_info(self, bvid: str) -> Dict[str, Any]:
|
||
# 优先使用 API 方法(更快速、更稳定)
|
||
try:
|
||
video_info = await self._extract_from_api(bvid)
|
||
if video_info and video_info.get('title'):
|
||
print(f"✓ API 提取成功")
|
||
subtitles = await self._extract_subtitles(bvid)
|
||
return self._build_result(video_info, subtitles)
|
||
except Exception as e:
|
||
print(f"API 提取失败,尝试页面提取: {e}")
|
||
|
||
# 如果 API 失败,尝试访问页面
|
||
# ... 页面提取逻辑
|
||
```
|
||
|
||
### 4. source_id 解析
|
||
|
||
```python
|
||
def _parse_source_id(self, source_id: str) -> Optional[str]:
|
||
"""解析 source_id 获取 BV 号"""
|
||
source_id = source_id.strip()
|
||
|
||
# 尝试匹配完整URL
|
||
url_match = self.URL_PATTERN.search(source_id)
|
||
if url_match:
|
||
return url_match.group(1)
|
||
|
||
# 尝试匹配BV号
|
||
bvid_match = self.BVID_PATTERN.search(source_id)
|
||
if bvid_match:
|
||
return bvid_match.group(0)
|
||
|
||
return None
|
||
```
|
||
|
||
## 依赖安装
|
||
|
||
```bash
|
||
# 创建虚拟环境
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate
|
||
|
||
# 安装依赖
|
||
pip install playwright undetected-playwright beautifulsoup4 lxml pyyaml
|
||
|
||
# 安装 Playwright 浏览器
|
||
playwright install chromium
|
||
```
|
||
|
||
## 文件清单
|
||
|
||
1. ✅ `/home/admin/.openclaw/workspace/skills/obsidian-kb/src/extractors/bilibili_extractor.py` - B站提取器实现
|
||
2. ✅ 测试脚本:
|
||
- `test_playwright.py` - Playwright 基本功能测试
|
||
- `test_bilibili_api.py` - B站 API 测试
|
||
- `test_api_only.py` - API 提取测试
|
||
- `simple_test2.py` - 简单提取器测试
|
||
- `complete_test.py` - 完整测试
|
||
|
||
## 后续优化建议
|
||
|
||
1. **短链接解析**:实现 `b23.tv` 短链接解析功能
|
||
2. **字幕提取优化**:处理需要权限的字幕
|
||
3. **错误处理增强**:添加更多异常处理和重试机制
|
||
4. **Stealth 模式**:如需更强的反爬虫能力,可以启用 stealth 模式
|
||
5. **性能优化**:缓存机制、并发请求等
|
||
|
||
## 总结
|
||
|
||
Checkpoint 3 已成功完成!B站提取器已实现并测试通过,可以正常提取视频元数据、统计数据和描述信息。采用 API 优先策略,速度快且稳定;同时保留页面备用策略,确保可靠性。
|