Local Search 技能
具備自動引擎備援的本地網頁搜尋。 直接解析 DuckDuckGo / Bing / Google 的 HTML · 對抗速率限制 · 標準化結果結構。
這個技能會直接從您的機器呼叫公開搜尋引擎。無需 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 — 可在 Node 18+ 上透過
tsx執行,或透過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 | 時間過濾器 |
|---|---|---|---|---|---|
| DuckDuckGo | html.duckduckgo.com/html/ (GET) | 無 | ✅ 高 | ⚠️ 負載下會速率限制 | df=d<N> (精確天數) |
| Bing | www.bing.com/search | 無 | ✅ 高 | ✅ 高 | freshness=d1|w1|m1 (區間) |
www.google.com/search | 無 | ⚠️ 中等 | ❌ 低 (enablejs 牆) | tbs=qdr:d|w|m|y (區間) |
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 | 取決於 SDK | tsx 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 或任何支援 TypeScript 的執行器來執行。
基本搜尋
# 預設:自動引擎,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 輸出至 stdout
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> | -e | duckduckgo | bing | google | auto(預設:auto) |
--recency-days <N> | -r | 限制為過去 N 天內的結果(預設:0 = 無過濾) |
--timeout <ms> | — | 每個引擎的超時時間,單位為毫秒(預設:8000) |
--json | — | 輸出 JSON 而非人類可讀格式 |
--output <path> | -o | 將 JSON 寫入檔案而非 stdout |
--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 實作(測試 / Edge 執行時期)
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 通常會回傳一個「請啟用 JavaScript」的重新導向頁面(
/httpservice/retry/enablejs),其中包含零個可解析的結果 — 引擎會將其視為軟失敗,自動鏈結會繼續往下嘗試。從 住宅 IP 發出請求時,Google HTML 解析通常可以正常運作。 - 時間過濾器:
tbs=qdr:d|w|m|y區間。 - 最佳使用時機:住宅 IP 上的最後備援;在雲端 IP 上通常會失敗(此時 DDG+Bing 已能滿足需求)。
自動備援策略
當 engine: "auto"(預設值)時,協調器會依下列順序嘗試引擎:
- DuckDuckGo — 最不積極的阻擋,最精細的日期過濾器
- Bing — 通常對任何 IP 都穩定,包括資料中心
- Google — 可連線時結果品質最佳;在資料中心 IP 上常被封鎖
它會回傳第一個產生 ≥ 1 個結果的引擎。如果所有三個引擎都失敗,結果會是 { success: false, errors: [...] },並附上每個引擎的錯誤 — 或者,在 searchOrThrow 模式下,會拋出 AllEnginesFailedError 例外。
實用可靠性表格(測試期間觀察到的情況):
| 呼叫者 IP 類型 | DDG | Bing | 有效的自動鏈結 | |
|---|---|---|---|---|
| 住宅 | 高 | 高 | 中等 | DDG → Bing → Google (3 個可用) |
| 資料中心 / 雲端 | 中等 (負載下會速率限制) | 高 | 低 (enablejs 牆) | 實際為 DDG → Bing |
順序定義在 src/engines/index.ts(AUTO_ENGINE_ORDER)中;如果您想要不同的優先順序,請編輯該陣列。
常見使用案例
- 即時資訊 — 取得模型訓練資料截止日期後的新聞、股價、天氣、體育賽事比分。
- 最新文件 — 擷取框架發行說明、API 變更、近期發表的論文。
- 事實查核 — 比對 AI 產生的聲明與即時網路來源。
- 研究 — 收集關於一個主題的多個來源,比較不同觀點。
- 內容發現 — 尋找特定主題的教學文章、部落格貼文、近期演講。
- 競爭 / 市場分析 — 監控競爭對手公告、產業趨勢。
- 學術查詢 — 尋找論文、引用、作者頁面。