SearXNG 的工作原理:从一次搜索请求到结果聚合(技术向)


SearXNG 是一个 元搜索(metasearch)聚合器:它不像 Google/Bing 那样自己维护一个覆盖全网的倒排索引库,而是把你的查询同时发给多个搜索引擎/数据源,然后把返回结果进行 标准化、去重、重排,再统一展示。

这篇文章从工程视角拆开讲:一次搜索请求在 SearXNG 里到底经历了什么、每一层在解决什么问题,以及为什么“自建元搜索”会遇到验证码/封禁、以及如何权衡。


1. 典型架构:SearXNG 站在你和搜索引擎之间

把它看成三层会更清晰:

  1. Web/UI 层:接收用户请求,输出 HTML/JSON
  2. 引擎适配层(engines):把 query 翻译成每家引擎的请求,并解析返回
  3. 聚合层(aggregation):合并、去重、评分、排序

数据流大致如下:

浏览器/客户端
   │  (q=... & category=...)

SearXNG
   │  并发请求
   ├────────────► Engine A (HTML/JSON)
   ├────────────► Engine B (HTML/JSON)
   ├────────────► Engine C (HTML/JSON)

标准化结果列表

去重/融合/评分

输出 HTML/JSON

隐私点:对外部引擎来说,请求来源是 SearXNG 服务器的出口 IP,而不是用户的真实 IP。


2. 一次搜索请求的生命周期(request lifecycle)

当你在 SearXNG 输入关键词并点击搜索,大体会经历:

2.1 参数解析与规范化

SearXNG 会把请求参数归一化成内部统一模型,例如:

  • query 文本
  • 语言/地区(language / locale
  • 搜索类别(general / images / news / videos 等)
  • 时间范围(过去一天/一周/一月)
  • 安全搜索等级
  • 页码、每页数量

它的意义是:不同引擎的参数体系不一致,先把“用户意图”抽象出来。

2.2 选择引擎集合(engine selection)

你配置里启用的引擎,会按 category 过滤。例如:

  • 你搜“图片”,只会调图片引擎
  • 你搜“新闻”,只会调新闻引擎

同时还会考虑:

  • 引擎是否健康(最近是否大量失败)
  • 引擎是否需要 key
  • 引擎是否被限制(限速/并发)

2.3 并发调度与超时控制

核心点:同一查询会被拆成多个独立的 engine task 并行执行

工程上通常会有:

  • 单引擎请求超时(避免被慢引擎拖死)
  • 全局超时(前端体验不能无限等)
  • 失败隔离(某个引擎挂了不影响整体)

所以你常看到:

  • 某些引擎 0 results 或报错
  • 但整体仍能返回结果

3. 引擎(engine)适配:最“脆弱”也最核心的部分

每个引擎模块基本都包含:

3.1 请求构造(build request)

要解决的问题:

  • A 引擎用 q=,B 引擎用 query=
  • 语言参数格式不一样(hl=zh-CN / lr=lang_zh-CN / setlang=...
  • 时间筛选方式不一样
  • 有的走 HTML 页面,有的走 JSON API

以及请求指纹:

  • User-Agent
  • Accept-Language
  • Referer
  • Cookie(通常尽量不用,保持“无状态”)

3.2 结果解析(parse response)

这是最容易坏的一环:

  • 引擎页面结构经常变(CSS selector 改、DOM 改)
  • 反爬策略变化会导致返回验证码页/挑战页

解析输出会统一成类似结构:

  • title
  • url
  • content/snippet
  • engine(来源)
  • publishedDate(若可得)
  • thumbnail(若可得)

理解重点:SearXNG 不负责“检索”,它负责“把别人检索的结果稳定转成统一格式”。


4. 聚合层:去重、融合、排序怎么做

把多个引擎结果拉回来以后,SearXNG 会做“结果融合”。这部分通常包含:

4.1 URL 规范化(canonicalization)

为了去重,需要把 URL 做标准化,例如:

  • 去掉常见跟踪参数:utm_*reffbclid
  • http/https 统一
  • 去掉末尾 /

否则同一页面会因为参数不同被当成多条结果。

4.2 去重(dedup)

常见策略是:

  • URL 相同 → 合并
  • URL 不同但高度相似(同域名同路径差一点)→ 可能合并(依实现)

合并后通常会保留:

  • “被哪些引擎返回过”
  • “出现次数/投票数”

4.3 评分与重排(scoring / rerank)

SearXNG 不会重建 PageRank,但会做轻量排序:

  • 同一条结果被多个引擎返回 → 通常加分(类似投票)
  • 引擎权重(engine weight)→ 你更信任谁就给谁更大权重
  • 时间过滤(新闻/博客)→ 新鲜度可影响

这也是为什么:

  • 多引擎聚合能减少“单引擎偏差”
  • 但也可能放大“同质化来源”的排名

5. 隐私机制:为什么它能“保护用户”

SearXNG 的隐私优势主要来自:

  1. 搜索引擎看不到用户真实 IP:它只看到你的 SearXNG 出口 IP
  2. 可配置不记录用户行为:不做画像、不做广告 ID
  3. 可自定义请求头/参数清理:减少可识别信息
  4. 可配出口代理:让 SearXNG 自己通过代理访问引擎(进一步隔离)

但这也带来代价:

  • 如果你的出口 IP 被引擎判定为“机器人/异常流量”,更容易触发验证码

6. 为什么自建会遇到验证码/封禁(反爬视角)

对引擎来说,SearXNG 的访问模式往往“像机器人”:

  • 同一 IP 在短时间内访问大量 query
  • 请求头/指纹较固定
  • 缺少真实用户的浏览器行为信号

因此常见现象:

  • 返回 challenge 页面(而不是结果)
  • 返回空结果或 429/403
  • 解析器失效(因为拿到的不是搜索结果 DOM)

工程应对一般是:

  • 限速与并发控制(最重要)
  • 选择更稳定/更友好的引擎
  • 出口代理池(成本更高)
  • 在可行时使用官方 API(更稳定但可能要钱/要 key)

7. 缓存与性能:为什么很多实例需要缓存

一条 query 如果被多个用户重复搜索(比如热点关键词),可以缓存:

  • 降低对外部引擎的请求压力
  • 减少触发反爬
  • 提升响应速度

但缓存也有 trade-off:

  • 时效性下降
  • 对“个性化/地区化结果”可能不适用

8. 实用建议:如何把 SearXNG 调到“更稳、更快、更少验证码”

如果是自建(尤其公开给多人用),我通常建议:

  • 减少引擎数量:挑 3~6 个稳定引擎即可,不要 20 个全开
  • 控制并发与速率:宁可慢一点也不要被封
  • 优先选择 API 型引擎(可选):稳定但可能需要 key
  • 把实例放在“出口质量好”的网络:出口 IP 风险小很多
  • 加反向代理与基础防护:避免被人当成“开放代理”滥用

如果你把你当前 settings.yml 的两段配置贴出来:

  • engines:(启用了哪些引擎、权重)
  • outgoing:(是否走代理、超时并发)

我可以按你实际配置做一次“针对性调参建议”(哪些引擎该关、权重怎么配、并发怎么设)。