Community写作与编辑github.com

Sakurakilove/local-search

完全在用户机器上运行的网页搜索技能,无需 Z.AI / 云 SDK 依赖。通过 HTML 抓取 DuckDuckGo / Bing / Google,并自动提供引擎回退。

local-search 是什么?

这是一个本地运行的网页搜索技能,称为 `local-search`,完全在用户自己的机器上执行,无需任何云 SDK 或 API 密钥。它通过直接 HTML 抓取 DuckDuckGo、Bing 和 Google 这三个公共搜索引擎来工作,并能自动在它们之间回退。如果某个引擎(例如 Google 在数据中心 IP 上)因速率限制而失败,协调器会静默地尝试下一个引擎,通常能确保搜索成功。该技能返回结构化的结果,遵循通用的 `SearchFunctionResultItem` 模式,包含 URL、名称、摘要等字段,并额外提供来源引擎、原始 HTML 和相关性分数等扩展信息。它支持 Node.js 18+ 和纯 TypeScript ESM,可通过 CLI 或程序化 SDK 使用,非常适合需要实时信息、最新文档或事实核查,且不想依赖第三方 API 的开发者。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add Sakurakilove/local-search

Installed? Explore more 写作与编辑 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

预览

来自技能 README

ClawHub
版本
许可证: MIT
Node

文档

本地搜索技能

具有自动引擎回退的本地网页搜索。 直接 HTML 抓取 DuckDuckGo / Bing / Google · 对抗速率限制 · 标准结果模式。

ClawHub 版本 许可证: MIT Node

此技能直接从您的机器调用公共搜索引擎。无需 API 密钥,无需 SDK,无需网络跳转。 如果某个引擎对您进行速率限制,协调器会静默地回退到下一个引擎——因此,即使在 Google 被屏蔽的数据中心 IP 上,调用通常也能在首次尝试时成功。

每个结果都是一个 SearchFunctionResultItem,包含标准的 7 个字段(url、name、snippet、host_name、rank、date、favicon)以及三个可选扩展字段:source_engine、raw_html、score。针对其他任何形状相似的网页搜索技能编写的消费代码可以在此处无需修改地运行。

✨ 亮点

  • 零云 SDK 依赖——仅需 cheerio(HTML 解析器)和 Node 内置的 fetch。
  • 三个引擎,自动回退——当 engine: "auto"(默认)时,DuckDuckGo → Bing → Google。
  • 区域感知——--locale en-US / zh-CN / ja-JP / 任意 BCP-47 标签。对于非美国 IP 尤为重要,否则 Bing 会为英文查询提供本地化结果。
  • 时效性过滤——--recency-days 7 限制为过去一周的结果。DDG 支持精确 N 天;Bing/Google 使用天/周/月桶。
  • 标准结果模式——url / name / snippet / host_name / rank / date / favicon 字段,形状与 ClawHub 注册表中的其他网页搜索技能相同。
  • CLI + SDK——一次性使用 tsx bin/web-search.ts <query>,或在代码中使用 import { search } from "local-search"。
  • 纯 TypeScript ESM——通过 tsx 在 Node 18+ 上运行,或通过 bun 零配置运行。

🚀 快速开始

# 1. 安装(一个运行时依赖:cheerio)
cd skills/local-search && npm install

# 2. 搜索(跨 DDG → Bing → Google 自动回退)
tsx bin/web-search.ts "artificial intelligence"

# 3. 指定引擎和区域
tsx bin/web-search.ts "machine learning" --engine bing --locale en-US --num 5

# 4. 最近新闻(JSON 格式)
tsx bin/web-search.ts "AI breakthroughs" --recency-days 7 --json -o ai_news.json

程序化使用:

import { search } from "local-search";

const outcome = await search("What is the capital of France?", { num: 5 });
if (outcome.success) {
  console.log(`由 ${outcome.engine} 回答,耗时 ${outcome.elapsedMs} 毫秒`);
  outcome.results.forEach(r => console.log(`- ${r.name}\n  ${r.url}`));
}

