Files
MediaCrawler/mac-agent-os-main/05_tools/05_crawl/content-inspiration/README.md
T
butubb 2112c1a870
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
移植自 mac-agent-os 的 mediacrawler_adapter:不起子进程、不开页面,用浏览器里那份
登录态直接调抖音 Web 接口。产物键名照抄 store/douyin,所以 ingest 那条链路一个字不用改。

**目前能用的(真环境实测,非推断)**:

    profile/other : 200, 7075 字节  —— 博主主页指标(粉丝/获赞/作品数/昵称)
    aweme/detail  : 200, 45425 字节 —— 单条作品详情(含点赞/评论/收藏/分享)

**目前不能用的:作品列表 `aweme/post`。** 两个互相独立的原因:
  1. 这个接口被抖音单独升级成了真校验:不带 x-tt-argus 回 403「Uifid Not Found」,
     带上 dummy 值回 200 + **空 body**。也就是说「头在不在」骗得过,「真校验」过不了。
     同一套头打 profile/other 和 aweme/detail 都是通的 —— 抖音是挑着接口加保护的,
     挑中的恰好是「批量拉作品列表」这个最敏感的动作。
  2. 改走页面截获也不行:CDP 浏览器打开博主主页会落到「验证码中间页」(当天大量探测的
     代价,过几小时要重测)。

  所以现在的边界是:**已知作品的指标刷新能做,自动发现新作品做不了**。

**排查中控住变量后得到的两条事实**(都写进注释了):
  · `Accept` / `Accept-Language` / `Referer` 才是主页接口能返回真数据的原因 —— 只有
    UA+client hints+Cookie 时是 200 但仅 121 字节的空壳,补上这三个头变 7074 字节。
    (我先前猜的 sec-ch-ua 不是关键。)
  · 因此 UA 与 client hints 必须**成套地取自同一个浏览器**,所以 BrowserIdentity 一次
    从 CDP 取齐 cookie + UA + hints,而不是各自写死。

「200 + 空 body 必须当场报错」也是刻意写死的:放过去它会在下游变成「这个博主没作品」,
把一次失败伪装成一条正常结果 —— 爬虫那条路正是这么栽的,还被翻译成「账号被封」。

测试 +11:cookie 解析、请求头成套性(含 uifid 缺失/回退)、产物键名与 store 对齐、
以及 _get 的三条失败路径(空 body / 403 带网关原话 / 正常返回)。
2026-10-10 17:12:25 +08:00

