登录

SDK 的结构

.NET SDK 是对 API Reference 中所述 HTTP API 的轻量封装。在原始 HTTP 调用中作为查询字符串附加的每个 Crawling API 参数,都可作为 Dictionary<string, object> 选项访问:名称、默认值和行为均一一对应。

有一点需要提前了解:.NET SDK 将响应状态暴露在 API 实例本身上,而不是返回值对象上。诸如 api.Get(url) 的调用返回 void;您通过 api.StatusCodeapi.Body 等读取结果。这与 Python / Node / Ruby / PHP SDK 不同(后者返回一个响应对象)。Storage API 是个例外:它的方法返回一个可直接读取的响应对象。

相比直接使用 HttpClient,使用它能获得:

  • URL 编码、参数验证和响应解析开箱即用。
  • 每个动词都有同步 + 异步配对,按调用场景选择即可。
  • 每个 Crawlbase API 对应一个客户端类,全部共享相同的构造函数 / 调用形式。
  • 合理的默认值(90 秒超时、对 format=json 响应自动进行 JSON 解析)。

源代码位于 github.com/crawlbase/crawlbase-net

安装

最新版本发布在 NuGet 上。目标框架为 .NET 6+;已测试至 .NET 9。

# .NET CLI
dotnet add package CrawlbaseAPI

# Package Manager Console
Install-Package CrawlbaseAPI

# Or in csproj:
# <PackageReference Include="CrawlbaseAPI" Version="1.1.0" />

身份验证

每个 Crawlbase API 都使用相同的 token 模型进行身份验证。一个账号下有两种 token 类型:

  • Normal Token (TCP) - 用于静态 HTML、JSON 端点等不需要浏览器的场景。更快 + 更便宜。
  • JavaScript Token - 用于 SPA、懒加载信息流,以及任何将内容隐藏在客户端渲染背后的场景。使用 page_waitajax_waitscrollcss_click_selector 时必需。

在生产环境中请使用环境变量或 DI 容器的配置。模式:

// Pick the right token at instantiation; the SDK doesn't switch
// tokens per-call, so keep two clients if you alternate.
var api = new Crawlbase.API(Environment.GetEnvironmentVariable("CRAWLBASE_TOKEN"));
var js = new Crawlbase.API(Environment.GetEnvironmentVariable("CRAWLBASE_JS_TOKEN"));

await api.GetAsync("https://github.com/anthropic");

var opts = new Dictionary<string, object> { ["page_wait"] = 2000 };
await js.GetAsync("https://feed.example.com", opts);

完整的 token 模型 + 仪表盘位置请参见 Authentication 页面。

快速开始

从命名空间到爬取响应只需三行代码。注意响应状态保存在 api 实例上:

var api = new Crawlbase.API("YOUR_TOKEN");
await api.GetAsync("https://github.com/anthropic");

if (api.StatusCode == 200) {
 Console.WriteLine(api.Body);
}

在决定是否重试时,根据 api.StatusCode(SDK 到 Crawlbase 的 HTTP 状态)和 api.CrawlbaseStatus(Crawlbase 的判定结果:参见下方错误)进行分支判断。传入 new Dictionary<string,object> { ["format"] = "json" } 可接收 JSON 封装结果,而不是原始页面内容。

一个包,所有 API

每个 Crawlbase 产品都有对应的客户端类。相同的构造函数(单个 token 字符串),相同的 Get / GetAsync / Post / PostAsync 形式。

string token = "YOUR_TOKEN";

var crawl = new Crawlbase.API(token); // Crawling API
var scraper = new Crawlbase.ScraperAPI(token); // parsed JSON for supported sites
var leads = new Crawlbase.LeadsAPI(token); // domain-scoped email extraction (legacy)
var shots = new Crawlbase.ScreenshotsAPI(token); // body is base64-encoded image
var storage = new Crawlbase.StorageAPI(token); // Cloud Storage CRUD

// Push high-volume async jobs to the Enterprise Crawler via the Crawling API:
// api.Get(url, options) where options carries `callback=true` + `crawler=YourCrawler`.
// See /docs/crawler for the queue-management workflow.

常见模式

JavaScript 渲染

对于 SPA、懒加载信息流,以及初始 HTML 为空的页面,使用 JavaScript token 进行实例化,并传入 page_waitajax_waitscrollcss_click_selector 的任意组合。建议的顺序:先固定等待,再等待网络空闲,然后滚动以触发懒加载,最后点击任何拦截 UI 元素。

