核心修复(v2.2.1): - 修复 Brotli 乱码 bug: build_browser_headers 智能声明 Accept-Encoding, 仅在 brotli 可用时才声明 br; fetch.py 双路径 br 解压(requests + stdlib) 此前 Chrome/Edge UA 抓取 example.com 等返回 br 的站点输出乱码 v2.2.0 新功能: - main() 拆分为 _handle_verify/_handle_research/_handle_batch/_handle_single - --cache-max-size MB: 缓存大小上限 + LRU 淘汰(默认 100MB) - --pages N: 多页聚合 + 跨页去重 - --research 跨角度合并: 新增 merged_results 字段 - --stream / --progress: JSON Lines 流式输出 + request_id 贯穿 - --dry-run / --save-config / --log-format json - --similarity-dedup / --throttle-* 参数化 - 15-UA 池 + PDF/docx 解析 + error_code 字段 文档与测试: - SKILL.md: 版本号唯一(元数据),删除版本标记干扰 - README.md: 测试数量 539 -> 544 - 544 passed (新增 5 个 Content-Encoding 解压测试)
22 KiB
SearXNG CLI 技能包
一个面向 AI Agent 的网络搜索与网页抓取技能包。AI 通过终端调用 CLI 脚本即可获得"搜索网络"和"抓取网页"两项核心能力,无需 API Key,路由通过用户自建的 SearXNG 实例完成。
这不是给人用的工具,而是给 AI 用的技能。 任何能执行终端命令的 AI Agent(Hermes、Claude Code、Codex、OpenCode、Cursor、Trae 等)均可直接调用。
为什么需要这个技能
AI Agent 在以下场景中需要实时网络信息:
- 查询最新新闻、文档、技术资料
- 验证事实、获取实时数据
- 抓取网页内容进行阅读和分析
传统方案依赖付费搜索 API(Google、Bing)或专有爬虫服务。本技能通过用户自建的 SearXNG 实例(隐私元搜索引擎,聚合 70+ 搜索服务)实现零成本、零 API Key、隐私可控的网络搜索能力。
AI 如何使用
搜索网络
python scripts/search.py -q "搜索词" -i https://your-searxng-instance
AI 调用后,stdout 输出 JSON 格式搜索结果,AI 可解析并使用:
{
"query": "搜索词",
"results": [
{"title": "...", "url": "https://...", "content": "摘要...", "engine": "google", "score": 1.0}
],
"suggestions": ["相关建议词"],
"answers": ["直接答案(如有)"]
}
抓取网页
python scripts/fetch.py -u "https://example.com" --extract markdown
AI 调用后,stdout 输出网页正文(text/html/markdown 三种格式),AI 可直接阅读分析。
输入输出约定(AI 必读)
| 通道 | 内容 | 说明 |
|---|---|---|
| stdout | 数据 | JSON/CSV/文本,AI 解析的唯一来源 |
| stderr | 日志 | 进度、警告、错误,AI 可忽略或用于调试 |
| exit 0 | 成功 | 有结果 |
| exit 1 | 失败 | 致命错误(所有实例不可用、参数错误等) |
| exit 2 | 空结果 | 搜索成功但无结果 |
错误处理:--format json 模式下,错误以 JSON 输出到 stdout(非 stderr),格式为 {"error": "...", "error_code": "E_NETWORK", "recovery_hint": "...", "exit_code": 1, "query": "..."},AI 可程序化捕获并按 recovery_hint 采取恢复行动。
错误码体系(error_code + recovery_hint 字段):
| 错误码 | 含义 | recovery_hint(节选) |
|---|---|---|
E_CONFIG |
配置错误(无实例) | 设置 -i/SEARXNG_INSTANCE/配置文件 |
E_AUTH |
认证失败(401/403) | 检查凭证、token 过期与权限 |
E_NETWORK |
网络错误(连接失败、5xx) | 重试退避、切换实例、检查代理 |
E_RATE_LIMIT |
限流(429) | 等待重试、降低频率、分散负载 |
E_PARSE |
解析错误 | 切换实例、切换 --method |
E_EMPTY |
空结果(exit 2) | 调整查询词、扩大 --time-range/--categories |
E_INPUT |
输入错误(参数/文件) | 检查语法、标志组合、文件路径 |
E_INTERNAL |
内部错误 | 用 --verbose 重跑并报告 |
E_UNSUPPORTED_MEDIA (v2.2.0) |
不支持的二进制媒体类型(PDF/docx/xlsx 解析失败) | 换 URL,或安装 pdftotext 用于 PDF 解析 |
流式输出与进度事件(AI 高级用法)
--stream:JSON Lines 流式输出,每条结果一行 JSON,AI 可增量处理:
{"type": "result", "result": {"title": "...", "url": "..."}}
{"type": "done", "schema_version": "1.0", "count": 10, "query": "..."}
搜索失败时输出 error 事件(含 recovery_hint):
{"type": "error", "error": "...", "error_code": "E_AUTH", "recovery_hint": "Verify credentials...", "query": "..."}
注意:--stream 仅在单查询 + --format json 下有效;与 --queries-file 或非 json 格式同用会立即报 E_INPUT。
--progress:进度事件流(JSON Lines 到 stderr),AI 可实时跟踪执行:
{"event": "start", "query": "...", "instances": 2, "request_id": "a1b2c3d4"}
{"event": "instance_try", "url": "https://inst1.example.com", "attempt": 1, "request_id": "a1b2c3d4"}
{"event": "instance_ok", "url": "https://inst1.example.com", "latency": 0.342, "results": 10, "request_id": "a1b2c3d4"}
{"event": "instance_fail", "url": "https://inst2.example.com", "error": "HTTP 503", "error_code": "E_NETWORK", "request_id": "a1b2c3d4"}
{"event": "cache_hit", "query": "...", "ttl": 30, "request_id": "a1b2c3d4"}
{"event": "page_ok", "pageno": 1, "results": 10, "request_id": "a1b2c3d4"}
{"event": "page_fail", "pageno": 2, "error": "HTTP 503", "request_id": "a1b2c3d4"}
{"event": "fetch_ok", "url": "...", "chars": 12345, "request_id": "a1b2c3d4"}
{"event": "done", "results": 10, "query": "...", "request_id": "a1b2c3d4"}
v2.2.0:每个事件含 request_id(8 位 hex,每次运行自动生成);--pages N 时新增 page_ok/page_fail 事件。
--dump-schema:输出当前版本的 JSON Schema 到 stdout 并退出,AI 可程序化发现字段名与类型,无需解析文档。
# AI 推荐用法:流式输出 + 进度事件
python scripts/search.py -q "research" -i https://your-instance --stream --progress
部署
前置条件
- Python 3.8+(3.11+ 开箱即用;3.8-3.10 使用
searxng.toml配置需pip install tomli) - 一个 SearXNG 实例 URL(自建或受信任的实例)
安装
git clone https://git.metona.cn/MetonaTeam/searxng-use-cli.git
无需安装依赖。search.py 仅使用 Python 标准库,开箱即用。
可选安装:
# 提升 fetch.py 抓取质量(HTTP 连接池 + HTML 解析)
pip install requests beautifulsoup4
# Python 3.8-3.10 使用 searxng.toml 配置文件时需要(3.11+ 内置 tomllib)
pip install tomli
配置实例
AI Agent 无需每次传入实例 URL 和认证信息,支持通过配置文件一次性设置:
- CLI 参数:
-i https://your-instance(最高优先级) - 环境变量:
export SEARXNG_INSTANCE="https://your-instance" - 配置文件:
./searxng.toml→~/.config/searxng-cli/searxng.toml→%APPDATA%/searxng-cli/searxng.toml(Windows)
# searxng.toml
[searxng]
instance = "https://your-searxng.example.com"
# 私有实例认证(可选,二选一):
auth_basic = "user:password" # Basic 认证
# auth_bearer = "sk-token-123" # Bearer Token(与 auth_basic 同时设置时 bearer 优先)
认证优先级(从高到低):--auth-* CLI 参数 > --auth-*-file 文件 > searxng.toml 配置 > 环境变量
安全提醒:配置文件中的明文密码有泄露风险。生产环境推荐使用
--auth-basic-file ~/.searxng_auth或环境变量。
参数参考
search.py — 网络搜索
python scripts/search.py -q "查询词" -i https://your-instance \
[--format json|brief|urls|csv] \
[--engines google,bing,brave] \
[--time-range day|week|month|year|none] \
[--language zh-CN] \
[--sort-by score|date|engine|none] \
[--no-dedup] \
[--similarity-dedup] [--similarity-threshold 0.85] \
[--max-results 10] \
[--pages N] \
[--fetch 3] [--fetch-report [json]] \
[--no-fallback] \
[--referer URL] \
[--request-delay 0.3] \
[--cache-ttl 30] [--cache-max-size 100] \
[--queries-file queries.txt] \
[--research "研究主题"] [--research-angles "a,b,c"] \
[--include-domain example.com] \
[--exclude-domain spam.com] \
[--proxy http://corp:8080] \
[--auth-bearer-file ~/.token] \
[--throttle-failure-threshold 3] [--throttle-pause-seconds 30] [--throttle-max-delay 10] \
[--log-format text|json] \
[--dry-run] [--save-config FILE] \
[--verify] \
[--stream] \
[--progress] \
[--verbose|-v] [--quiet]
| 参数 | 说明 | 默认值 |
|---|---|---|
-q / --query |
搜索词(必填,除非用 --verify/--queries-file/--clear-cache/--cache-stats) |
— |
-i / --instance |
SearXNG 实例 URL,逗号分隔实现故障转移 | — |
-f / --format |
输出格式:json/brief/urls/csv | json |
--engines |
搜索引擎列表 | google,bing,brave,duckduckgo,startpage,wikipedia,wikidata |
-t / --time-range |
时间范围:day/week/month/year/none | year |
-s / --safesearch |
安全搜索:0/1/2 | 0(关闭) |
-l / --language |
语言代码 | — |
-p / --pageno |
页码 | 1 |
--sort-by |
排序:score/date/engine/none | score(降序) |
--no-dedup |
禁用跨引擎去重 | 默认开启去重 |
--max-results |
限制结果数(去重+排序后截取) | 不限 |
--fetch N |
自动抓取前 N 个结果的网页正文 | 0(不抓取) |
--fetch-report |
v2.0.0 抓取报告(stderr,含 WAF/兜底/限流统计) | 关闭 |
--no-fallback |
v2.0.0 禁用 Wayback Machine 兜底 | 默认启用兜底 |
--referer |
v2.0.0 设置 Referer 头 | 实例 URL |
--request-delay |
v2.0.0 抓取请求间隔秒数(自适应限流可能增大) | 0.3 |
--cache-ttl |
缓存分钟数 | 0(不缓存) |
--queries-file |
批量查询文件(每行一个查询) | — |
--research |
v2.1.0 研究模式:给定主题自动扩展 5 个多角度查询 | — |
--include-domain |
域名白名单 | — |
--exclude-domain |
域名黑名单 | — |
--proxy |
代理 URL | — |
--auth-bearer-file |
Bearer Token 文件 | — |
--auth-basic-file |
Basic Auth 文件 | — |
--verify |
实例健康检查模式 | — |
--config |
指定配置文件 | 自动发现 |
--stream |
JSON Lines 流式输出(每条结果一行) | 关闭 |
--progress |
进度事件(JSON Lines 到 stderr) | 关闭 |
-v / --verbose |
调试日志 | — |
--quiet |
仅输出警告和错误 | — |
--pages N |
v2.2.0 分页聚合:一次获取 N 页并跨页去重合并 | 1 |
--similarity-dedup |
v2.2.0 相似度去重(SimHash + Jaccard) | 关闭 |
--similarity-threshold |
v2.2.0 相似度阈值 | 0.85 |
--log-format |
v2.2.0 日志格式:text/json | text |
--dry-run |
v2.2.0 预览模式(不发 HTTP 请求) | 关闭 |
--throttle-failure-threshold |
v2.2.0 限流失败阈值 | 3 |
--throttle-pause-seconds |
v2.2.0 429 全局暂停秒数 | 30 |
--throttle-max-delay |
v2.2.0 限流最大延迟秒数 | 10 |
--research-angles |
v2.2.0 自定义研究角度(逗号分隔) | 默认 5 角度 |
--save-config |
v2.2.0 保存当前参数为 searxng.toml 并退出 | — |
--cache-max-size |
v2.2.0 缓存大小上限(MB) | 100 |
--fetch-report json |
v2.2.0 JSON 格式抓取报告 | text |
fetch.py — 网页抓取
python scripts/fetch.py -u https://example.com \
--extract text|html|markdown \
[--encoding gbk] \
[--max-size 5242880] \
[--timeout 15] \
[--retries 3] \
[--no-redirect] \
[--referer https://google.com/] \
[--proxy http://corp:8080] \
[--auth-bearer-file ~/.token]
| 参数 | 说明 | 默认值 |
|---|---|---|
-u / --url |
目标 URL(必填) | — |
-e / --extract |
提取模式:text/html/markdown | text |
--encoding |
强制字符编码 | 自动检测 |
--max-size |
最大字节数 | 不限 |
--timeout |
超时秒数(v2.0.0 内部拆分为 connect/read) | 15 |
--retries |
重试次数 | 3 |
--no-redirect |
不跟随重定向 | 跟随 |
--no-fallback |
v2.1.0 禁用 Wayback Machine 兜底 | 默认启用兜底 |
--referer |
设置 Referer 头(v2.0.0 反爬措施) | — |
--proxy |
代理 URL | — |
--auth-bearer-file |
Bearer Token 文件 | — |
--auth-basic-file |
Basic Auth 文件 | — |
能力清单
v2.2.1 修复
- Brotli 乱码修复:
build_browser_headers()智能声明Accept-Encoding——仅当本机安装了 brotli/brotlicffi 包时才声明br,避免服务器返回 Brotli 压缩字节而 requests 无法自动解压导致全页乱码 fetch.py双路径 br 解压:requests 路径和 stdlib urllib 路径都添加了 Brotli 手动解压逻辑(作为双保险,应对代理/CDN 强制返回 br 的边缘情况)- 此前 bug 表现:Chrome/Edge UA 抓取 example.com 等返回
Content-Encoding: br的站点时,输出 302 字符乱码(gzip 二进制被当作文本解码);修复后输出 127 字符正常文本
v2.2.0 新功能
--pages N分页聚合:一次获取 N 页结果并跨页去重合并,每页独立缓存(cache key 含 pageno),进度事件新增page_ok/page_fail- 缓存治理:缓存大小上限 + LRU 淘汰,新增
--cache-max-size MB(默认 100MB);stats()新增total_bytes/max_size_bytes/evicted_count/utilization_pct字段;新增evict_expired()主动清理方法 --similarity-dedup相似度去重:基于标题 SimHash + Jaccard 相似度,默认关闭;--similarity-threshold(默认 0.85)控制严格程度;O(n²) 复杂度,结果数 > 500 时自动跳过- PDF/文档解析:fetch 支持解析 PDF(pdftotext subprocess)、
.docx/.xlsx(stdlib zipfile);不支持的二进制类型返回E_UNSUPPORTED_MEDIA --log-format json结构化日志:每行输出 JSON 对象{ts, level, logger, msg, request_id},便于 AI Agent 程序化解析- request ID 贯穿:每次运行自动生成 8 位 hex request_id,贯穿所有日志和进度事件
--dry-run预览模式:不发 HTTP 请求,打印{action, url, params, headers_count}JSON 到 stdout;支持 search/research/batch/verify 四种模式- AdaptiveThrottle 参数可配置:新增
--throttle-failure-threshold(默认 3)、--throttle-pause-seconds(默认 30)、--throttle-max-delay(默认 10) --research-angles自定义研究角度:覆盖默认 5 角度,每个角度直接作为查询后缀--save-config FILE:将当前 CLI 参数保存为 searxng.toml 配置文件并退出--fetch-report json:输出完整 JSON 报告(含 items 数组 + summary 摘要);原--fetch-report(无参数)保持 text 格式- UA 池更新到 2026 年版本:Chrome 138-140 / Edge 138 / Firefox 140 / Safari 18,池移至
_config.py(SSOT) - readability-lite 按语言调整:CJK 内容 100 字符阈值,其他 200 字符阈值
- classify_error 改用异常链(内部改进)、
_domain_ua_cache加锁(内部改进)
搜索
- 多实例故障转移 + 并行探测
- 指数退避重试(429/5xx/连接错误)
- 跨引擎去重(忽略 utm_*/gclid 等跟踪参数)
- 结果排序(score/date/engine)
- 域名白名单/黑名单
- 批量查询(
--queries-file) - v2.1.0 研究模式(
--research):给定主题自动扩展 5 个多角度查询(overview/profile/background/works/review),输出含research_topic和research_queries元数据- v2.1.1 增强:跨角度合并去重,输出
merged_results字段;根据主题语言自动切换中英文后缀(中文主题用"简介/经历/作品/评价",英文主题用"profile/background/works/reviews")
- v2.1.1 增强:跨角度合并去重,输出
- 实例健康检查(
--verify)
输出
- JSON(默认,含完整元数据)
- brief(标题+URL+摘要)
- urls(纯 URL 列表)
- CSV(表格导出)
- 结构化 JSON 错误输出
网页抓取
- text:提取纯文本
- html:原始 HTML
- markdown:增强 Markdown 转换(GFM 表格、代码块、引用块、嵌套列表、定义列表)
- v2.0.0 readability-lite:
<article>/<main>缺失时,用文本密度算法选最可能正文的<div>(v2.2.0:CJK 内容 100 字符阈值,其他 200 字符阈值) - v2.2.0 PDF/文档解析:支持解析 PDF(pdftotext subprocess)、
.docx/.xlsx(stdlib zipfile);不支持的二进制类型返回E_UNSUPPORTED_MEDIA
反爬与抓取稳定性(v2.0.0)
- 浏览器指纹头:
build_browser_headers()发送完整 Sec-Ch-Ua / Sec-Fetch-* / Accept-Language,不仅靠 User-Agent - 15 个 UA 池(v2.2.0 更新):Chrome 138-140 / Edge 138 / Firefox 140 / Safari 18 × Windows/macOS/Linux;UA 池移至
_config.py(SSOT),common.py 通过导入引用 - 确定性 UA 轮换:
get_ua_for_domain()用 SHA-256 为每个域名固定一个 UA(会话内稳定,跨进程可复现) - requests.Session 复用:连接池 + cookie 持久化 + TLS 会话恢复
- 超时分离:
(connect, read)元组,避免大页面下载中途超时浪费已建连接 - Retry-After 遵守:429/503 响应读取 Retry-After header(数字或 HTTP date)作为最小重试延迟
- 退避封顶 60s:原公式无上限,N=10 时达 1536s 会卡死进程
- WAF 指纹库:识别 Cloudflare / Imperva / PerimeterX / DataDome / Akamai / 通用反爬页,全文档扫描(非仅前 2000 字符)
- Wayback Machine 兜底:404/403/超时自动尝试
https://web.archive.org/web/2/<url>,默认启用,--no-fallback关闭 - v2.1.0 fetch.py 独立调用也支持 Wayback 兜底(之前仅 search.py --fetch 路径有)
- v2.1.0 被墙站点智能回退:
is_hard_blocked_domain()识别百度搜索/百度百科/知乎/微博/微信公众号/豆瓣等强反爬站点,403 时自动优先 Wayback- v2.1.1 精确化:
baidu.com从子域匹配改为精确子域列表(www/baike/zhidao/tieba/wenku),pan.baidu.com(网盘)/cloud.baidu.com(智能云)不再被误伤
- v2.1.1 精确化:
- 自适应限流:
AdaptiveThrottle状态机,连续 3 次失败自动翻倍延迟 + 减半并发,429 触发全局暂停 30s- v2.1.1:
report_failure新增error_code参数,优先用结构化E_RATE_LIMIT检测 429(原字符串匹配"429"会漏判"Too Many Requests");fetch_page返回结果新增error_code字段 - v2.2.0:原硬编码值现可通过 CLI 配置——
--throttle-failure-threshold(默认 3)、--throttle-pause-seconds(默认 30)、--throttle-max-delay(默认 10)
- v2.1.1:
--fetch-report:结构化抓取报告到 stderr(每 URL 状态/WAF 类型/兜底方式/字符数 + JSON 摘要);v2.2.0:--fetch-report json输出完整 JSON 报告(items 数组 + summary 摘要)--referer/--request-delay:精细控制 Referer 头和请求间隔- fetch 结果新增字段:
anti_bot_detected(bool)、waf_type(str|null)、fallback_used(str|null)、error_code(str|null,v2.1.1)
缓存
- SQLite 缓存(
--cache-ttl),相同查询在 TTL 内跳过网络 --clear-cache/--cache-stats管理缓存- v2.2.0 缓存治理:
--cache-max-size MB(默认 100MB)大小上限 + LRU 淘汰;stats()新增total_bytes/max_size_bytes/evicted_count/utilization_pct字段;新增evict_expired()主动清理方法
网络
- 代理支持(
--proxy) - 认证(Bearer/Basic,支持 CLI/文件/配置文件/环境变量四级优先级)
searxng.toml配置auth_basic/auth_bearer字段,AI Agent 一次配置即可- 凭证文件权限警告(POSIX)
工程
- 共享
common.py(统一重试/字符集/认证/日志/UA池/浏览器头/退避) - 结构化日志(
--verbose/--quiet) - UTF-8 stdout 强制(
force_utf8_stdout(),修复 Windows GBK 崩溃) - Windows 配置路径发现(
%APPDATA%/searxng-cli/) - fetch.py 失败诊断增强(
status_code=/cause=/url=字段) - 结构化错误码 +
recovery_hint恢复建议(E_NETWORK/E_AUTH/E_RATE_LIMIT等) - JSON 输出含
schema_version字段,--dump-schema输出 JSON Schema 文档 - JSON Lines 流式输出(
--stream,含error事件类型) - 进度事件(
--progress,含instance_try/instance_ok/instance_fail,JSON Lines 到 stderr) - batch 模式统一 schema(
status字段区分成功/失败) - 544 个单元+集成测试
跨 Agent 兼容性
本技能与 Agent 无关——任何能执行终端命令的 AI 均可使用:
| Agent | 调用方式 |
|---|---|
| Hermes | python scripts/search.py -q "..." -i https://your-instance |
| Claude Code | 同上,通过终端工具调用 |
| Codex (OpenAI) | 同上 |
| OpenCode | 同上 |
| Cursor | 同上 |
| Trae | 同上 |
设计要点:
- 零外部依赖(
search.py仅标准库) - 脚本自注入目录到
sys.path,可从任意工作目录运行 - stdout 纯数据,stderr 纯日志
- 无 Agent 专属 API 调用,纯 CLI,跨平台可移植
测试
pip install pytest
pytest -q
539 个测试覆盖:缓存操作、认证解析、域名过滤、Markdown 转换、搜索逻辑、集成流程、日志配置、HTML 回退、自动抓取、健康检查、输出格式化、实例解析、并行搜索、CLI 端到端、错误码分类、流式输出、进度事件、配置文件认证、schema_version、recovery_hint、batch 统一 schema、--dump-schema、UTF-8 stdout 强制、Windows APPDATA 路径、v2.0.0 浏览器指纹头、WAF 反爬检测(v2.0.1 收窄误判 + title 精准检测)、Wayback Machine 兜底(v2.0.1 修复 HTTP 200 反爬页触发)、自适应限流(v2.1.1 结构化 error_code 检测 429)、v2.1.0 Wayback 共享逻辑(should_try_wayback/build_wayback_url)、被墙站点智能回退(v2.1.1 精确化 baidu 子域,pan/cloud 不再误伤)、--research 研究模式(v2.1.1 跨角度合并去重 + 中英文双语后缀)、--time-range week 支持(v2.1.1)、stdlib gzip/deflate 解压(v2.1.1)、实例引擎挂起检测(v2.1.1 _warn_unresponsive_engines)。
项目结构
├── scripts/
│ ├── search.py # 搜索(多实例故障转移/缓存/批量/域名过滤)
│ ├── fetch.py # 网页抓取(text/markdown 提取)
│ ├── common.py # 共享工具(认证/重试/字符集/日志)
│ ├── cache.py # SQLite 结果缓存
│ └── _config.py # 版本号 + User-Agent
├── tests/ # pytest 单元+集成测试
├── SKILL.md # 完整技能文档(Agent 技能描述)
├── pytest.ini # 测试配置
└── README.md
许可证
MIT