5507b1d986
- kb-link-parser: Multi-platform URL parser (Bilibili, YouTube, Zhihu) - kb-bilibili-metadata: Bilibili video/article/up主 metadata extractor - kb-zhihu-metadata: Zhihu question/answer/user metadata extractor - kb-bilibili-content: Bilibili video download and content extraction - kb-ocr-processor: OCR text extraction from video frames - kb-deep-analyzer: AI-powered deep content analysis - kb-workflow: Workflow orchestration (inbox, archive, subscriptions, report) Also add: - ARCHITECTURE_FLOWCHART.md: System architecture diagrams - DETAILED_DESIGN.md: Complete design documentation
151 lines
4.0 KiB
Python
Executable File
151 lines
4.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
B站元数据提取 CLI 工具
|
||
|
||
支持命令行调用,输出 JSON 格式数据
|
||
"""
|
||
|
||
import argparse
|
||
import json
|
||
import sys
|
||
from typing import Dict, Any
|
||
|
||
from bilibili_extractor import BilibiliExtractor
|
||
|
||
|
||
def format_number(num: int) -> str:
|
||
"""格式化数字"""
|
||
if num >= 100000000:
|
||
return f"{num / 100000000:.1f}亿"
|
||
elif num >= 10000:
|
||
return f"{num / 10000:.1f}万"
|
||
else:
|
||
return f"{num:,}"
|
||
|
||
|
||
def extract_video(extractor: BilibiliExtractor, bvid: str, output_file: str = None) -> Dict[str, Any]:
|
||
"""提取视频元数据"""
|
||
result = extractor.extract_video_metadata(bvid)
|
||
|
||
# 如果需要输出到文件
|
||
if output_file:
|
||
with open(output_file, 'w', encoding='utf-8') as f:
|
||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||
|
||
return result
|
||
|
||
|
||
def extract_article(extractor: BilibiliExtractor, cvid: str, output_file: str = None) -> Dict[str, Any]:
|
||
"""提取专栏元数据"""
|
||
result = extractor.extract_article_metadata(cvid)
|
||
|
||
if output_file:
|
||
with open(output_file, 'w', encoding='utf-8') as f:
|
||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||
|
||
return result
|
||
|
||
|
||
def extract_up(extractor: BilibiliExtractor, mid: str, output_file: str = None) -> Dict[str, Any]:
|
||
"""提取UP主信息"""
|
||
result = extractor.extract_up_metadata(mid)
|
||
|
||
if output_file:
|
||
with open(output_file, 'w', encoding='utf-8') as f:
|
||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||
|
||
return result
|
||
|
||
|
||
def main():
|
||
"""主函数"""
|
||
parser = argparse.ArgumentParser(
|
||
description='B站元数据提取工具',
|
||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||
epilog="""
|
||
示例:
|
||
# 提取视频元数据
|
||
python bilibili_metadata.py --id "BV1xx411c7mD" --type video
|
||
|
||
# 提取专栏元数据
|
||
python bilibili_metadata.py --id "cv43780186" --type article
|
||
|
||
# 提取UP主信息
|
||
python bilibili_metadata.py --id "7770724" --type up
|
||
|
||
# 输出到文件
|
||
python bilibili_metadata.py --id "BV1xx411c7mD" --type video --output result.json
|
||
"""
|
||
)
|
||
|
||
parser.add_argument(
|
||
'--id',
|
||
required=True,
|
||
help='B站资源ID(BV号、CV号或UP主ID)'
|
||
)
|
||
parser.add_argument(
|
||
'--type',
|
||
required=True,
|
||
choices=['video', 'article', 'up'],
|
||
help='资源类型'
|
||
)
|
||
parser.add_argument(
|
||
'--output',
|
||
'-o',
|
||
help='输出文件路径(JSON格式)'
|
||
)
|
||
parser.add_argument(
|
||
'--headless',
|
||
action='store_true',
|
||
default=True,
|
||
help='使用无头模式(浏览器,默认开启)'
|
||
)
|
||
parser.add_argument(
|
||
'--timeout',
|
||
type=int,
|
||
default=30,
|
||
help='超时时间(秒,默认30)'
|
||
)
|
||
parser.add_argument(
|
||
'--pretty',
|
||
action='store_true',
|
||
default=True,
|
||
help='格式化输出(默认开启)'
|
||
)
|
||
|
||
args = parser.parse_args()
|
||
|
||
# 创建提取器
|
||
extractor = BilibiliExtractor(headless=args.headless, timeout=args.timeout)
|
||
|
||
try:
|
||
# 根据类型提取数据
|
||
if args.type == 'video':
|
||
result = extract_video(extractor, args.id, args.output)
|
||
elif args.type == 'article':
|
||
result = extract_article(extractor, args.id, args.output)
|
||
elif args.type == 'up':
|
||
result = extract_up(extractor, args.id, args.output)
|
||
else:
|
||
print(f"错误: 不支持的类型 {args.type}")
|
||
sys.exit(1)
|
||
|
||
# 输出结果
|
||
if not args.output:
|
||
if args.pretty:
|
||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||
else:
|
||
print(json.dumps(result, ensure_ascii=False))
|
||
|
||
if args.output:
|
||
print(f"结果已保存到: {args.output}")
|
||
|
||
except Exception as e:
|
||
print(f"错误: {e}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|