metasearch · 多源聚合搜索

一次输入,同时打到多个搜索来源,结果统一成同一种格式、跨来源去重合并,再按来源分组交给你。 本体是一个命令行工具;这一页把其中三个不需要登录态的公开源接上了服务端出口,你可以直接在下面试。

网页版:GitHub · arXiv · Hacker News 本地完整版:21 个来源 并发派发 跨源 URL 去重 单源失败隔离

1 · 它替你解决什么

同一个问题,答案分散在互不相通的几个站里。于是你开五个标签页,同一串关键词敲五遍, 再自己在脑子里合并——哪些是同一篇、哪个先看、哪个站今天登录掉了。metasearch 把这一整套动作压成一次输入。

选一个技术方案

「有没有现成的库」这件事,代码仓库、社区讨论、问答站各知道一半。同时问过去,你拿到的是一张合并过的表, 而不是几个标签页。

摸清一个学术概念

预印本、引用图谱、DOI 元数据分散在不同库里。同一个术语一次打过去,同一篇论文若在多个库同时命中, 会被识别成一条并标注出「哪几个来源都收录了它」。

一个源坏了,不该拖垮整次搜索

某个源超时、限流、掉登录,只让它自己降级并把原因摆出来,其余源照常返回——你知道这次少看了什么, 而不是默默少了一块。这条在下面的演示里可以直接点出来看。

2 · 网页版接了什么、没接什么

本网页版接了三个源:GitHub、arXiv、Hacker News。 它们都是公开检索接口,不需要任何登录态,所以能由服务端代发。

本地完整版还有小红书、知乎、个人知识库等来源,公网版接不了—— 它们要么依赖浏览器登录态,要么依赖只存在于本机的私域凭证与本地索引文件。 网页托管别人的登录凭据这件事不该做,也做不对,所以这一页就是三个源,不是缩水的完整版,是公开源那一半

3 · 试一下:三源并行搜索

三个源同时发出(不是排队轮问),谁先回来先渲染谁,总耗时取决于最慢的那个源而不是三者相加。 每个源单独显示耗时;某个源失败只标它自己失败,其余照常显示。

来源

4 · 去重规则,你也可以在这里试

合并视图用的就是下面这套逻辑(URL 归一化 + 跨源合并),在你的浏览器里当场算,不联网。 改改试试:把 utm_source 换个值、把参数顺序调一下、加个 # 锚点,看它还认不认得这是同一条。

5 · 本地完整版的 21 个来源

点表头可排序。「零配置」=装完就能跑;其余需要你自己准备密钥、登录态或本地命令。 带「网页版」标记的三个,就是上面那个搜索框接的源;其余在公网上接不了。 单个来源缺条件不会导致命令失败,只会被标成降级。

来源领域后端开箱状态网页版
github代码仓库GitHub 公开检索接口(按 star 数给分)本地需 gh 已登录已接
arxiv学术预印本arXiv 官方 Atom API零配置已接
hackernews技术趋势Hacker News 全文检索 API零配置已接
web通用网页DuckDuckGo;配了环境变量则改用 SearXNG / Brave / Google 自定义搜索零配置未接
openalex开放学术图谱OpenAlex API(可选密钥仅用于提额)零配置未接
crossrefDOI / 引文元数据Crossref REST(带 mailto 走礼貌池)零配置未接
semantic_scholar学术(摘要 / 引用)Semantic Scholar Graph API(可选密钥更稳)零配置未接
europepmc生物医学Europe PMC REST零配置未接
stackexchange技术问答Stack Exchange API(默认站点 Stack Overflow)零配置未接
npmJavaScript 包npm registry 搜索端点零配置未接
cratesioRust 包crates.io API零配置未接
wikipedia百科MediaWiki Action API(默认英文站,改一个常量即切语种)零配置未接
gdelt全球新闻(65 语种)GDELT DOC 2.0(限速每 5 秒 1 次)零配置未接
xhs小红书xhs 命令行工具,复用浏览器登录态(按点赞数给分)需装 CLI 并登录要登录态
kb本地知识库本地 SQLite 全文检索(FTS5)命令行需本地知识库私域本机
notion个人文档Notion 官方搜索 API需个人 token私域凭证
tavily通用网页(面向 AI)Tavily Search API需 API 密钥私域凭证
youtube视频YouTube Data API v3需 API 密钥私域凭证
reddit论坛Reddit 搜索;未授权时公开端点会被拒,需 OAuth 凭据需 OAuth 凭据私域凭证
tieba百度贴吧aiotieba;贴吧无全局搜索,只能吧内搜,须指定吧名(可多吧并发)需指定吧名要登录态
bili哔哩哔哩bili 命令行工具需装 CLI要登录态