452 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🎬 口播素材智能采集与分析系统
> 完全本地运行的口播灵感工坊——采集、AI 分析、智能下载、统一检索,隐私安全零成本。
**版本**:v1.0.0
**适用环境**:Mac M1 / 16GB RAM / macOS
**作者**:ghai
**日期**:2026-04-28
---
## 一、这是什么?
一个个人口播创作者的**素材灵感管理系统**。解决的核心问题:
| 痛点 | 解决方案 |
|------|----------|
| 素材散布在抖音/小红书/B站 | 一键采集元数据到本地 SQLite |
| 收藏夹大量 404 | AI 判断价值 → 自动下载到本地 |
| 看标题判断不了口播价值 | 本地 LLM 自动提取金句/情绪/结构 |
| 不想上云、不想付费 | 全部跑在本机,零网络依赖(采集除外) |
**一句话**:搜得到、看得懂、存得住、找得快。
---
## 二、系统架构
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ collect.py │────→│ analyze.py │────→│ app.py │
│ 多平台采集 │ │ AI 分析 │ │ Web 界面 │
└──────┬──────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ JSONL 存档 │ │ oMLX 本地LLM │ │ SQLite 索引 │
│ data/raw/ │ │ Qwen2.5-VL │ │ data/db │
└──────────────┘ └──────────────┘ └──────┬───────┘
│
┌──────▼───────┐
│downloader.py │
│ yt-dlp 下载 │
└──────┬───────┘
│
▼
~/workbuddy-agent-os/agent-local/materials/
```
### 技术选型
| 组件 | 选型 | 为什么 |
|------|------|--------|
| 采集引擎 | MediaCrawler (Playwright) | 主流平台支持最全 |
| AI 大脑 | oMLX + Qwen2.5-VL-3B-8bit | 本地免费,3B 模型足够 JSON 输出 |
| 结构化存储 | SQLite (WAL 模式) | 零配置,16GB 无压力 |
| 媒体下载 | yt-dlp | 支持平台最多 |
| Web 界面 | Gradio | Python 原生,开发最快 |
| 配置管理 | YAML | 人类可读,注释友好 |
---
## 三、快速开始
### 3.1 环境准备
```bash
# 确认 Python 环境
~/.workbuddy/binaries/python/envs/agent-os/bin/python3 --version
# 应输出: Python 3.13.12
# 确认 oMLX 运行中
curl -s http://localhost:8000/v1/models -H "Authorization: Bearer omlx" | python3 -c "import sys,json; [print(m['id']) for m in json.load(sys.stdin)['data']]"
# 应输出: Qwen2.5-VL-3B-Instruct-8bit
```
### 3.2 安装依赖
```bash
~/.workbuddy/binaries/python/envs/agent-os/bin/pip install gradio yt-dlp
```
### 3.3 初始化数据库
```bash
cd ~/workbuddy-agent-os/agent-sync/05_tools/05_crawl/content-inspiration
~/.workbuddy/binaries/python/envs/agent-os/bin/python3 collect.py --init-db
# 输出: [OK] 数据库初始化完成
```
### 3.4 开始使用
```bash
# 1. 采集素材(需要先配置 MediaCrawler Cookie)
python collect.py -p xiaohongshu -k "普通人逆袭"
# 2. AI 分析(需要 oMLX 运行中)
python analyze.py
# 3. 启动 Web 界面
python app.py
# 打开 http://127.0.0.1:7860
# 4. 下载视频(在 Web 界面标记后)
python downloader.py
```
---
## 四、项目结构
```
content-inspiration/
├── SKILL.md # 技能身份证(system/user 能力说明)
├── README.md # 本文件(完整项目说明)
├── config.yaml # 所有配置(平台/模型/存储/下载/Web)
├── schema.sql # 数据库表结构(3 张表)
├── requirements.txt # Python 依赖清单
│
├── collect.py # 采集脚本(MediaCrawler 封装)
├── analyze.py # AI 分析脚本(oMLX 调用 + JSON 解析)
├── downloader.py # 下载脚本(yt-dlp 封装)
├── app.py # Web 界面(Gradio)
├── utils.py # 通用工具(配置/数据库/日志/JSONL)
│
├── data/
│ ├── raw/ # JSONL 原始采集存档
│ │ └── 2026-04-28_xiaohongshu_普通人逆袭.jsonl
│ └── database.db # SQLite 素材库
│
└── logs/ # 运行日志(按日期分割)
├── collect_20260428.log
└── analyze_20260428.log
```
### 与 AgentOS 的关系
```
~/workbuddy-agent-os/agent-sync/ ← 坚果云同步 + Git
└── 05_tools/05_crawl/
└── content-inspiration/ ← 本项目
├── 代码 + 配置 + 数据库 (同步)
└── data/raw/*.jsonl (同步)
~/workbuddy-agent-os/agent-local/ ← 本机专属,不同步
└── materials/
├── video/ ← 下载的视频
└── audio/ ← 下载的音频
```
- 项目代码和数据库跟随 agent-os 同步
- 下载的视频/音频在本机专属目录,不占用同步空间
- AI 分析结果可通过 AgentOS 的 inbox_refine 归档到知识库
---
## 五、配置说明(config.yaml)
```yaml
# 平台和关键词
platforms:
- xiaohongshu # 目前最成熟
- douyin # 需要 Cookie
- bilibili # 支持
keywords:
- "普通人逆袭"
- "情感故事"
- "科普冷知识"
max_count: 20 # 每关键词每次采集上限
# 本地 LLM(oMLX,非 Ollama)
llm:
model: "Qwen2.5-VL-3B-Instruct-8bit"
base_url: "http://localhost:8000/v1" # oMLX 端口
api_key: "omlx" # oMLX 固定 key
timeout: 120 # 每条分析超时
temperature: 0.3 # 低温度保证稳定
# 存储路径
storage:
raw_dir: "data/raw"
db_path: "data/database.db"
media_dir: "~/workbuddy-agent-os/agent-local/materials/video"
audio_dir: "~/workbuddy-agent-os/agent-local/materials/audio"
# Web 界面
web:
host: "127.0.0.1"
port: 7860
title: "口播灵感工坊"
# 下载配置
download:
rate_limit: "1M" # 速率限制,防 IP 封禁
retries: 3 # 重试次数
```
---
## 六、脚本详细说明
### collect.py — 采集脚本
**功能**:从主流平台采集内容元数据(标题、描述、封面、互动数据等),不下载视频本体。
```bash
# 初始化数据库
python collect.py --init-db
# 指定平台和关键词采集
python collect.py -p xiaohongshu -k "科普冷知识"
# 指定数量
python collect.py -p xiaohongshu -k "情感故事" -n 10
# 按 config.yaml 批量采集(遍历所有平台×关键词)
python collect.py
```
**输出**:
- `data/raw/YYYY-MM-DD_平台_关键词.jsonl` — 原始数据存档
- `data/database.db` — 写入 materials 表(自动去重)
**前置条件**:MediaCrawler 已安装并配置好 Cookie。
### analyze.py — AI 分析脚本
**功能**:对未分析的素材调用本地 oMLX(Qwen2.5-VL-3B),提取口播可用信息。
```bash
# 分析所有未分析的素材
python analyze.py
# 只分析前 10 条(测试用)
python analyze.py -n 10
# 只看有多少待分析(不执行)
python analyze.py --dry-run
# 重试之前失败的记录
python analyze.py --retry-failed
```
**输出**:写入 analysis 表,字段包括:
- `tags` — AI 标签(科普、情感、冷知识…)
- `golden_quote` — 可直接引用的金句
- `core_idea` — 核心立意
- `structure` — 口播脚本结构
- `emotion` — 整体情绪
- `worth_downloading` — 是否推荐下载
**注意**:串行执行(每次只处理一条),16GB Mac 不会 OOM。每条间隔 1 秒。
### downloader.py — 下载脚本
**功能**:下载标记为 pending 的素材视频到本地。
```bash
# 下载所有标记为待下载的
python downloader.py
# 下载所有 AI 推荐的
python downloader.py --all
# 限制数量
python downloader.py -n 5
# 手动指定 URL
python downloader.py -u "https://v.douyin.com/xxx"
```
**输出**:文件保存到 `~/workbuddy-agent-os/agent-local/materials/video/`,文件名格式:
```
xiaohongshu_作者名_标题前20字_日期.mp4
```
### app.py — Web 界面
**功能**:本地浏览器访问的素材管理界面。
```bash
python app.py
# 打开 http://127.0.0.1:7860
```
**功能清单**:
- 🔍 关键词搜索(标题/描述/标签/金句)
- 📋 平台/情绪/下载状态筛选
- 📊 实时统计(总数/已分析/已下载/AI推荐)
- 📖 素材详情(AI 分析完整结果)
- 📥 一键标记下载
- 📝 金句可直接复制
### utils.py — 工具函数
| 函数 | 用途 |
|------|------|
| `load_config()` | 加载 config.yaml |
| `get_db()` / `init_db()` | 数据库连接/初始化 |
| `setup_logger()` | 日志配置 |
| `parse_jsonl()` / `save_jsonl()` | JSONL 读写 |
| `check_omlx()` | 检测 oMLX 可用性 |
| `truncate_text()` | 文件名安全截断 |
---
## 七、数据库设计
### materials 表(素材元数据)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER | 主键 |
| platform | TEXT | 平台(xiaohongshu/douyin/bilibili) |
| original_id | TEXT | 平台内唯一 ID |
| url | TEXT | 原始链接 |
| title | TEXT | 标题 |
| description | TEXT | 描述/正文 |
| author | TEXT | 作者 |
| cover_url | TEXT | 封面图 |
| music_name | TEXT | BGM |
| like_count | INTEGER | 点赞数 |
| analyzed | INTEGER | 0未分析/1已分析/2失败 |
| download_status | TEXT | none/pending/downloading/done/failed |
| local_files | TEXT | JSON(本地文件路径) |
| raw_json | TEXT | 完整原始数据备份 |
### analysis 表(AI 分析结果)
| 字段 | 类型 | 说明 |
|------|------|------|
| material_id | INTEGER | 关联素材 |
| tags | TEXT | AI 标签(逗号分隔) |
| golden_quote | TEXT | 金句 |
| core_idea | TEXT | 核心立意 |
| structure | TEXT | 脚本结构 |
| emotion | TEXT | 情绪 |
| worth_downloading | TEXT | yes/no/maybe |
| download_reason | TEXT | 下载理由 |
| raw_model_output | TEXT | 模型原始输出(调试) |
### collect_batches 表(采集批次记录)
记录每次采集的平台、关键词、数量、状态,方便回溯。
---
## 八、知识库索引卡片
采集并分析后的素材,可以在知识库中生成索引卡片(存入 `03_knowledge/50_resources/`):
**文件名格式**:`{hostname}_{YYYYMMDD}_{slug}.md`
**示例**:`Redmi-12C_20260428_xiaohongshu-普通人逆袭.md`
```markdown
---
title: 普通人逆袭合集
source_url: https://www.xiaohongshu.com/explore/xxx
local_path: ~/workbuddy-agent-os/agent-local/materials/video/xiaohongshu_作者_标题.mp4
type: video
platform: xiaohongshu
collected_by: Redmi-12C
collected_at: 2026-04-28
tags: [口播素材, 励志, 逆袭]
---
一句话说明:适合逆袭主题口播开头,情绪张力强。
```
`collected_by` 字段防止多机同步时文件名冲突。
---
## 九、MediaCrawler 配置(前置条件)
### 安装
```bash
cd ~/workbuddy-agent-os/agent-sync/05_tools/05_crawl
git clone https://github.com/NanmiCoder/MediaCrawler.git
cd MediaCrawler
~/.workbuddy/binaries/python/envs/agent-os/bin/pip install -r requirements.txt
```
### 配置 Cookie
各平台需要在首次使用前扫码登录获取 Cookie:
1. `cd ~/workbuddy-agent-os/agent-sync/05_tools/05_crawl/MediaCrawler`
2. `python main.py --platform xhs --lt qrcode`
3. 扫描终端显示的二维码
4. Cookie 自动保存,后续无需重复登录
### 配置本项目
安装完成后,更新 `config.yaml`:
```yaml
crawler:
project_path: "~/workbuddy-agent-os/agent-sync/05_tools/05_crawl/MediaCrawler"
```
---
## 十、性能与资源管理(16GB Mac)
| 场景 | 内存占用 | 建议 |
|------|----------|------|
| 采集(Playwright) | ~500MB | 关闭其他浏览器 |
| AI 分析(Qwen2.5-VL-3B) | ~2GB | 关闭其他大型应用,串行执行 |
| Web 界面(Gradio) | ~300MB | 轻量,无压力 |
| 下载(yt-dlp) | ~100MB | 速率限制 1MB/s |
**关键原则**:分析期间不同时运行其他 AI 任务,每次只处理一条记录。
---
## 十一、常见问题
**Q: oMLX 返回 500 错误?**
A: Qwen3-8B-MLX-4bit 有已知问题。本系统使用 Qwen2.5-VL-3B-Instruct-8bit,不受影响。
**Q: 采集没有数据?**
A: 检查 MediaCrawler Cookie 是否过期,重新扫码登录。
**Q: AI 分析结果不准确?**
A: 3B 模型有限,可通过调整 `temperature`(降低=更稳定)或更换更强模型改善。
**Q: 视频下载失败?**
A: 抖音/小红书链接有时效性,采集后尽快下载。也可尝试 `--retry-failed`。
**Q: 如何接入 AgentOS 自动化?**
A: 可在 WorkBuddy 中创建定时自动化,例如每天凌晨执行 `python analyze.py`。
---
## 十二、合规提醒
- ⚠️ 仅供**个人学习研究**,禁止大规模抓取或商业化
- 下载的视频仅供**分析借鉴**,口播内容须二次原创
- 所有数据**本地存储**,注意定期备份
---
## 十三、未来扩展
- [ ] 定时自动采集 + 热点推送
- [ ] 向量语义搜索(接入 ChromaDB + Qwen3-Embedding)
- [ ] 提示词模板可视化编辑
- [ ] 素材标签归一化
- [ ] 简易剪辑时间线