npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gausszhou/dsh-web-search-local

v0.2.1

Published

Keyless multi-engine web search + page fetch providers for the dsh web seam (no DeepSeek dependency).

Readme

dsh-web-search-local

DeepSeek Harness(dsh)ctx.web 接口提供的无密钥多引擎网页搜索与抓取 provider。适用于任何模型后端——包括完全本地模型无需 API Key,也不依赖 DeepSeek 的服务端搜索

npm 版本 npm 月下载量 累计下载量 开源协议

为什么需要它

dsh 内置的 web_search 工具与模型无关:它只调用 ctx.web.search()。依赖 DeepSeek 的是它的默认搜索 providerdsh-web-search-deepseek),该 provider 会把每次查询带上 DEEPSEEK_API_KEY 发给 DeepSeek 的 web_search_20250305 服务端工具。一旦切换到本地模型(如 Ollama),这个 provider 没有 key,搜索就失效了。

本包注册两个由插件自己发 HTTP 请求的 provider:

| provider id | 能力 | 引擎 | | --- | --- | --- | | local-multi | web_search | 三层顺序执行——SearXNG(配置时)→ Google/DuckDuckGo/Mojeek(国外层)→ Bing/Baidu/Sogou/360(国内层);同层引擎并行请求round-robin 合并结果;一层无结果则降级到下一层 | | local-fetch | web_fetch | 直接 GET,字符集感知解码(含 gbk),返回 html/text 正文 |

代理 / VPN 支持

Node 进程不会自动使用操作系统/浏览器的代理。如果 DuckDuckGo 等引擎在你的网络环境下不可达,provider 会自动解析代理:

  1. proxyUrl 配置(显式指定,或设为 'off' 强制直连)
  2. HTTPS_PROXY / HTTP_PROXY / ALL_PROXY 环境变量
  3. 探测常见本地 HTTP 代理端口(7890 Clash、789710809 v2rayN、1080、……)

代理只作用于国外层引擎googleduckduckgomojeek)——它们才是大陆网络下需要隧道的一方。国内层引擎(bingbaidusogou360)和私有 SearXNG 实例始终直连(只有国外层引擎走 CONNECT 隧道;隧道在传输层挂掉时这些请求同样回退直连)。这个拆分很关键:把国内引擎塞进国外节点 IP 会触发百度的安全验证墙、搜狗的反爬验证码和 360 的 302 跳转;把自己的 SearXNG 实例也走 VPN 节点则可能拿到陈旧或空的结果集。

安装

通过 npm

已发布至 npm registry

npm install @gausszhou/dsh-web-search-local

或者用 dsh CLI 一步注册并激活插件:

dsh plugin add @gausszhou/dsh-web-search-local

本包内置 dsh.bundle patch,因此 dsh plugin add 会安装并自动激活插件: web profile 会自动切换为 searchProvider: local-multi / fetchProvider: local-fetch, 并禁用内置的 web-search-deepseek provider,无需手工编辑 cordis.patch.yml

如需调整 bundle 应用的默认值,可在你的 profile 的 cordis.patch.yml (web profile 即 $DSH_HOME/profiles/web/cordis.patch.yml,位于 bundle 层之后)中覆盖:

- id: web
  config:
    searchProvider: local-multi
    fetchProvider: local-fetch

- id: web-search-deepseek
  disabled: true

- insert:
    - id: web-search-local
      name: '@gausszhou/dsh-web-search-local'
      config:
        engines: [searxng, google, duckduckgo, mojeek, bing, baidu, sogou, 360]

本地目录 / 文件路径

把本包放到 dsh 进程可读的任意位置,例如 $DSH_HOME/profiles/web/plugins/web-search-local/(Windows:C:\Users\<you>\.dsh\profiles\web\plugins\web-search-local\)。然后在你的 profile 的 cordis.patch.yml(web profile 即 $DSH_HOME/profiles/web/cordis.patch.yml)中加入:

- id: web
  config:
    searchProvider: local-multi
    fetchProvider: local-fetch

- id: web-search-deepseek
  disabled: true

