用搜索数据 API 做一个关键词联想组件(防抖 + 缓存 + 可复用)

搜索框的联想/自动补全,大部分实现用的是「内置词库」或「热门词表」。但用户真正在搜什么,答案在谷歌的相关搜索里------related_searchespeople_also_ask 就是现成的真实联想词。这篇记录我做一个基于搜索数据 API 的联想组件:防抖、缓存、可复用,前端向,代码可直接跑。

需求

用户在搜索框打字时,出现基于真实搜索数据的联想词。要求:

  1. 输入停顿后请求(防抖),不每键都发
  2. 相同输入不重复请求(前端缓存)
  3. 做成可复用组件,不绑定业务

数据源

联想词来自搜索数据 API 的返回。我用的是 SerpBase(serpbase.dev)的 /google/search 端点,返回里带 related_searches(相关搜索)和 people_also_ask(人们还问),POST JSON + X-API-Key 认证。

关键安全点:API key 不能放浏览器。联想请求必须走后端代理,前端只调自己的接口。

第一步:后端代理接口

一个极薄的代理,把联想词捞出来(Node 版):

js 复制代码
// server.mjs
import express from "express";
const app = express();

const SERPBASE = "https://api.serpbase.dev";
const API_KEY = process.env.SERPBASE_API_KEY;   // key 只在服务端

app.get("/api/suggest", async (req, res) => {
  const q = (req.query.q || "").trim();
  if (!q) return res.json([]);

  const resp = await fetch(`${SERPBASE}/google/search`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "X-API-Key": API_KEY },
    body: JSON.stringify({ q, hl: "zh-cn", gl: "cn" }),
  });
  const data = await resp.json();

  // 把相关搜索 + PAA 问题合并成联想词列表
  const related = data.related_searches ?? [];
  const paas = (data.people_also_ask ?? []).map((p) => p.question);
  res.json([...new Set([...related, ...paas])].slice(0, 8));
});

app.use(express.static("public"));
app.listen(3000, () => console.log("http://localhost:3000"));

第二步:前端联想组件

做成一个可复用的 Web Component,不依赖框架:

html 复制代码
<!-- public/index.html -->
<script>
  class KeywordSuggestion extends HTMLElement {
    connectedCallback() {
      this._cache = new Map();          // 请求缓存:相同输入不重复发
      this._timer = null;
      this.innerHTML = `
        <input placeholder="输入关键词,看真实联想词..." />
        <ul hidden></ul>`;
      const input = this.querySelector("input");
      const list = this.querySelector("ul");

      input.addEventListener("input", (e) => {
        clearTimeout(this._timer);
        const q = e.target.value.trim();
        if (!q) { list.hidden = true; return; }
        this._timer = setTimeout(() => this._suggest(q, list), 300);  // 防抖 300ms
      });
    }

    async _suggest(q, list) {
      if (this._cache.has(q)) {
        this._render(this._cache.get(q), list);   // 命中缓存,不发请求
        return;
      }
      const words = await fetch(`/api/suggest?q=${encodeURIComponent(q)}`).then(r => r.json());
      this._cache.set(q, words);
      this._render(words, list);
    }

    _render(words, list) {
      list.innerHTML = words.map(w => `<li data-word="${w}">${w}</li>`).join("");
      list.hidden = words.length === 0;
      list.querySelectorAll("li").forEach(li =>
        li.addEventListener("click", () => {
          this.querySelector("input").value = li.dataset.word;
          list.hidden = true;
        })
      );
    }
  }
  customElements.define("keyword-suggestion", KeywordSuggestion);
</script>

<keyword-suggestion></keyword-suggestion>

要点:

  • 防抖 300ms:停止输入 300ms 后才请求,避免每键一请求
  • 前端缓存 Map:相同输入直接命中,不重复调接口、不浪费 credits
  • Web Component<keyword-suggestion> 一处定义,多处复用

第三步:效果与体验优化

几个值得加的点:

空态提示。 如果联想词为空,提示「无联想词」而不是空白,体验更好。

点击联想后继续联想。 点击一个联想词,可以把它当作新输入再触发联想------形成「词 → 相关词」的探索链:

js 复制代码
// 点击后把词填入输入框,再自动触发一次联想
li.addEventListener("click", () => {
  input.value = li.dataset.word;
  setTimeout(() => this._suggest(input.value, list), 100);
});

选中高亮。 键盘上下键导航是加分项,这里先不展开。

成本和注意点

  • /google/search 每次 1 credits;前端缓存保证了「同一用户同一次输入只请求一次」
  • 注册送 100 次免费搜索,开发测试完全够
  • 标准包 10买2万次(10 买 2 万次( 10买2万次(0.50/千次),永不过期------这种交互型调用量不大
  • related_searches / people_also_ask 是可选字段,服务端用 ?? [] 兜底

收尾

这个组件的价值,是把「谷歌的真实搜索数据」变成产品里的交互能力------搜索框联想、选题推荐、站内搜索补全都能用。核心技术点就三个:防抖、缓存、后端代理(保 key 安全)。

接口参数细节在 SerpBase 官方文档。从「复制组件 + 一个代理接口」开始,你就能在任意页面拥有基于真实搜索数据的联想功能。有更好的联想交互,评论区聊聊。

相关推荐
AC赳赳老秦1 小时前
企业标签体系搭建:基于 OpenClaw 采集的多维度公开数据,构建企业画像标签库
java·运维·服务器·python·信息可视化·deepseek·openclaw
吃旺旺雪饼的小男孩1 小时前
U-Net 语义分割详解:原论文、PyTorch 实现与真实消融实
人工智能·pytorch·python·算法
XZ-0700011 小时前
1-1-可视化-练习
开发语言·python
今天AI了吗2 小时前
AI Agent 在数据分析领域的落地判断:哪些场景真的需要 Agent
java·数据库·人工智能·python·sql·数据分析·copilot
橙橙笔记2 小时前
Python学习第三部分
开发语言·python·学习
huainingning2 小时前
个人版WorkBuddy编写设备巡检并导出设备配置python脚本
开发语言·python
欧叶冲冲冲2 小时前
uv Python 环境管理笔记
笔记·python·uv
很楠爱上2 小时前
从“AI 看合同”到可举证的合同决策链:CounterClause(对薄) 的架构设计与工程实践
人工智能·经验分享·python·学习·agent
这就是佬们吗2 小时前
治幻觉,先治检索:RAG 系统防幻觉的完整工程指南
python·langchain·embedding