🎯 何时使用此技能

当用户需要存在于公共网络上的信息时,请使用 local-search——超出模型训练数据范围的信息:

  • 实时信息:当前新闻、股票价格、天气、体育比分
  • 最新文档:框架发布说明、API 变更、最近发表的论文
  • 事实核查:对照实时网络来源验证声明
  • 研究:收集关于某个主题的多个来源,比较观点
  • 内容发现:查找教程、博客文章、近期演讲
  • 竞争/市场分析:竞争对手公告、行业趋势
  • 学术查阅:查找论文、引文、作者页面

🔄 引擎对比

引擎端点API 密钥住宅 IP数据中心 IP时效性
DuckDuckGohtml.duckduckgo.com/html/ (GET)无✅ 高⚠️ 负载下有限制df=d<N>(精确天数)
Bingwww.bing.com/search无✅ 高✅ 高`freshness=d1
Googlewww.google.com/search无⚠️ 中❌ 低(enablejs 墙)`tbs=qdr:d

engine: "auto" 按顺序尝试它们:DuckDuckGo → Bing → Google,返回第一个非空结果集。从数据中心 IP 出发,有效链是 DDG → Bing(Google 通常被屏蔽);从住宅 IP 出发,三个引擎都可用。编辑 src/engines/index.ts 中的 AUTO_ENGINE_ORDER 以更改优先级。

📦 安装路径

推荐路径:{project_path}/skills/local-search

将此技能包解压到项目中的上述路径。

先决条件

  • Node.js >= 18(使用内置的全局 fetch)。
  • 一个 npm 依赖:cheerio(HTML 解析器)。
  • 可用的互联网连接——技能直接调用公共搜索引擎。

在技能目录中安装一次:

cd {project_path}/skills/local-search
npm install            # 或:bun install / pnpm install

此技能是纯 TypeScript ESM。您可以通过 tsx(推荐,对开发者友好)或 bun(零配置)运行。在 Node 22+ 上,node --experimental-strip-types bin/web-search.ts 也能以运行时无关的方式工作。

为何选择本地?

方面云搜索技能此技能 (local-search)
搜索后端云函数 / API直接 HTTP 到 DuckDuckGo / Bing / Google
API 密钥 / SDK必需无
网络路径客户端 → 云 → 搜索引擎客户端 → 搜索引擎
故障处理取决于 SDK跨 3 个引擎自动回退
结果模式SearchFunctionResultItem(7 个字段)相同 7 个字段 + 3 个可选扩展字段
CLI特定 SDKtsx bin/web-search.ts

架构

local-search/
├── SKILL.md                 ← 您在这里
├── LICENSE.txt
├── package.json             ← 声明 `cheerio` 依赖
├── tsconfig.json
├── bin/
│   └── web-search.ts        ← CLI 入口
├── src/
│   ├── index.ts             ← 公共 SDK 导出
│   ├── search.ts            ← 带自动回退的协调器
│   ├── types.ts             ← SearchFunctionResultItem + 选项
│   └── engines/
│       ├── _shared.ts       ← fetch / parse 辅助函数
│       ├── duckduckgo.ts    ← POST https://html.duckduckgo.com/html/
│       ├── bing.ts          ← GET https://www.bing.com/search
│       ├── google.ts        ← GET https://www.google.com/search
│       └── index.ts         ← 引擎注册表 + AUTO_ENGINE_ORDER
└── scripts/
    └── web_search.ts        ← 快速入门示例

唯一的运行时依赖是 cheerio(HTML 解析器),在 package.json 中声明。Node 18+ 的内置 fetch 负责网络层——此包中未导入任何其他 SDK。

CLI 用法

CLI 位于 bin/web-search.ts。通过 tsx、bun 或任何 TS 感知的运行器运行。

