scaso01/monster-search

GitHub: scaso01/monster-search

一款自托管的多引擎元搜索工具,通过智能分层和 RRF 融合,让用户用一次查询同时获取 34 个搜索引擎的结果。

Stars: 0 | Forks: 0

# monster-search [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/scaso01/monster-search/actions/workflows/ci.yml) [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/downloads/) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) 提出一个问题,同时获取来自 34 个搜索引擎的答案。覆盖网页、学术、 代码、安全、包、WHOIS、新闻、视频、AI、社区、存档和 购物,全部集成于一个 CLI 和 Python API 之后。 它会首先读取查询内容,仅运行适合该查询的引擎,因此 CVE 标识符会被发送到漏洞数据库,而论文标题则会被发送到 学术搜索引擎。来自各个引擎的结果会被合并到一个排名列表中, 而不是作为单独的堆叠显示。 它与外界交互的所有内容要么是免费的公共 API,要么是你自行托管的 服务。这里没有付费层级,也不需要注册任何账号。 ![智能分层搜索,附带 AI 生成的回答及其来源](https://static.pigsec.cn/wp-content/uploads/repos/cas/d5/d527dae5932a4cf65fedd10735e856e80b9be0e0d14932a394cec3a2331f0fcd.png) ## 快速开始 ``` # 安装 git clone https://github.com/scaso01/monster-search.git cd monster-search pip install -e ".[dev]" # 搜索 (默认智能分层 -- 并行运行 tier1 引擎,约 15-60 秒) monster-search "python asyncio best practices" # 快速查询 (约 3 秒) monster-search --engine searxng "python asyncio" # 深度搜索,包含慢速 AI 引擎 (约 2-5 分钟) monster-search --deep "supply chain attacks 2026" # 检查服务健康状态 monster-search --health ``` ## 引擎 34 个引擎分为 12 个类别,按 3 个优先级层级执行。 ### 引擎列表 | 引擎 | 类别 | 层级 | 来源 | 耗时 | |--------|----------|------|--------|------| | SearXNG | 网页通用 | 1 | 自托管 (Docker, :8080) | ~3-4秒 | | Marginalia | 网页通用 | 1 | 外部 API | ~3秒 | | mwmbl | 网页通用 | 1 | 外部 API | ~3秒 | | Perplexity | 网页 AI | 1 | 外部 (cookie 认证) | ~30秒 | | Synthesizer | 网页 AI | 1 | SearXNG + Crawl4AI + llama-server | ~30-60秒 | | Vane | 网页 AI | 2 | 自托管 (Docker, :3004) | ~2分钟 | | Khoj | 网页 AI | 2 | 自托管 (Docker, :42110) | ~2分钟 | | Fyin | 网页 AI | 2 | 通过 SSH 访问的主机上的 CLI | ~2分钟 | | Local Deep Researcher | 网页 AI | 3 | 自托管 (Docker, :8300) | ~3-8分钟 | | arXiv | 学术 | 1 | 外部 API | ~3秒 | | Semantic Scholar | 学术 | 1 | 外部 API | ~3秒 | | OpenAlex | 学术 | 1 | 外部 API | ~3秒 | | Zoekt | 代码 | 1 | 自托管索引 | ~1秒 | | OSV | 安全 | 1 | 外部 API (osv.dev) | ~2秒 | | deps.dev | 包 | 1 | 外部 API | ~2秒 | | Who-Dat | 域名/WHOIS | 1 | 自托管 (Docker, :8083) | ~1秒 | | News (SearXNG) | 新闻 | 1 | 自托管 (Docker, :8080) | ~5秒 | | GNews | 新闻 | 1 | 外部 RSS | ~2秒 | | Archive.org | 存档 | 1 | 外部 API (CDX + catalog) | ~10秒 | | YouTube | 视频 | 1 | yt-dlp + youtube-transcript-api | ~5-10秒 | | grep.app | 代码 | 1 | 外部 API | ~3秒 | | GitHub Code Search | 代码 | 1 | gh CLI 子进程 | ~5秒 | | GitHub Repos | 代码 | 1 | gh CLI 子进程 | ~3秒 | | searchcode_repo | 代码 | 选填 | searchcode.com API (需要 --repo) | ~2秒 | | Hacker News | 社区 | 1 | Algolia API | ~2秒 | | HuggingFace | AI/ML | 1 | HuggingFace Hub API | ~3秒 | | Reddit | 社区 | 1 | Reddit Atom feed | ~3秒 | | CheapShark | 购物 | 1 | CheapShark API | ~2秒 | | SlickDeals | 购物 | 1 | SlickDeals API | ~3秒 | | Crawl4AI | 工具 | -- | 自托管 (Docker, :11235) | ~15秒 | | changedetection.io | 工具 | -- | 自托管 (Docker, :8086) | -- | **注意事项:** - 第 1 层级引擎默认在每次查询时运行(始终开启 + 路由控制的专业引擎)。 - 当第 1 层级结果稀少(< 3 个结果)时,第 2 层级引擎会自动提升执行。 - 第 3 层级引擎仅在指定 `--deep` 或进行深度研究查询时运行。 - Crawl4AI 接收 URL(页面提取)而非查询。changedetection.io 监控 URL 变更。 - Meilisearch 作为后台结果缓存运行(不是搜索引擎)。 - 路由控制的引擎(学术、安全、包、代码、WHOIS、存档)仅在查询通过 regex 分类匹配到其类别时才会激活。 ### 类别 | 类别 | 引擎 | 触发条件 | |----------|---------|---------| | 网页通用 | searxng, marginalia, mwmbl | 始终开启 | | 网页 AI | perplexity, synthesizer, vane, khoj, fyin, local_researcher | 始终开启 (tier1) / 提升执行 (tier2) / 深度执行 (tier3) | | 学术 | arxiv, semantic_scholar, openalex | 查询包含 paper/research/arxiv/doi 关键词 | | 代码 | zoekt, grepapp, github_code, github_repos | 查询包含代码结构 (.py, func, class 等) | | 安全 | osv | 查询包含 CVE/GHSA/vulnerability 关键词 | | 包 | deps | 查询包含生态系统前缀 (npm:, pypi:, cargo: 等) | | 域名/WHOIS | whodat | 查询包含域名或 IP 地址 | | 新闻 | news, gnews | 查询包含 latest/breaking/headlines 关键词 | | 存档 | archive_org | 查询包含 wayback/archive/cached 关键词或是 URL | | 视频 | youtube | 查询包含 video/tutorial/watch 关键词 | | 社区 | hackernews, reddit | 查询包含 discussion/forum/community 关键词 | | AI/ML | huggingface | 查询包含 model/dataset/ML 关键词 | | 购物 | cheapshark, slickdeals | 查询包含 buy/price/deal/discount 关键词 | ## 智能分层执行 默认搜索模式(`monster-search "query"`)采用智能分层: 1. 通过 regex 模式**分类**查询(安全、学术、代码、新闻等) 2. 并行**运行第 1 层级**引擎(始终开启 + 类别匹配的专业引擎) 3. 如果第 1 层级产生的结果少于 3 个,则**自动提升第 2 层级** 4. **第 3 层级**仅在指定 `--deep` 或进行深度研究查询时运行 5. 通过加权 Reciprocal Rank Fusion (RRF) **融合**结果 6. 通过 MinHash LSH 内容相似度进行**去重** ``` Tier 1 (fast, ~15-60s): searxng, marginalia, news, gnews, perplexity, synthesizer, + router-gated specialists Tier 2 (medium, ~2 min): vane, khoj, fyin Tier 3 (slow, ~3-8 min): local_researcher ``` ### 熔断器 每个引擎都有一个独立的熔断器。在多次连续失败后,熔断器会打开并在冷却期内跳过该引擎 —— 从而防止一个损坏的服务拖慢整个搜索过程。 ### RRF 融合 来自多个引擎的结果使用加权 Reciprocal Rank Fusion 进行合并。每个引擎都有一个质量权重(perplexity: 1.0, searxng: 0.9, marginalia: 0.85 等)。重复的 URL 会与所有相关引擎的元数据合并。 ### MinHash 去重 在融合之后,MinHash LSH 步骤会根据片段相似度移除近似重复的内容(Jaccard 阈值 0.5,3-gram shingles)。短文本会回退到基于 URL 的去重。 ## CLI 参考 ``` monster-search [OPTIONS] QUERY ``` ### 核心选项 | 标志 | 描述 | |------|-------------| | `--engine NAME` | 运行特定的引擎或类别别名 | | `--deep` | 包含慢速 AI 引擎 (tier2 + tier3) | | `--category {general,news,images,science,files}` | SearXNG 类别过滤器 | | `--time-range {day,week,month,year}` | 时间过滤结果 | | `--max-results N` | 覆盖默认值 (5) | | `--json` | 输出 JSON 以便管道传输 | | `--no-fuse` | 禁用 RRF 融合(传统的首次出现去重) | | `--model MODEL` | 覆盖 AI 引擎使用的 LLM 模型 | | `--benchmark` | 使用计时表对引擎进行基准测试 | | `--health` | 检查服务健康状态 | ### 引擎和类别别名 ``` # 单个引擎 monster-search --engine searxng "query" monster-search --engine marginalia "query" monster-search --engine perplexity "query" monster-search --engine synthesizer "query" # alias: --engine synth monster-search --engine vane "query" monster-search --engine khoj "query" monster-search --engine fyin "query" monster-search --engine local_researcher "query" monster-search --engine news "topic" monster-search --engine gnews "topic" monster-search --engine archive_org "query or URL" monster-search --engine crawl "https://url" # page extraction (URL only) monster-search --engine arxiv "transformer" monster-search --engine semantic_scholar "attention" monster-search --engine openalex "machine learning" monster-search --engine osv "pypi:jinja2" monster-search --engine deps "npm:express" monster-search --engine whodat "example.com" monster-search --engine zoekt "func main" # 类别别名 (并行运行分组引擎并融合结果) monster-search --engine academic "transformer" # arxiv + semantic_scholar + openalex monster-search --engine code "func main" # zoekt + grepapp + github_code monster-search --engine security "pypi:jinja2" # osv monster-search --engine packages "npm:express" # deps monster-search --engine whois "example.com" # whodat monster-search --engine video "rust tutorial" # youtube monster-search --engine ai_ml "text generation" # huggingface monster-search --engine shopping "laptop" # searxng shopping + slickdeals + cheapshark # + deals_rss + priceghost + amazon + newegg monster-search --engine deals "ssd" # slickdeals + deals_rss + amazon # 全面扫描 monster-search --engine all "query" # all 34 engines (~2-5 min) ``` 别名会并发运行其包含的引擎并合并返回的结果,因此单一的 学术查询会返回根据排名交错排列的 arXiv 和 OpenAlex 结果, 而不是按来源分组: ![一个返回融合后 arXiv 和 OpenAlex 结果的学术类别搜索](https://static.pigsec.cn/wp-content/uploads/repos/cas/e2/e20dd64e3fab1d10e195854ec5e9eea2fb08706cfd4825dbe8c278fdeccdf4d0.png) ### URL 变更监控 ``` monster-search watch add "https://example.com" --tag news monster-search watch list monster-search watch list --tag news monster-search watch check UUID monster-search watch diff UUID monster-search watch remove UUID ``` ## Python API ``` from monster_search import ( SearXNGClient, AllEnginesClient, MarginaliaClient, PerplexityClient, Crawl4AIClient, LocalResearcherClient, NewsSearchClient, ArchiveOrgClient, VaneClient, ChangeDetectionClient, Config, check_health, ) import asyncio # 快速搜索 (约 3 秒) results = SearXNGClient().search("python asyncio", max_results=5) # AI 合成 (约 30 秒) message, results = PerplexityClient().search("latest frameworks") # 智能分层搜索 (async,推荐默认) client = AllEnginesClient() message, results = asyncio.run(client.smart_search("query")) # 深度搜索,包含慢速引擎 message, results = asyncio.run(client.smart_search("query", include_slow=True)) # 页面提取 (接收 URL,而非查询) content, results = Crawl4AIClient().search("https://example.com") # URL 监控 cd = ChangeDetectionClient() cd.add_watch("https://github.com/trending", tag="github") # 健康检查 status = check_health() ``` ### SearchResult 模型 每个引擎都会返回 `SearchResult` 对象: ``` @dataclass(frozen=True, slots=True) class SearchResult: title: str url: str snippet: str source: str # engine name or "fused" engine: str | None = None # upstream engine (e.g., "google") score: float | None = None published: str | None = None category: str | None = None sources: tuple[str, ...] | None = None # engines that found this URL fused_score: float | None = None # weighted RRF score ``` ## 前置条件 **起步阶段无需任何前置条件。** Python 3.12 和 `pip install` 就足够了。下面 “外部 API”表格中的每一个引擎都是免费且无需密钥的,因此新克隆的项目 开箱即可搜索大约二十个引擎。任何你尚未设置的服务都会 报告自身不可用并被跳过,而不会导致搜索失败。 其余的都是你自行托管的。每一项都会增加相应的引擎;但全都不是 强制的。将匹配的 `MONSTER_*_URL` 指向你运行它的位置, 不设置即可保持该引擎处于关闭状态。 | 服务 | 默认端口 | 增加的功能 | |---------|--------------|------| | [SearXNG](https://github.com/searxng/searxng) | :8080 | 通用网页和新闻搜索,以及 synthesizer 撰写答案所依据的来源 | | [Vane](https://github.com/ItzCraworzyy/Perplexica) | :3004 | AI 搜索 (Perplexica 的一个 fork) | | [Khoj](https://github.com/khoj-ai/khoj) | :42110 | AI 聊天和搜索,匿名模式 | | [Local Deep Researcher](https://langchain-ai.github.io/langgraph/) | :8300 | 迭代多步研究 | | [Crawl4AI](https://github.com/unclecode/crawl4ai) | :11235 | 提取 JavaScript 渲染的页面 | | [changedetection.io](https://github.com/dgtlmoon/changedetection.io) | :8086 | `watch` 子命令 | | [Who-Dat](https://github.com/MoeClub/whodat) | :8083 | WHOIS 查询 | | [Zoekt](https://github.com/sourcegraph/zoekt) | :6070 | 跨自有仓库的 regex 代码搜索 | | [Meilisearch](https://github.com/meilisearch/meilisearch) | :7700 | 缓存,使得重复查询能瞬间返回 | | 任何 OpenAI 兼容的 LLM | :8080 | Synthesizer 生成的书面回答。[llama-server](https://github.com/ggml-org/llama.cpp), Ollama 和 vLLM 均可工作 | 外部 API(无需容器): | 服务 | 认证 | 备注 | |---------|------|-------| | [Marginalia](https://search.marginalia.nu/) | 无 | 独立的网络索引,遵循 CC-BY-NC-SA 4.0 协议 | | [Perplexity](https://www.perplexity.ai/) | Session cookie | 大约每月需手动刷新 | | [arXiv](https://arxiv.org/) | 无 | 预印本搜索 API | | [Semantic Scholar](https://www.semanticscholar.org/) | 无 | 学术论文搜索 | | [OpenAlex](https://openalex.org/) | 无 | 开放的学术作品 | | [OSV.dev](https://osv.dev/) | 无 | 漏洞数据库 | | [deps.dev](https://deps.dev/) | 无 | 包元数据 | | [Who-Dat](https://github.com/MoeClub/whodat) | 无 | WHOIS 查询 | | [GNews](https://news.google.com/) | 无 | Google News RSS | | [Archive.org](https://archive.org/) | 无 | CDX + 高级搜索 | 其中一个引擎 **fyin** 是一个 CLI 二进制程序而不是服务,因此它会在你 安装它的主机上通过 SSH 运行。在你设置 `MONSTER_SSH_HOST` 之前,它将保持关闭状态。请参阅 [通过 SSH 运行的引擎](#engines-that-run-over-ssh)。 `--health` 会向你展示当前的配置状态。它会对每个 引擎发出真实的查询,而不是仅 ping 端口,因此如果某个引擎做出了响应但返回的 内容不可用,它也会被报告为宕机。在下面的例子中,除了 fyin 之外,一切都已配置完毕,因为 fyin 没有设置 SSH 主机。 ![列出每个引擎的健康状态及延迟的健康检查输出](https://static.pigsec.cn/wp-content/uploads/repos/cas/f4/f4f3610a34889ec2f1a8fd2886df7907ea0a52aace357e12359b5c551fd4cb83.png) ## 架构 ``` src/monster_search/ ├── __init__.py # Public API exports ├── models.py # SearchResult frozen dataclass (sources, fused_score) ├── config.py # Config from MONSTER_* env vars ├── health.py # Container health probes ├── cli.py # CLI entry point (argparse + watch routing) ├── benchmark.py # Engine benchmarking (--benchmark) ├── fusion.py # Weighted RRF with metadata merge ├── _tiered.py # Tiered execution engine (tier1/2/3) ├── _router.py # Regex query classifier (9 categories) ├── _breaker.py # Per-engine circuit breakers ├── _dedup.py # MinHash LSH content deduplication ├── __main__.py # python -m support └── clients/ ├── _pool.py # Connection pool (reusable httpx clients) ├── searxng.py # SearXNG JSON API (sync + async) ├── marginalia.py # Marginalia independent search ├── perplexity_client.py # Perplexity AI synthesis (cookie auth) ├── synthesizer.py # AI synthesis (SearXNG + Crawl4AI + llama-server) ├── local_researcher.py # Local Deep Researcher LangGraph REST ├── crawl4ai_client.py # Crawl4AI page extraction ├── news.py # SearXNG news category, date-sorted ├── gnews.py # Google News RSS ├── archive_org.py # Archive.org CDX + Advanced Search ├── vane.py # Vane AI search (dynamic provider IDs) ├── khoj.py # Khoj AI chat/search (anonymous) ├── fyin.py # Fyin search over SSH ├── arxiv.py # arXiv preprint search ├── semantic_scholar.py # Semantic Scholar papers ├── openalex.py # OpenAlex works ├── osv.py # OSV.dev vulnerabilities ├── deps.py # deps.dev package info ├── whodat.py # Who-Dat WHOIS lookup ├── zoekt.py # Zoekt code search ├── meilisearch_client.py # Meilisearch result cache (background) ├── changedetection_client.py # changedetection.io URL monitoring └── all_engines.py # Composite: tiered parallel + RRF fusion ``` ## 配置 所有设置均通过 `MONSTER_*` 环境变量进行。将 `.env.example` 复制为 `.env`: ``` cp .env.example .env ``` 主要变量: | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `MONSTER_SEARXNG_URL` | `http://localhost:8080` | SearXNG 基础 URL | | `MONSTER_DEFAULT_ENGINE` | `all` | 默认 CLI 引擎 | | `MONSTER_MAX_RESULTS` | `5` | 每个引擎的结果数 | | `MONSTER_TIMEOUT` | `15` | HTTP 超时时间 (SearXNG) | | `MONSTER_PERPLEXITY_SESSION_TOKEN` | -- | Perplexity cookie (每月刷新) | | `MONSTER_PERPLEXITY_TIMEOUT` | `90` | Perplexity 超时时间 | | `MONSTER_VANE_URL` | `http://localhost:3004` | Vane AI 搜索 URL | | `MONSTER_VANE_TIMEOUT` | `300` | Vane 超时时间 | | `MONSTER_KHOJ_URL` | `http://localhost:42110` | Khoj AI 搜索 URL | | `MONSTER_KHOJ_TIMEOUT` | `300` | Khoj 超时时间 | | `MONSTER_ZOEKT_URL` | `http://localhost:6070` | Zoekt 代码搜索 URL | | `MONSTER_WHODAT_URL` | `http://localhost:8083` | Who-Dat WHOIS URL | | `MONSTER_MEILISEARCH_URL` | `http://localhost:7700` | Meilisearch 结果缓存 URL | | `MONSTER_MEILISEARCH_KEY` | -- | Meilisearch API 密钥 | | `MONSTER_LLAMA_URL` | `http://localhost:8080` | Synthesizer 的 OpenAI 兼容 endpoint | | `MONSTER_SYNTHESIZER_TIMEOUT` | `120` | Synthesizer 超时时间 | | `MONSTER_SSH_HOST` | -- | SSH 路由引擎的远程主机(见下文) | | `MONSTER_FYIN_ENV_FILE` | -- | 在 fyin 之前在该主机上 source 的可选环境变量文件 | | `MONSTER_FYIN_TIMEOUT` | `300` | Fyin SSH 超时时间 | | `MONSTER_LOCAL_RESEARCHER_URL` | `http://localhost:8300` | Local Deep Researcher URL | | `MONSTER_LOCAL_RESEARCHER_TIMEOUT` | `600` | Local Researcher 超时时间 | | `MONSTER_CRAWL4AI_URL` | `http://localhost:11235` | Crawl4AI URL | | `MONSTER_CRAWL4AI_TIMEOUT` | `60` | Crawl4AI 超时时间 | | `MONSTER_ARCHIVE_ORG_TIMEOUT` | `60` | Archive.org 超时时间 | | `MONSTER_CHANGEDETECTION_URL` | `http://localhost:8086` | changedetection.io URL | | `MONSTER_CHANGEDETECTION_API_KEY` | -- | changedetection.io API 密钥 | | `MONSTER_SEMANTIC_SCHOLAR_API_KEY` | -- | 免费密钥;如果没有密钥,该引擎将被跳过 | | `MONSTER_GREPAPP_ENABLED` | `false` | grep.app 默认关闭(它会在许多网络中触发 429 错误) | `.env.example` 列出了每一个变量及其真实的默认值。这两者会相互 检查,如果这里的默认值与代码不一致,那就是一个 bug。 ### 通过 SSH 运行的引擎 有两个引擎是通过 SSH 在 shell 中运行而不是使用 HTTP 通信的,在 你将 `MONSTER_SSH_HOST` 设置为 `ssh` 接受的值(`user@host`)之前,它们都处于关闭状态: - **fyin** 需要在该主机上安装 `fyin` 二进制文件。如果未设置主机,它将 报告为禁用状态,而不会在查询时报错。 - **archive.org** 查询默认直接发出。archive.org 会严格限制 某些 VPN 出口 IP 的速率 —— 在 CDX 上持续出现 HTTP 429,有时是 TCP 超时 —— 因此设置主机后会改为通过 `curl` 在那里路由 请求。仅当你自己的出口 IP 是被阻止的 IP 之一时才执行此操作。 此工具中的其他任何操作都不会打开 SSH 连接。 ## 测试 ``` # 单元测试:所有 HTTP 调用均为 mocked,无需服务。这是 CI 运行的内容。 pytest tests/ -m "not integration" # 集成测试:向真实服务发起真实请求。 pytest tests/test_integration.py -m integration # ...不包含每个耗时约两分钟的 AI 引擎。 pytest tests/test_integration.py -m "integration and not slow" # Lint pyflakes src/monster_search/ tests/ ``` 单元测试套件通过 `respx` 模拟 HTTP 且不进行任何网络调用,因此它是 确定的,可以在任何地方安全运行。 集成测试套件用于捕获那些已经悄悄 停止工作的引擎。搜索提供商会毫无预兆地更改 endpoint,而 模拟的测试在发生这种情况时仍会通过,因为 mock 依然返回 旧的数据结构。当所需的服务不可达或未配置时,那里的每个测试 都会自动跳过,因此部分的配置只会产生跳过而不会 导致失败。 ## 许可证 MIT 许可证。详情请参阅 [LICENSE](LICENSE)。
标签:Python, 信息检索, 元搜索, 搜索引擎, 无后门, 聚合搜索, 自托管, 请求拦截, 逆向工具