- insert:
    - id: web-search-local
      name: 'file:///C:/Users/<you>/.dsh/profiles/web/plugins/web-search-local/index.js'
      config:
        engines: [searxng, google, duckduckgo, mojeek, bing, baidu, sogou, 360]
  1. 重启 dsh。web_search 现在返回纯来源列表(无服务端摘要),且适用于任何模型。

配置

config:
  engines: [searxng, google, duckduckgo, mojeek, bing, baidu, sogou, 360]  # 成员列表(执行按层:searxng → 国外 → 国内,层内并行)
  skipWithoutProxy: [google, duckduckgo, mojeek] # 无代理时直接跳过的引擎([] = 总是尝试)
  searxngBaseUrl: 'http://127.0.0.1:8080'   # 可选;设置后优先执行
  proxyUrl: ''                              # '' 自动 | 'off' 直连 | 'http://host:port' 显式指定
  searchTimeoutMs: 12000
  fetchTimeoutMs: 20000
  maxFetchBytes: 1048576
  maxSources: 12
  cacheTtlMs: 300000                        # 内存结果缓存
  engineMinIntervalMs: 1500                 # 引擎请求最小间隔(防限流)
  engineCooldownMs: 600000                  # 验证墙/验证码后熔断冷却(0 = 关闭)
  engineRetryCooldownMs: 60000              # 普通失败后冷却(0 = 关闭)
  userAgent: '<浏览器风格的 UA>'