基本搜索

# 默认:自动引擎,10 个结果,人类可读输出
tsx bin/web-search.ts "artificial intelligence"

# 限制结果数量
tsx bin/web-search.ts "machine learning" --num 5
# (短选项也有效)
tsx bin/web-search.ts "machine learning" -n 5

指定引擎

# 强制仅使用 DuckDuckGo
tsx bin/web-search.ts "latest tech news" --engine duckduckgo
# 强制仅使用 Bing
tsx bin/web-search.ts "latest tech news" --engine bing
# 强制仅使用 Google(质量最高,最可能被限速)
tsx bin/web-search.ts "latest tech news" --engine google
# 默认——尝试 DDG → Bing → Google,返回第一个非空
tsx bin/web-search.ts "latest tech news" --engine auto

时效性过滤

# 过去 7 天的结果
tsx bin/web-search.ts "cryptocurrency news" --num 10 --recency-days 7
# (短选项)
tsx bin/web-search.ts "cryptocurrency news" -r 7

保存结果为 JSON

# 将 JSON 写入文件(抑制人类可读横幅)
tsx bin/web-search.ts "climate change research" --num 5 --json -o search_results.json

# 或将 JSON 通过管道输出到标准输出
tsx bin/web-search.ts "AI breakthroughs" --num 3 --recency-days 1 --json > ai_news.json

静默模式(脚本 / 管道)

# 抑制“引擎/计时”横幅——仅打印结果
tsx bin/web-search.ts "react hooks" --quiet

CLI 参数

标志短选项描述
--num <N>-n结果数量(默认:10,最大:50)
--engine <id>-educkduckgo | bing | google | auto(默认:auto)
--recency-days <N>-r限制为过去 N 天的结果(默认:0 = 无过滤)
--timeout <ms>—每个引擎的超时时间(毫秒)(默认:8000)
--json—输出 JSON 而非人类可读输出
--output <path>-o将 JSON 写入文件而非标准输出
--pretty—美化 JSON(默认开启;传递 --no-pretty 以禁用——尚未支持,改为省略 --json)
--quiet-q抑制引擎信息横幅
--help-h显示帮助

搜索结果结构

每个结果项都是一个 SearchFunctionResultItem:

interface SearchFunctionResultItem {
  // ----- 标准字段(在 ClawHub 网页搜索技能中共享的形状) -----
  url: string;          // 结果的完整 URL
  name: string;         // 页面标题
  snippet: string;      // 预览文本 / 描述
  host_name: string;    // 域名(例如 "en.wikipedia.org")
  rank: number;         // 在引擎结果集中从 1 开始的排名
  date: string;         // 发布日期 / 更新日期;未知时为 "N/A"
  favicon: string;      // 图标 URL(Google S2)

  // ----- 扩展字段(local-search 新增) -----
  source_engine: "duckduckgo" | "bing" | "google";
  raw_html?: string;    // 摘要元素的原始 HTML(可选)
  score?: number;       // 启发式相关性分数 [0, 100](可选)
}

SDK 用法

如果您正在编写 TypeScript/JavaScript 代码(而非运行 CLI),请从 src/index.ts 导入:

简单搜索

import { search } from "local-search";

const outcome = await search("What is the capital of France?", { num: 5 });

if (outcome.success) {
  console.log(`使用的引擎:${outcome.engine}`);
  console.log(`尝试顺序:${outcome.enginesTried.join(" → ")}`);
  console.log(`耗时:${outcome.elapsedMs}毫秒`);
  for (const item of outcome.results) {
    console.log(`- ${item.name}  [${item.source_engine}]`);
    console.log(`  ${item.url}`);
    console.log(`  ${item.snippet}`);
  }
} else {
  console.error("搜索失败:", outcome.error);
  if (outcome.errors) {
    // 自动模式:查看哪些引擎尝试过及其报告
    for (const e of outcome.errors) {
      console.error(`  ${e.engine}:`, e.error);
    }
  }
}