6 · 命令行怎么用

# 看看当前注册了哪些源
metasearch --list-sources

# 只问三个源,每源最多 5 条,JSON 输出到屏幕
metasearch "claude code" --sources web,github,arxiv --limit 5

# 不指定源 = 全部启用的源一起上
metasearch "vector database"

# 单源超时收紧到 8 秒(慢源自动降级,不等它)
metasearch "vector database" --sources web,hackernews --timeout 8

# 出 Markdown / 自包含 HTML,写到文件
metasearch "transformer" --format md   -o out.md
metasearch "transformer" --format html -o out.html

参数总表:--sources 逗号分隔的源名(默认全部)· --limit 每源条数上限(默认 10)· --timeout 单源超时秒(默认 15)· --format json|md|html(默认 json)· -o 写文件 · --list-sources 列出源。

7 · 技术上怎么做的

核心是一份只有两个字段要求的适配器契约:每个源实现 async search(query, limit), 把自家返回映射成统一的结果对象(标题 / 链接 / 来源 / 摘要 / 分值 / 时间,外加一份原始负载兜底,不丢信息)。 派发层拿到的是一组同构对象,因此它只认契约不认源——21 个源里既有原生异步 HTTP 调用,也有包成线程的同步子进程命令行, 在派发层眼里没有区别。所有源用一次 asyncio.gather 并发出去,每个源套一层独立的超时与异常隔离壳: 它只会返回「结果」或「降级原因」,绝不向上抛——这是「单源失败不拖垮整体」在代码层面的落点,而不是一句设计意图。

聚合层做两件事:归一化 URL 后跨源去重合并(保留高分那条,累计多源标记),以及组内排序。 去重主键是归一化后的 URL:剥掉 utm_* 一类跟踪参数与 fbclid / gclid / spm / ref 等分享参数、丢掉锚点、把剩余参数排序、统一去掉末尾斜杠; 没有 URL 的结果(本地知识库、部分社交内容)退回用「来源 + 标题」作主键,不会被误合。 上面那个搜索框走的是同一套规则的 JavaScript 复刻版,逐条对齐。

网页版这一层只多做一件事:把三个公开源的请求挪到服务端出口 (GET /api/fetch?src=<github|arxiv|hackernews>&q=<关键词>, 返回 {src, items:[{title,url,meta,snippet}], ms}), 浏览器侧三个请求一起发、各自渲染、各自计时。加来源在命令行版是往目录里丢一个文件; 在网页版则要先回答「这个源需不需要登录态」——需要的那些,答案就是不接。

本页三处数据的口径分别是:①「跑合成样例」按钮④ 去重演示的默认输入合成数据(编的标题与 example.org 链接,不是真实抓取结果,其中「arXiv 502」是故意造的失败,用来演示单源隔离); ②「搜索」按钮会真的向本站 /api/fetch 发三个请求,结果来自 GitHub / arXiv / Hacker News 的公开接口; ③ 来源表描述的是本地命令行版的实际能力。去重演示完全在你的浏览器里计算,输入不离开本机。 本地完整版跑在你自己的机器上,搜索词与结果不经过第三方服务器。