默认引擎列表分三层、按序执行,同层引擎并行请求并合并

  1. searxng——配置了 searxngBaseUrl 的私有 SearXNG 实例本身就是元搜索聚合,有结果就直接返回,跳过下面两层
  2. 国外层——Google、DuckDuckGo、Mojeek(大陆需要代理;无代理时整体直接跳过,见 skipWithoutProxy
  3. 国内层——Bing、Baidu、Sogou、360(直连可用,无需 VPN/代理)

一层无结果(空、被墙或跳过的引擎)就降级到下一层,所以国外层永远不会拖垮可直连的国内层。google 引擎易被反爬(consent 墙、sorry/ 机器人检测、enablejs JS 墙);要稳定拿到 Google 结果,使用启用了 google 引擎的 SearXNG 实例。在开放网络(全球引擎可直连)上,把 skipWithoutProxy 设为 []

私有 SearXNG 实例(Docker:docker run -p 8080:8080 searxng/searxng)是所有引擎中最稳健的:元搜索聚合、JSON API、无需逐引擎爬取。

限流韧性

搜索引擎(尤其是 DuckDuckGo)会限流脚本。以下三个机制让单引擎配置也能稳定使用:

  • 节流——按引擎计:同一引擎在 engineMinIntervalMs 内不会被调用两次(防限流),同层不同引擎则一起启动。
  • 熔断——引擎出现机器人墙(blocked by captcha / anomaly check / 百度的 verification wall,或 HTTP 403/429)时,在 engineCooldownMs(默认 10 分钟)内跳过;普通失败(传输、HTTP 错误)只触发更短的 engineRetryCooldownMs(默认 60 秒)。冷却期间引擎被跳过,原因会聚合进错误信息。
  • DuckDuckGo lite 兜底——html.duckduckgo.com 端点被机器人墙拦截时,同一查询会改走 lite.duckduckgo.com/lite/ 重试一次(该端点对脚本更宽容)。若 lite 端点也被墙,引擎会报告 blocked by anomaly check (html and lite) 并触发长冷却 engineCooldownMs,而不是每次搜索都反复冲击两个端点。

被墙的引擎不会让整个搜索失败(前提是还有其他引擎);单引擎模式下会快速失败并给出 "cooling down" 原因,而不是反复冲击被墙端点。

模型指定引擎

模型可以在每次搜索时指定用哪个引擎,两种途径:

  1. 工具——在官方 web_search 之外,本插件注册了 web_search_engine,带两个可选参数:
    • engine:单个引擎——searxnggoogleduckduckgomojeekbingbaidusogou360
    • engines:有序的引擎优先级列表 两者都不传时,调用降级为配置的默认三层引擎链,与 web_search 完全一致。
  2. provider 请求——任何直接调用 ctx.web.search({ query, engine })ctx.web.search({ query, engines }) 的调用方都获得同样的覆盖;未知引擎名会抛 WEB_PROVIDER_ERROR 并列出合法 id。

显式覆盖会完全替换配置的引擎链(包括 SearXNG 自动前置)——模型的明确选择优先。指定的引擎同样按 searxng / 国外 / 国内三层分组、层内并行合并(与默认链一致);只指定一个引擎就是单跑。节奏控制、熔断和 skipWithoutProxy 对指定引擎同样生效,所以指定了但不可达的引擎会快速失败,而不会拖垮整个搜索。

回退到 DeepSeek 搜索

cordis.patch.yml 中移除 web 覆盖项、web-search-deepseek 禁用项以及插入的那一行即可。

注意事项

  • 引擎靠正则抓取纯 HTML;上游改版可能导致某个引擎失效——链路会自动落到下一个引擎。所有引擎的错误会聚合进抛出的异常信息。搜狗的 /link?url= 加密跳转会在服务端解析(跳转页正文内嵌真实地址);360 的跳转链接在锚点的 data-mdurl 属性里直接暴露真实地址,解析器直接读取。
  • google 引擎用双布局解析器抓取 HTML 结果页(基础 gbv=1 标记与现代 JS 时代标记),并发送 CONSENT/SOCS Cookie 绕过欧盟 consent 墙。Google 经常对脚本返回"需要启用 JavaScript"墙(/httpservice/retry/enablejs)或 sorry/ 验证码而不是结果——两者都会被检测并触发长熔断冷却(带明确原因),国外层随即降级到国内层。要稳定拿到 Google 结果,使用启用了 google 引擎的 SearXNG 实例。
  • 返回结构与官方 provider 一致:web_search 返回 { sources: [{ url, title?, snippet?, publishedAt? }], truncated }。层内引擎并行请求,来源round-robin 合并、去重、截断到 maxSources(合并结果超过上限时 truncated 置 true);一层无结果则降级到下一层。publishedAt 是尽力而为的 YYYY-MM-DD 日期,当引擎页面出现日期时填充(SearXNG 的 publishedDate,或 Bing/Baidu/Sogou/360 结果块中的日期文本),否则省略该字段——与官方 page_age 相同的可选语义。
  • 无第三方运行时依赖:只用 fetch + node:http/https/net/tls,外加 dsh 自带的 @deepseek-ai/dsh-web(以 peerDependency 声明;每个 dsh profile 都已内置)。
  • 错误遵循 seam 的 provider 契约:失败时抛 WebError,code 为 WEB_PROVIDER_ERROR(引擎/传输/超时,引擎错误会聚合进 message)或 WEB_ABORTED(调用方取消)——与官方 provider 使用同一套错误词汇。
  • web_fetch 需要 tool-webfetch: true;自带的 standard agent 预设默认是 fetch: false——把预设复制到 $DSH_HOME/.agent-presets/ 并在那里打开开关。

配置与设置集成

插件声明了一个 schemastery Config 架构(字段与 defaultConfig() 一一对应)并通过 dsh 的 settings 服务注册了一个设置命名空间(web-search-local)——内置的 web-search-deepseekshellagent-loop 等插件用的就是这套机制。这带来:

  • 配置经过校验与规范化,可通过 dsh 的 settings 服务持久化。
  • provider 每次搜索/抓取时读取实时生效的配置段:通过设置 UI 改动的值会在下一次调用立即生效,无需重启。(ConfigSETTINGS_NAMESPACE 均作为具名导出。)
  • 在没有 settings 服务的 profile 里,行为与原来完全一致:仍走 cordis.patch.yml 传给 apply(ctx, config) 的组合配置。

说明:在“插件配置”面板中看得见的那张卡片是一个客户端 React 组件——内置插件(终端 / Agent 循环 / 网页搜索)的卡片都硬编码在 dsh-client-ui-settings-plugins 这个打包客户端包里。要让本插件在这套面板里出现可编辑卡片,还需要随包提供一个 ./client 半端来注册 settings.plugin.item 卡片(见后文)。本插件的配置界面 = 上面的服务端 schema 集成 + 客户端卡片两部分。

许可证

MIT