失败时抛出异常的变体

import { searchOrThrow, AllEnginesFailedError } from "local-search";

try {
  const results = await searchOrThrow("JavaScript frameworks", { num: 10 });
  console.log(results);
} catch (err) {
  if (err instanceof AllEnginesFailedError) {
    console.error("所有引擎均失败:", err.errors);
  } else {
    console.error("单引擎错误:", err);
  }
}

指定引擎

import { search } from "local-search";

// 跳过回退链——仅使用 DuckDuckGo。
const outcome = await search("quantum computing applications", {
  num: 8,
  engine: "duckduckgo",
});

时效性过滤

const outcome = await search("genomics research", {
  num: 5,
  recency_days: 30, // 过去 30 天
});

自定义 fetch(测试 / 边缘运行时)

const outcome = await search("hello world", {
  fetchImpl: myMockFetch, // 任何符合 WhatWG-fetch 标准的函数
  userAgent: "my-bot/1.0",
  timeoutMs: 5000,
});

引擎后端

DuckDuckGo (duckduckgo)

  • 端点:https://html.duckduckgo.com/html/(POST 表单 q=...)
  • 无需 API 密钥。受到粗略的速率限制——持续高负载会返回空结果集。
  • 时效性:df=d<N> 表单字段。
  • 最佳用途:默认首次尝试;很少被彻底屏蔽;尊重隐私。

Bing (bing)

  • 端点:https://www.bing.com/search?q=...&count=...
  • 无需 API 密钥。HTML 布局稳定且易于解析。
  • 时效性:freshness=d1 / w1 / m1 桶(Bing 没有任意 N 天 URL 过滤器)。
  • 最佳用途:第二个回退引擎;英文结果良好;偶尔的区域怪癖(通过 ensearch=1 缓解)。

Google (google)

  • 端点:https://www.google.com/search?q=...&num=...
  • 无需 API 密钥,但 Google 在阻止抓取方面最为激进。从 数据中心 / 云 IP 出发,Google 通常会返回一个“请启用 JS”的重定向页面(/httpservice/retry/enablejs),且没有可解析的结果——引擎将其视为软失败,自动链会回退。从 住宅 IP 出发,Google HTML 抓取通常工作正常。
  • 时效性:tbs=qdr:d|w|m|y 桶。
  • 最佳用途:在住宅 IP 上的最后回退引擎;在云 IP 上通常会失败(而 DDG+Bing 已满足需求)。

自动回退策略

当 engine: "auto"(默认)时,协调器按此顺序尝试引擎:

  1. DuckDuckGo——阻止最少,粒度最细的日期过滤器
  2. Bing——从任何 IP(包括数据中心)通常稳定
  3. Google——可达时结果质量最好;在数据中心 IP 上通常被屏蔽

它返回第一个产生 ≥ 1 个结果的引擎。如果所有三个都失败,则结果为 { success: false, errors: [...] },并附带每个引擎的错误——或在 searchOrThrow 模式下,抛出 AllEnginesFailedError。

实际可靠性表格(测试期间观察):

调用者 IP 类型DDGBingGoogle有效自动链
住宅高高中DDG → Bing → Google(3 个可行)
数据中心 / 云中(负载下有限制)高低(enablejs 墙)实际为 DDG → Bing

顺序在 src/engines/index.ts(AUTO_ENGINE_ORDER)中定义;如果您想要不同的优先级,请编辑该数组。

常见用例

  1. 实时信息——新闻、股票、天气、体育比分
  2. 最新文档——框架发布说明、API 变更
  3. 事实核查——对照实时来源验证声明
  4. 研究——收集多个来源
  5. 内容发现——查找教程和博客文章
  6. 竞争分析——竞争对手公告
  7. 学术查阅——查找论文和引文

相关技能