var api = new Crawlbase.API("YOUR_JS_TOKEN");

await api.GetAsync("https://spa.example.com", new Dictionary<string, object> {
 ["page_wait"] = 2000,
 ["ajax_wait"] = true,
 ["scroll"] = true,
});

使用内置 Scraper

在受支持的网站上完全跳过解析器。传入 ["scraper"] = "NAME",body 就会变成一个 JSON 字符串,包含每个 scraper 页面所记录的结构化字段。

using System.Text.Json;

var api = new Crawlbase.ScraperAPI("YOUR_TOKEN");
await api.GetAsync(
 "https://www.amazon.com/dp/1098145356",
 new Dictionary<string, object> { ["scraper"] = "amazon-product-details" }
);

var data = JsonSerializer.Deserialize<JsonElement>(api.Body);
Console.WriteLine($"{data.GetProperty("name")} - {data.GetProperty("price")}");

地理路由

传入 ["country"] = "ISO" 即可通过该国家的出口节点路由爬取请求。当目标网站根据 IP 提供本地化内容时使用此功能。

var api = new Crawlbase.API("YOUR_TOKEN");

// Hit the German Amazon catalog from a German residential IP
await api.GetAsync(
 "https://www.amazon.com/dp/1098145356",
 new Dictionary<string, object> { ["country"] = "DE" }
);

带退避的重试

推荐的重试形式:指数退避,最多 3-5 次尝试,仅对临时错误(5xx 或空 body)进行重试,不要对 4xx 进行重试。

public async Task<bool> CrawlAsync(Crawlbase.API api, string url, int attempts = 5) {
 var rand = new Random();
 for (int i = 0; i < attempts; i++) {
 try {
 await api.GetAsync(url);
 } catch (Exception) {
 // SDK throws on transport failures - fall through to retry
 }
 if (api.StatusCode == 200 && api.CrawlbaseStatus == 200) {
 return true;
 }
 if (api.StatusCode is >= 400 and < 500) {
 throw new InvalidOperationException($"client error {api.StatusCode}: {url}");
 }
 // Exponential backoff with jitter
 var ms = (int) (rand.NextDouble() * Math.Pow(2, i) * 1000);
 await Task.Delay(ms);
 }
 return false;
}

异步爬取 + Webhook

发后即忘模式。传入 ["async"] = true["callback"] URL;调用会立即返回,当页面就绪时 Crawlbase 会将结果 POST 到您的 webhook。适用于批处理任务和较慢的目标。

var api = new Crawlbase.API("YOUR_TOKEN");

await api.GetAsync("https://example.com", new Dictionary<string, object> {
 ["async"] = true,
 ["callback"] = "https://your-app.com/webhook",
});

// api.Body is a JSON envelope { rid: ... } - use that to correlate
// the eventual webhook delivery.
//
// Your ASP.NET / Minimal API endpoint receives a POST with:
// { rid, url, original_status, pc_status, body }

对于超大批量(数百万个 URL),请使用 Enterprise Crawler,它位于这一相同异步管道的前端。

粘性会话

某些流程需要在多次调用之间使用同一个住宅 IP。传入 cookies_session 和一个稳定的标识符,Crawlbase 会在约 30 分钟内复用同一个出口节点。

var api = new Crawlbase.API("YOUR_JS_TOKEN");

var session = $"checkout-{userId}";
var opts = new Dictionary<string, object> { ["cookies_session"] = session };

await api.GetAsync("https://shop.example.com/cart", opts);
await api.GetAsync("https://shop.example.com/checkout", opts);
await api.GetAsync("https://shop.example.com/confirm", opts);

Cloud Storage CRUD

Storage API 是「响应挂在 api 实例上」这一模式的例外:它的方法返回一个可直接读取的响应对象。读取先前 Crawling API 调用(store=true)保存的结果时很有用。

var storage = new Crawlbase.StorageAPI("YOUR_TOKEN");

// Fetch by URL
var response = storage.GetByUrl("https://www.apple.com");
Console.WriteLine(response.OriginalStatus);
Console.WriteLine(response.CrawlbaseStatus);
Console.WriteLine(response.URL);
Console.WriteLine(response.RID);
Console.WriteLine(response.StoredAt);

