context-infra 检查与复盘infra.guiming.net · 全内容自包含呈现 · 生成于 2026-07-21 16:28 UTC

链接内容提取

Z3 全文↑ Z2 条目

术-流程 · 术层 skill 全文

← 返回术层 skill 索引 · 返回方法论区

本页是 <code>rules/skills/workflow_content_extraction.md</code> 的逐字投影(仅隐私清洗,零改写)。

时点提示:本页是仓内文件 rules/skills/workflow_content_extraction.md 的逐字投影(仅做隐私清洗:仓库根绝对路径→相对路径、家目录→~/;除此零改写)。若源文件后续有修订,以仓内真源为准。

Skill: 链接内容提取

When to Use

当用户发送一个 URL(无论是在微信对话、直接粘贴、还是文件中提及),需要提取其内容时触发。适用场景:

  1. 微信转发的链接(通过 WeClaude bridge 到达)
  2. 对话中直接发送的 URL
  3. 文档中引用的外部链接需要本地化
  4. 批量处理多个链接

核心原则:统一管线 + 分层特殊化。大部分网页(包括未见过的)走通用 handler;常用平台(GitHub/X/小红书/微信/B站/YouTube)有专用 handler 做更精细的处理。所有结果都进同一套 PostProcessor 链(质量门控 → 噪声过滤 → 图片下载 → OCR → 转录 → 去重 → frontmatter → 保存)。

四维数据模型

任何链接被当作可能包含下列四种内容的混合体:

维度存储方式
文字ExtractionResult.text
图片ExtractionResult.images[](url + 本地 path + OCR 文本)
视频ExtractionResult.videos[](url + 本地 path + duration + transcript)
音频ExtractionResult.audios[](同上)

默认只提取正文 + 图片。视频/音频下载与转录需要 --transcribe 标志。评论、弹幕、互动数据默认不提取

Prerequisites

工具依赖(按名引用,路径查 tools/INDEX.md):

工具用途必需
link_router统一入口(detector + HandlerRegistry + PostProcessorChain)
bilibili_downloadB站 BBDown 下载B站链接时
video_downloadyt-dlp 下载(YouTube 等)非B站视频时
browser_captureOCR helpers、Playwright cookie 注入handler 内部调用
audio_transcribeGroq Whisper API 语音转录(默认,备选 Windows remote GPU)需要转录时

Python 依赖trafilatura(GenericHandler 主内容提取)。已装在 user site-packages。

Handler 清单

link_router 内部 7 个 handler,按 URL 特征自动匹配:

HandlerURL 特征实现策略
bilibilibilibili.com/video/BV b23.tv/BBDown CLI
youtubeyoutube.com/watch youtu.be/*yt-dlp
twitterx.com//status/ twitter.com//status/FxTwitter API(api.fxtwitter.com)主路径 → Playwright fallback
githubgithub.com/{owner}/{repo}GitHub REST API /repos/{o}/{r}/readme(raw markdown)
xiaohongshuxiaohongshu.com/ xhslink.com/Playwright + Cookie → 解析 __INITIAL_STATE__ JSON → 图片 URL rebuild
wechatmp.weixin.qq.com/s/*Playwright + Cookie + 图片下载 + OCR
generic其他所有Playwright + Cookie + trafilatura(语义正文提取)

短链接处理

b23.tvxhslink.comt.coyoutu.be 等短链接由 detector.py 自动 curl -L 跟随重定向,解析后重新路由。

PostProcessor 链(所有 handler 共享)

Processor作用触发条件
QualityGate拒绝反爬页面 / 登录墙 / 平台首页 / 文本 < 100 字符永远运行,失败即短路
NoiseFilter按平台过滤已知 UI 噪声(X / GitHub / 小红书 / 通用 cookie)有 text 时
ImageDownload下载图片到 .image_cache/<slug>/默认 on,--no-download-images 关闭
ImageOCRVision Framework OCR 大于 300x300 的图片wechat 默认开;其他平台 --ocr 开启
MediaTranscribeGroq Whisper API 转录音视频(默认)--transcribe
URLDedup扫 library 的 frontmatter url 字段--on-duplicate {skip,overwrite,version},默认 skip
Frontmatter按统一 schema 生成 YAML所有成功结果
LibrarySave幂等写入 contexts/library/{articles,videos}/--save

CLI 使用

# 仅检测,返回 JSON(platform、handler_name、confidence 等)
python3 tools/link_router/link_router.py detect <url>

# 提取,保存到 library
python3 tools/link_router/link_router.py extract <url> --save

# 含音视频转录
python3 tools/link_router/link_router.py extract <url> --save --transcribe

# 指定 Chrome 小号 profile 读取 cookie(例如 Profile 2 / Michel)
python3 tools/link_router/link_router.py extract <url> --save --cookie-profile "Profile 2"

# 所有平台图片 OCR
python3 tools/link_router/link_router.py extract <url> --save --ocr

# URL 重复时处理策略
python3 tools/link_router/link_router.py extract <url> --save --on-duplicate version

# 批量
python3 tools/link_router/link_router.py batch <urls.txt> --save --transcribe

场景 A:单个链接提取

  1. 不确定类型 → 先 detect,再 extract --save
  2. 明确是文章 → extract --save
  3. 明确是视频/音频 → extract --save --transcribe

场景 B:微信转发链接处理

微信通过 WeClaude bridge 转发的链接以纯文本形式到达:

python3 tools/link_router/link_router.py extract <url> --save --transcribe

--transcribe 只对视频生效,--save 只对成功提取的结果写盘。文章和视频一条命令通吃。

场景 C:批量链接处理

python3 tools/link_router/link_router.py batch urls.txt --save --transcribe

统一 Frontmatter Schema

所有 library 文件使用同一套字段:

---
title: string                           # 必需
url: string                             # 必需
resolved_url: string                    # 可选(短链接解析后)
platform: enum                          # github/twitter/xiaohongshu/wechat/bilibili/youtube/generic
content_type: enum                      # article/video/tweet/image_set/readme
author: string                          # 必需,可空串
pub_date: ISO 8601                      # 可选
extracted_at: ISO 8601 UTC              # 必需
extraction_method: string               # 具体走的路径(如 fxtwitter_api、github_api、generic_trafilatura)
status: full | partial | failed         # 必需
confidence: float                       # 0-1
text_length: int                        # 必需
image_count: int                        # 必需
video_count: int                        # 必需
# 视频专用
duration_seconds: float
transcription_engine: string
# 平台特有
metadata:
  stars: int                            # GitHub
  topics: [string]                      # GitHub
  license: string                       # GitHub
  likes: int                            # XHS/Twitter
  ...
warnings: [string]                      # 部分失败的提示
---

旧文件(source:saved_at: 等字段名)不会自动迁移,但不影响新提取。如需统一,后续写迁移脚本。

端到端验证状态(2026-04-16 统一管线重构后)

7/7 真实 URL 测试全部通过,评分全 A 或 A-:

链路测试用例质量extraction_method
X Article → articles/garrytan/status/2042925773300908103 "Thin Harness, Fat Skills"Afxtwitter_api
GitHub README → articles/github.com/JoeanAmier/XHS-DownloaderAgithub_api
小红书图文 → articles/带 xsec_token 的真实 note URLA-xiaohongshu_initial_state
小红书失效 URL(反向测试)693fb734000000001e013823(xsec_token 过期)AQualityGate 正确拒绝
微信公众号 → articles/机器之心文章(回归)Awechat_playwright
一般网页 → articles/trafilatura.readthedocs.io/en/latest/Ageneric_trafilatura
B站视频 → videos/BV1GVXzBaELr(36s 技术讲解)Abbdown + audio_transcribe
YouTube 视频 → videos/jNQXAC9IVRw "Me at the zoo"(19s)Ayt-dlp + audio_transcribe

关键质量指标

"无人声视频"处理:转录引擎返回空字符串时,MediaTranscribe 添加 warning,不生成垃圾 transcript 文件。

关键决策

决策点选择原因
架构Handler Registry + PostProcessor Chain统一管线 + 少量特殊化;新增平台只需写一个 handler
X/Twitter 策略FxTwitter API 主,Playwright fallback零成本、无 UI 噪声、支持 Article Draft.js 渲染
GitHub 策略REST API /readmeraw markdown,零 UI 噪声;60 req/h 足够个人使用
小红书图片URL rebuild + 本地下载CDN 签名 URL 几小时过期;rebuild 到 ci.xiaohongshu.com/{token}?imageView2/format/png 得到永久链接
通用网页正文trafilatura + BeautifulSoup 语义选择器 fallbackROUGE-N.f1 0.64,优于 document.body.innerText
B站下载工具BBDown比 yt-dlp 对 B 站稳定
Cookie 来源Chrome 本地数据库 via pycookiecheat零配置,用户已登录的平台自动可用
转录引擎Groq Whisper API(默认,engine chain groq-whisper,remote-gpu识别计算走远端 API / 远端 GPU,本机不占推理资源;实现见 tools/audio_transcribe
质量门控QualityGate 短路整条链反爬 / 登录墙 / 首页 title 的废页面不入库
URL 去重默认 skip,可 version/overwrite避免重复写入和误覆盖用户手工整理

陷阱

  1. Python 解释器:handler 内部调用的 video_download / browser_capture/usr/bin/python3(系统 Python 3.9),pycookiecheat 的 Keychain 授权绑在此解释器。link_router 本身的 CLI 可以用任何 python3
  2. 短链接超时b23.tv 等短链接解析依赖 curl 跟随重定向,网络不好时可能超时。默认 10 秒
  3. audio_transcribe venvtools/audio_transcribe/.venv/bin/ 如果被 homebrew upgrade 破坏,需要 python3.12 -m venv tools/audio_transcribe/.venv --without-pip 重建
  4. ASR 错别字:转录引擎会把专业术语识别错(如 "Claude" → "cloud")。未做 LLM 后处理
  5. XHS xsec_token:小红书 note URL 没有 xsec_token 或 token 过期时,平台只返回首页。QualityGate 会识别并拒绝

5a. 小红书账号隔离:默认 cookie 来源是 Chrome 默认 profile。测试小号时必须先让小号登录一个独立 Chrome profile,再用 --cookie-profileLINK_ROUTER_COOKIE_PROFILE 指向该 profile;显式指定的 profile 找不到时不会回退到默认 profile

  1. FxTwitter 依赖第三方api.fxtwitter.com 不是官方服务,理论上可能挂。TwitterHandler 会自动 fallback 到 api.vxtwitter.com,再失败 fallback 到 Playwright
  2. GitHub API 配额:未认证 60 req/h。设置环境变量 GITHUB_TOKEN 提升到 5000 req/h
  3. trafilatura 对 SPA 支持有限:我们先用 Playwright 抓 rendered HTML 再喂给 trafilatura,所以多数 SPA 可用。但需要用户交互(点击"展开")才显示内容的页面仍抓不到

Python API(供其他工具调用)

from tools.link_router import extract, detect, ExtractionOptions

# 检测
detection = detect("https://x.com/garrytan/status/2042925773300908103")
# → LinkDetection(platform="twitter", handler_name="twitter", confidence=0.9, ...)

# 提取(options 是 keyword-only 参数)
result = extract(
    "https://x.com/garrytan/status/2042925773300908103",
    options=ExtractionOptions(save=True, transcribe=False, on_duplicate="skip"),
)
# → ExtractionResult(status="full", text="...", images=[...], ...)

必须用 /usr/bin/python3(pycookiecheat 的 Keychain 授权和 Playwright 绑在该解释器)。

代码组织

tools/link_router/
  link_router.py              # 向后兼容 wrapper(CLI 入口)
  cli.py                      # 新 CLI 实现
  router_types.py             # ExtractionResult、ExtractionOptions 等
  detector.py                 # URL → LinkDetection
  registry.py                 # HandlerRegistry + PostProcessorChain
  frontmatter_schema.py       # 统一 schema + 生成器
  handlers/
    base.py                   # PlatformHandler Protocol
    _browser_utils.py         # 共享 Playwright + Cookie 工具
    bilibili.py youtube.py wechat.py twitter.py github.py xiaohongshu.py generic.py
  post_processors/
    base.py
    quality_gate.py noise_filter.py image_download.py image_ocr.py
    media_transcribe.py url_dedup.py frontmatter.py library_save.py

后续改进方向

已完成(之前列为改进方向):

剩余(低优先级):

  1. Library 旧文件迁移:现有 library 文件的 frontmatter schema 未自动升级,需要单独脚本
  2. LLM 后处理 ASR:转录引擎输出通过 LLM 修正专业术语
  3. 下载缓存:相同 URL 近期已处理时跳过,省流量
  4. 内部 API 直调:B站和小红书的内部 API 直调可以避免 Playwright 开销(MediaCrawler 30k stars 有现成实现)
  5. URL 等价性判断URLDedup 当前按完整字符串匹配,可扩展为规范化(去 www、去尾部 /)后比较
  6. 小红书 OCR 默认开启:小红书图文笔记的内容主要在图片里,默认开 OCR 可能更实用

← 返回术层 skill 索引 · 返回方法论区