site logo

Marico's space

SerpApi JavaScript 入门指北:从调通到跑稳生产环境

前端技术 2026-04-27 15:04:58 1

这篇文章不是软文——SerpApi 本身也不是什么新鲜玩意儿了。写的是实打实的工程经验:认证怎么过、返回的 JSON 结构到底长啥样、额度怎么省、LangChain 里怎么接,以及那些文档里不会写但人人都踩的坑。

如果你正在做 AI Agent、SEO 工具、比价爬虫,或者任何需要搜索数据的产品,这篇值得花 5 分钟看完。

认证:别把 Key 写进代码

SerpApi 的认证是整个流程里最简单的部分了——一个 API Key,往 URL 参数里一塞就完事。没有 OAuth,没有 Bearer Token,也不用装什么 SDK。但简单归简单,Key 管理不能含糊。

const params = new URLSearchParams({
  engine: 'google',
  q: 'javascript developer advocate',
  api_key: process.env.SERPAPI_API_KEY // 永远不要硬编码
});

const response = await fetch(`https://serpapi.com/search?${params}`);
const data = await response.json();

Key 放环境变量里,别碰源码,更别提交到公开仓库。获取方式也很常规:注册账号 → Dashboard → Your API Key。免费版每月 100 次搜索,拿到就能用。

第一次搜索调用:包装成函数

直接写调用当然可以,但生产环境里需要一个封装好的 search 函数来处理参数和异常:

async function search(query, options = {}) {
  const params = new URLSearchParams({
    engine: 'google',
    q: query,
    api_key: process.env.SERPAPI_API_KEY,
    num: options.num || 10,
    hl: options.language || 'en',
    gl: options.country || 'us',
    ...options
  });

  const res = await fetch(`https://serpapi.com/search?${params}`);
  if (!res.ok) {
    const error = await res.json();
    throw new Error(`SerpApi error: ${error.error}`);
  }
  return res.json();
}

const results = await search('web scraping api javascript');
console.log(results.organic_results[0]);

JSON 响应结构:文档没讲清楚的那部分

这是最容易被忽略的地方。SerpApi 的文档把字段列表列出来了,但没告诉你哪些字段是"可能不存在"的——结果线上很多人一访问就报错。

{
  "search_metadata": { "id": "...", "status": "Success", "total_time_taken": 1.23 },
  "search_parameters": { "engine": "google", "q": "your query" },
  "organic_results": [
    { "position": 1, "title": "Result title", "link": "https://...", "snippet": "Description text..." }
  ],
  "related_searches": [...],
  "pagination": { "next": "https://serpapi.com/search?..." }
}

核心原则:永远先检查字段是否存在再访问

const answer = results.answer_box?.answer ?? null;
const organicResults = results.organic_results ?? [];

location 错误:几乎所有人都踩过的坑

最常见的 bug:搜索结果只返回图片、FAQ 或者 AI 摘要,就是没有正常的自然搜索结果。问题根源是 location 参数不明确。

修复方案一:显式设置 location

const params = new URLSearchParams({
  engine: 'google',
  q: 'your query',
  location: 'Austin, Texas, United States',
  google_domain: 'google.com',
  gl: 'us',
  hl: 'en',
  api_key: process.env.SERPAPI_API_KEY
});

修复方案二:用 Locations API 查找正确的 location 字符串

const locationRes = await fetch(`https://serpapi.com/locations.json?q=Austin&limit=5`);
const locations = await locationRes.json();

修复方案三:直接看返回里有什么字段

const fields = Object.keys(results);
console.log('Available fields:', fields);

节省额度:生产级别的必修课

SerpApi 按次收费,大规模使用时额度管理是真实存在的问题。

查看剩余额度

async function getAccountInfo() {
  const res = await fetch(`https://serpapi.com/account?api_key=${process.env.SERPAPI_API_KEY}`);
  const account = await res.json();
  return { searchesUsed: account.searches_this_month, creditsRemaining: account.plan_searches_left };
}

缓存结果避免重复请求

const cache = new Map();
async function cachedSearch(query, ttlMs = 3600000) {
  const cacheKey = query.toLowerCase().trim();
  const cached = cache.get(cacheKey);
  if (cached && Date.now() - cached.timestamp < ttlMs) return cached.data;
  const data = await search(query);
  cache.set(cacheKey, { data, timestamp: Date.now() });
  return data;
}

LangChain 里的接法

SerpApi 在 2026 年 4 月支持了 llms.txt,明显是在朝 AI Agent 这个方向做适配。以下是接入 LangChain 的基本写法:

import { SerpAPI } from "@langchain/community/tools/serpapi";
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { pull } from "langchain/hub";

const searchTool = new SerpAPI(process.env.SERPAPI_API_KEY, { location: "United States" });
const llm = new ChatOpenAI({ model: "gpt-4", temperature: 0 });
const agent = await createOpenAIFunctionsAgent({ llm, tools: [searchTool], prompt: await pull("hwchase17/openai-functions-agent") });
const executor = new AgentExecutor({ agent, tools: [searchTool] });
const result = await executor.invoke({ input: "What are the latest developments in JavaScript developer tooling?" });

错误处理参考

async function safeSearch(query, options = {}) {
  try {
    return await search(query, options);
  } catch (err) {
    if (err.message.includes('429')) { await new Promise(r => setTimeout(r, 60000)); return search(query, options); }
    if (err.message.includes('Invalid API key')) throw new Error('检查 SERPAPI_API_KEY 环境变量');
    if (err.message.includes('Your account has run out')) throw new Error('SerpApi 额度已耗尽');
    throw err;
  }
}

原文:Your First SerpApi Integration in JavaScript — From Hello World to Production