登录

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_waitajax_waitscrollcss_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_waitajax_waitscrollcss_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 为空,此时 StatusCode200,但 PCStatus520

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 == 520525 时再升级即可。
  • 优先使用 ajax_wait 而不是 page_wait 固定延迟会在每个请求上消耗并发,即使是快速的请求也不例外。
  • 批量任务:使用 async + webhook,或推送到 Enterprise Crawler。 在同步调用上阻塞的 goroutine 池会很快耗尽并发上限;async + webhook 则在请求一进入队列时就立刻释放槽位。
  • 在服务端代码中使用 GetWithContext / PostWithContext 当调用方退出时,请求作用域的 context 会传播取消信号 - 没有它,一个挂起的爬取会在调用方截止时间之后继续运行。

响应字段

完整的方法签名、godoc 和按方法划分的示例都在 pkg.go.dev 上。下面列出的是 Crawlbase 用户最常用到的字段 - 关于目标的类型化判定,在每个 *crawlbase.Response 上都会返回:

StatusCode
int
SDK 向 Crawlbase 发起请求的 HTTP 状态。
PCStatus
int
Crawlbase 对目标站点的判定。从 pc_status(或 cb_status)响应头中提取出来以便类型化访问。基于此字段做重试决策。
OriginalStatus
int
目标站点返回给 Crawlbase 的 HTTP 状态。
URL
string
目标侧重定向后的最终 URL。
Body
string
页面内容(当使用 format=json / scraper= 时为 JSON 字符串;当 screenshot=true 时为 base64 编码的图片)。
Headers
map[string]string
小写形式的响应头。
RID
string
请求 ID - 当调用携带 "async": "true""store": "true" 时设置。
JSON
map[string]any
当响应 Content-Type 为 JSON 时,预先解析好的 JSON。在 scraper / format=json 调用中省去一次 json.Unmarshal 步骤。