呆呆虫12头像

Go 调用搜索 API 教程:标准库实现 SerpBase 接口请求(附代码)

Go 项目里要接搜索数据接口,标准库就够了——net/http + encoding/json,不用引入任何第三方依赖。这篇给一份完整可运行的代码,以及几个 Go 场景下容易踩的点。

完整代码

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "time"
)

// 信封字段:六个端点共用
type Envelope struct {
    Status         int    `json:"status"`
    RequestID      string `json:"request_id"`
    ElapsedMs      int    `json:"elapsed_ms"`
    CreditsCharged *int   `json:"credits_charged"` // 可空,用指针
    SearchType     string `json:"search_type"`
}

type SearchResponse struct {
    Envelope
    Organic []struct {
        Rank  int    `json:"rank"`
        Title string `json:"title"`
        Link  string `json:"link"`
    } `json:"organic"`
}

func main() {
    apiKey := os.Getenv("SERPBASE_API_KEY")

    body, _ := json.Marshal(map[string]string{
        "q":  "serp api",
        "hl": "en",
        "gl": "us",
    })

    req, _ := http.NewRequest("POST",
        "https://api.serpbase.dev/google/search",
        bytes.NewReader(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", apiKey)

    client := &http.Client{Timeout: 30 * time.Second}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    var out SearchResponse
    if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
        panic(err)
    }

    // 信封先判 status,再读 organic
    if out.Status != 0 {
        panic(fmt.Sprintf("SERP failed: status=%d request_id=%s", out.Status, out.RequestID))
    }

    fmt.Printf("elapsed=%dms\n", out.ElapsedMs)
    for _, r := range out.Organic {
        fmt.Printf("#%d %s %s\n", r.Rank, r.Title, r.Link)
    }
}

运行:

export SERPBASE_API_KEY=你的key
go run main.go

三个 Go 场景的要点

一、credits_charged 可空,必须用指针。 计费字段可能是数字、0,也可能是 null(计费未确认)。Go 里如果用 int 接收,null 会被解析成 0——「未确认」和「确认不扣费」混为一谈,对账就错了。用 *int,nil 就是 null。

二、信封嵌套用嵌入结构体。 六个端点共用顶层字段,用 Go 的 struct embedding(Envelope 嵌入 SearchResponse)复用定义,换端点只改业务字段。

三、http.Client 复用。 别每次请求 &http.Client{} 新建——连接池没法复用。整个进程共用一个 client(默认自带连接池),批量采集时差距明显。

封装成客户端(简化版)

type Client struct {
    apiKey string
    http   *http.Client
}

func New(apiKey string) *Client {
    return &Client{apiKey: apiKey, http: &http.Client{Timeout: 30 * time.Second}}
}

func (c *Client) Search(q, hl, gl string) (*SearchResponse, error) {
    body, _ := json.Marshal(map[string]string{"q": q, "hl": hl, "gl": gl})
    req, _ := http.NewRequest("POST", "https://api.serpbase.dev/google/search", bytes.NewReader(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", c.apiKey)
    resp, err := c.http.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    var out SearchResponse
    if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
        return nil, err
    }
    return &out, nil
}

要注意的点

失败也可能计费。 官网口径:已执行的失败可能消耗 credits。重试要设上限和退避,别无限循环。

字段都是可选的。 snippet、模块字段以下游解析为准,Go 里用指针类型接收,nil 即「没有」。

Key 从环境变量读。 别硬编码进代码——Go 项目同样有把 Key 提交进仓库的风险。

成本

搜索端点 1 credit 一次。1000 个关键词一次采集 1,000 credits,$10 Starter 包(2 万 credits,无日历过期)够跑 20 轮。

小结

Go 调搜索数据接口,标准库全搞定:http.Client 复用 + 嵌入结构体复用信封 + 指针处理可空字段。三件事做对,代码既干净又不会在对账时踩坑。

接口的字段结构和计费规则见 SerpBase 官方文档。你的 Go 项目怎么调第三方接口?评论区聊聊。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/yxdkjhfl/article/details/168242882

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--