Go
面向 Crawlbase 平台的官方 Go 客户端。地道的 Go 风格 - 用 error 返回值代替异常,每个方法都支持 context.Context,零外部依赖(仅使用 net/http + 标准库)。
SDK 的设计形态
Go SDK 刻意保持精简。一个客户端 - CrawlingAPI:通过统一的 Crawling API endpoint 覆盖所有 Crawlbase 产品:
| 使用场景 | 在 options 中传入 |
|---|---|
| 普通爬取 | (什么都不传 - 这就是默认行为) |
| 内置 scraper | "scraper": "amazon-product-details"(以及目录中的其他选项) |
| 截图 | "screenshot": "true" |
| 邮箱提取 | "scraper": "email-extractor" |
| Async + webhook | "async": "true" + "callback": "https://..." |
| 推送到 Enterprise Crawler | "async": "true" + "callback" + "crawler": "YourCrawler" |
独立的 /scraper、/leads 和 /screenshots endpoint(旧版 Crawlbase SDK 用独立的客户端类来封装)自 2024 年起已对新用户关闭注册。Go SDK 只提供现代化的路径 - 一个客户端、所有产品、没有遗留的类。
相比直接使用 net/http,使用本 SDK 的好处:
- URL 编码、参数校验和响应解析开箱即用。
- 地道的 Go 接口 -
(result, error)返回值、具名 struct 字段,传输失败时不会 panic。 - 每个方法都通过
*WithContext变体支持context.Context,可用于取消、超时控制和链路追踪传播。 - 合理的默认值(90 秒超时、透明 gzip 解压、对
format=json/scraper=响应自动 JSON 解析)。
源码在 github.com/crawlbase/crawlbase-go。参考文档在 pkg.go.dev。欢迎提交 issue 和 PR。
安装
最新版本见 pkg.go.dev。需要 Go 1.21+。
go get github.com/crawlbase/crawlbase-go@latest
# Or pin a specific version
go get github.com/crawlbase/[email protected]认证
所有 Crawlbase API 使用同一套 token 认证模型。每个账号下有两种 token:
- Normal Token(TCP) - 用于静态 HTML、JSON endpoint,以及任何不需要浏览器的场景。更快、更便宜。
- JavaScript Token
- 用于 SPA、懒加载信息流,以及任何将内容隐藏在客户端渲染之后的场景。使用
page_wait、ajax_wait、scroll和css_click_selector时必须使用此 token。
生产环境请使用环境变量。SDK 本身不会读取环境变量 - 这是有意为之,以便您完全掌控凭据的来源。常见模式:
package main
import (
"log"
"os"
"github.com/crawlbase/crawlbase-go"
)
func main() {
// Pick the right token at instantiation; the SDK doesn't switch
// tokens per-call, so keep two clients if you alternate.
api, err := crawlbase.NewCrawlingAPI(os.Getenv("CRAWLBASE_TOKEN"))
if err != nil {
log.Fatal(err)
}
js, err := crawlbase.NewCrawlingAPI(os.Getenv("CRAWLBASE_JS_TOKEN"))
if err != nil {
log.Fatal(err)
}
api.Get("https://github.com/anthropic", nil)
js.Get("https://feed.example.com", map[string]string{"page_wait": "2000"})
}如果传入的 token 字符串为空,构造函数会返回 crawlbase.ErrTokenRequired。完整的 token 模型和后台位置请参见认证页面。
快速开始
从导入到爬取 HTML 只需三行代码:
package main
import (
"fmt"
"log"
"github.com/crawlbase/crawlbase-go"
)
func main() {
api, err := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
if err != nil {
log.Fatal(err)
}
res, err := api.Get("https://github.com/anthropic", nil)
if err != nil {
log.Fatal(err)
}
if res.StatusCode == 200 {
fmt.Println(res.Body)
}
}决定是否重试时,请根据 res.StatusCode(SDK 向 Crawlbase 发起请求的 HTTP 状态)和 res.PCStatus(Crawlbase 的判定结果 - 见下方错误)来分支。传入 map[string]string{"format": "json"} 可获得 JSON 信封而非原始页面内容(会自动解析到 res.JSON)。
常见模式
JavaScript 渲染
对于 SPA、懒加载信息流和初始 HTML 为空的页面,请使用 JavaScript token 实例化客户端,并传入 page_wait、ajax_wait、scroll 和 css_click_selector 的任意组合。建议的思考顺序:先固定等待,再等待网络空闲,然后滚动以触发懒加载,最后点击拦截 UI 元素。
api, _ := crawlbase.NewCrawlingAPI("YOUR_JS_TOKEN")
res, err := api.Get("https://spa.example.com", map[string]string{
"page_wait": "2000",
"ajax_wait": "true",
"scroll": "true",
})使用内置 scraper
在受支持的站点上完全跳过解析器。传入 "scraper": "NAME",响应 Body 即变为一个 JSON 字符串,其中包含每个 scraper 页面所记录的结构化字段。Body 还会预先解码到 res.JSON,您可以直接读取字段。
api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
res, err := api.Get(
"https://www.amazon.com/dp/1098145356",
map[string]string{"scraper": "amazon-product-details"},
)
if err != nil {
log.Fatal(err)
}
if name, ok := res.JSON["name"].(string); ok {
fmt.Println(name)
}地理路由
传入 "country": "ISO" 可将爬取请求路由通过该国家的出口节点。当目标站点根据 IP 提供本地化内容时使用。
api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
// Hit the German Amazon catalog from a German residential IP
res, _ := api.Get(
"https://www.amazon.com/dp/1098145356",
map[string]string{"country": "DE"},
)带退避的重试
推荐的重试形态:指数退避,最多 3-5 次重试,仅在瞬时错误(5xx 或空 body)时重试,4xx 不重试。
import (
"fmt"
"math"
"math/rand"
"time"
"github.com/crawlbase/crawlbase-go"
)
func Crawl(api *crawlbase.CrawlingAPI, url string, attempts int) (*crawlbase.Response, error) {
for i := 0; i < attempts; i++ {
res, err := api.Get(url, nil)
if err != nil {
return nil, err
}
if res.StatusCode == 200 && res.PCStatus == 200 {
return res, nil
}
if res.StatusCode >= 400 && res.StatusCode < 500 {
return nil, fmt.Errorf("client error %d: %s", res.StatusCode, url)
}
// Exponential backoff with jitter
d := time.Duration(rand.Float64() * math.Pow(2, float64(i)) * float64(time.Second))
time.Sleep(d)
}
return nil, fmt.Errorf("failed: %s", url)
}异步爬取 + webhook
发后即弃模式。SDK 调用立即返回一个 RID;当页面就绪后,Crawlbase 会将结果 POST 到您的回调 URL。适用于批处理任务和慢速目标站点。
api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
res, _ := api.Get("https://example.com", map[string]string{
"async": "true",
"callback": "https://your-app.com/webhook",
})
rid := res.RID // correlate the eventual webhook delivery
// Your net/http handler receives a POST with:
// { rid, url, original_status, pc_status, body }对于超大批量场景(数百万 URL),可在 async + callback 选项之外加上 "crawler": "YourCrawlerName",将任务推送到 Enterprise Crawler。
粘性会话
某些流程需要在多次调用中保持同一住宅 IP。传入带稳定标识符的 cookies_session,Crawlbase 会在约 30 分钟内复用同一出口节点。
api, _ := crawlbase.NewCrawlingAPI("YOUR_JS_TOKEN")
session := fmt.Sprintf("checkout-%d", userID)
opts := map[string]string{"cookies_session": session}
api.Get("https://shop.example.com/cart", opts)
api.Get("https://shop.example.com/checkout", opts)
api.Get("https://shop.example.com/confirm", opts)截图
传入 "screenshot": "true" 可捕获整页截图。Body 返回为 base64 编码的图像;使用 crawlbase.ImageBytes(res) 解码为原始字节,然后传给 os.WriteFile / image.Decode。
api, _ := crawlbase.NewCrawlingAPI("YOUR_JS_TOKEN")
res, _ := api.Get("https://www.apple.com", map[string]string{
"screenshot": "true",
})
img, err := crawlbase.ImageBytes(res)
if err != nil {
log.Fatal(err)
}
os.WriteFile("apple.png", img, 0o644)用 Context 实现取消
每个方法都有 *WithContext 变体,可配合 context.Context 使用:在调用需要响应上游取消、截止时间或追踪传播时非常有用(HTTP handler、gRPC 服务器,以及任何请求循环中的场景)。
import (
"context"
"time"
)
api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
res, err := api.GetWithContext(ctx, "https://example.com", nil)错误 & 重试
平台在每个响应中都会返回两个状态码:SDK 自身的 res.StatusCode(向 Crawlbase 发起请求的 HTTP 状态)和 res.PCStatus(Crawlbase 对目标的判定 - 从 pc_status 响应头中提取,便于类型化访问;完整列表请参见 Crawling API 错误表)。决定是否重试时,请始终基于 PCStatus 进行分支 - 一个目标可能返回 200 但 body 为空,此时 StatusCode 为 200,但 PCStatus 为 520。
res, err := api.Get(url, nil)
if err != nil {
return err
}
switch res.PCStatus {
case 200:
use(res.Body)
case 520, 525:
// 520 = empty body, 525 = anti-bot couldn't be solved.
// Switch to JS token and retry.
retryWithJSToken(url)
case 521, 522, 523:
// Target unreachable or timed out. Retry with backoff.
scheduleRetry(url)
default:
log.Printf("crawl failed: url=%s pc_status=%d", url, res.PCStatus)
}所有针对平台的重试都是免费的 - 只有成功的响应(PCStatus: 200)才会计入您的配额。
性能 & 最佳实践
- 每个 token 复用单个客户端。
构造函数开销很小,但每个
*CrawlingAPI实例都拥有自己的底层http.Client,并带有独立的连接池。在服务初始化时构建一次,跨 goroutine 共享使用(SDK 是 goroutine 安全的)。 - 使用能完成任务的最便宜的 token。
不要为了「以防万一」而默认使用 JavaScript token - Normal token 请求更快,占用的并发更少。在
PCStatus == 520或525时再升级即可。 - 优先使用
ajax_wait而不是page_wait。 固定延迟会在每个请求上消耗并发,即使是快速的请求也不例外。 - 批量任务:使用 async + webhook,或推送到 Enterprise Crawler。 在同步调用上阻塞的 goroutine 池会很快耗尽并发上限;async + webhook 则在请求一进入队列时就立刻释放槽位。
- 在服务端代码中使用
GetWithContext/PostWithContext。 当调用方退出时,请求作用域的 context 会传播取消信号 - 没有它,一个挂起的爬取会在调用方截止时间之后继续运行。
响应字段
完整的方法签名、godoc 和按方法划分的示例都在 pkg.go.dev 上。下面列出的是 Crawlbase 用户最常用到的字段 - 关于目标的类型化判定,在每个 *crawlbase.Response 上都会返回:
pc_status(或 cb_status)响应头中提取出来以便类型化访问。基于此字段做重试决策。format=json / scraper= 时为 JSON 字符串;当 screenshot=true 时为 base64 编码的图片)。"async": "true" 或 "store": "true" 时设置。json.Unmarshal 步骤。