// Or fetch by RID, delete, bulk-fetch, list RIDs, total count
var item = storage.GetByRID(rid);
bool deleted = storage.Delete(rid);
var items = storage.Bulk(new List<string> { rid1, rid2 });
var rids = storage.RIDs(100); // optional limit
var total = storage.TotalCount();

错误 & 重试

平台在每个响应上都返回两个状态码:SDK 自身的 api.StatusCode(请求 Crawlbase 本身的 HTTP 状态)和 api.CrawlbaseStatus(Crawlbase 对目标的判定结果:完整列表参见 Crawling API 错误表)。决定是否重试时,请始终根据 api.CrawlbaseStatus 进行分支:目标可能返回 200 但响应正文为空,这种情况下 StatusCode200,而 CrawlbaseStatus520

try {
 await api.GetAsync(url);
} catch (Exception ex) {
 log.LogError(ex, "transport error");
 return;
}

int pc = api.CrawlbaseStatus;

switch (pc) {
 case 200:
 UseBody(api.Body);
 break;
 case 520 or 525:
 // 520 = empty body, 525 = anti-bot couldn't be solved.
 // Switch to JS token and retry.
 await RetryWithJsTokenAsync(url);
 break;
 case 521 or 522 or 523:
 // Target unreachable or timed out. Retry with backoff.
 ScheduleRetry(url);
 break;
 default:
 log.LogError("crawl failed url={Url} crawlbase_status={CrawlbaseStatus}", url, pc);
 break;
}

针对平台的所有重试都是免费的:只有成功响应(CrawlbaseStatus: 200)才计入您的配额。

性能 & 最佳实践

  • 每个 token 复用单一客户端。 在您的 DI 容器中将其注册为单例:每个实例都会打开自己的底层 HttpClient。不要为每个请求都构造一个新实例。
  • 使用能用的最便宜的 token。 不要「以防万一」就默认使用 JavaScript token:Normal token 请求更快,并且占用更少的并发量。
  • 优先使用 ajax_wait 而非 page_wait 固定延迟会在每个请求上消耗并发量,即使是快速请求也是如此。
  • 注意 API 实例上的共享状态。 由于 Crawling/Scraper/Leads/Screenshots API 会将响应状态写入 api 对象(而不是返回值),不要在多个并发 Task 之间共享同一个实例:第二个 await 的 GetAsync() 会在第一个任务读取过程中覆盖其响应状态。请为每个 worker 池化一个实例,或使用 StorageAPI 的返回对象式方法(可安全交错调用)。
  • 对于批处理任务:async + webhook,或推送到 Enterprise Crawler。 在同步调用上阻塞的 Awaitable Task 会很快用满并发上限;async + webhook 则会在请求入队的那一刻就释放槽位。

方法参考

所有非 Storage 客户端类共享同一套接口。构造函数接受一个 token 字符串;动作方法以同步 + 异步成对提供,并将响应状态写入 api 实例。

new Crawlbase.API(string token)
构造函数
初始化一个 Crawling API 客户端。Crawlbase.ScraperAPICrawlbase.LeadsAPICrawlbase.ScreenshotsAPICrawlbase.StorageAPI 形式相同。
api.Get(string url, Dictionary options = null)
方法
发送一个 GET(同步)。返回 void;通过 api 上的属性读取响应。
api.GetAsync(string url, Dictionary options = null)
方法
发送一个 GET(异步)。返回 Task。响应模型相同。
api.Post(...) / api.PostAsync(...)
方法
发送 POST。data 是请求体:传入 Dictionary 进行表单编码,或传入字符串作为原始内容。

响应状态:调用之后 api 实例上的属性:

api.StatusCode
int
SDK 向 Crawlbase 发起请求的 HTTP 状态。
api.CrawlbaseStatus
int
Crawlbase 对目标的判定结果。可据此分支决定是否重试。
api.OriginalStatus
int
目标返回给 Crawlbase 的 HTTP 状态。
api.Body
string
页面内容(或在使用 format=json / scraper= 时为 JSON 字符串)。对于 ScreenshotsAPI,此内容为 base64 编码:可使用 Convert.FromBase64String(api.Body) 进行转换。
api.StorageURL / api.StorageRID
string
当调用携带 store=true 时设置。可用于通过 StorageAPI 取回已存储的响应。