登录

SDK 的整体形态

Java SDK 是对 API Reference 中所记录 HTTP API 的轻量封装。在原始 HTTP 调用中作为查询字符串附加的每个 Crawling API 参数,都可作为 HashMap<String, Object> 选项使用 - 名称、默认值和行为均为一一对应。

有一个需要提前了解的特性:Java SDK 将响应状态暴露在 API 实例自身上,而不是返回值对象。api.get(url) 等调用返回 void;您需要通过 api.getStatusCode()api.getBody() 等方法读取结果。这与 Python / Node / Ruby / PHP SDK(它们返回响应对象)不同 - 了解这一点后,其余接口都很直观。

相比直接使用 HttpClient / OkHttp,使用本 SDK 的好处:

  • URL 编码、参数校验和响应解析均开箱即用。
  • 每个 Crawlbase API 对应一个客户端类,共享相同的构造器 / 调用形态。
  • 符合 Java 习惯 - 传输失败使用运行时异常(无需声明受检异常)。
  • 合理的默认值(90 秒超时,自动解码 JSON / gzip 响应)。

源码位于 github.com/crawlbase/crawlbase-java

安装

最新版本发布于 Maven Central。要求 JDK 8+;已通过 JDK 21 测试。

<!-- pom.xml -->
<dependency>
 <groupId>com.crawlbase</groupId>
 <artifactId>crawlbase-java-sdk-pom</artifactId>
 <version>1.1</version>
</dependency>

<!-- Or build.gradle -->
implementation 'com.crawlbase:crawlbase-java-sdk-pom:1.1'

身份验证

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

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

在生产环境中请使用环境变量或 Spring 配置。SDK 本身不会读取它们。模式如下:

import java.util.*;
import com.crawlbase.*;

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

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

HashMap<String, Object> opts = new HashMap<>();
opts.put("page_wait", 2000);
js.get("https://feed.example.com", opts);

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

快速开始

从导入到爬取 HTML,只需三行。注意响应状态保存在 API 实例上:

import com.crawlbase.*;

API api = new API("YOUR_TOKEN");
api.get("https://github.com/anthropic");

if (api.getStatusCode() == 200) {
 System.out.println(api.getBody());
}

在决定是否重试时,根据 api.getStatusCode()(SDK 发往 Crawlbase 的 HTTP 状态)和 api.getCrawlbaseStatus()(Crawlbase 的判定结果 - 见下方错误章节)进行分支处理。传入带有 "format" → "json"HashMap,即可接收 JSON 信封格式而非原始页面内容。

所有 API 集于一个构件

每个 Crawlbase 产品都有对应的客户端类。构造器相同(单个 token 字符串),方法形态一致。

import com.crawlbase.*;

String token = "YOUR_TOKEN";

API crawl = new API(token); // Crawling API: general-purpose page fetch
ScraperAPI scraper = new ScraperAPI(token); // parsed JSON for supported sites
LeadsAPI leads = new LeadsAPI(token); // domain-scoped email extraction (legacy)
ScreenshotsAPI shots = new ScreenshotsAPI(token); // screenshots; body is base64-encoded image bytes

// 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 元素。

API api = new API("YOUR_JS_TOKEN");

HashMap<String, Object> opts = new HashMap<>();
opts.put("page_wait", 2000);
opts.put("ajax_wait", true);
opts.put("scroll", true);

api.get("https://spa.example.com", opts);

使用内置 scraper

在受支持的站点上完全跳过解析步骤。传入 "scraper" → "NAME",响应 body 即变为 JSON 字符串,包含对应 scraper 页面所述的结构化字段。

import com.crawlbase.*;
import com.fasterxml.jackson.databind.*;
import java.util.*;

API api = new API("YOUR_TOKEN");

HashMap<String, Object> opts = new HashMap<>();
opts.put("scraper", "amazon-product-details");
api.get("https://www.amazon.com/dp/1098145356", opts);

ObjectMapper mapper = new ObjectMapper();
Map<String, Object> data = mapper.readValue(api.getBody(), Map.class);
System.out.println(data.get("name") + " - " + data.get("price"));

地理路由

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

API api = new API("YOUR_TOKEN");

// Hit the German Amazon catalog from a German residential IP
HashMap<String, Object> opts = new HashMap<>();
opts.put("country", "DE");
api.get("https://www.amazon.com/dp/1098145356", opts);

带退避的重试

推荐的重试模式:指数退避,最多 3-5 次尝试,仅在瞬时错误(5xx 或空 body)时重试,4xx 不重试。

import com.crawlbase.*;
import java.util.concurrent.ThreadLocalRandom;

public boolean crawl(API api, String url, int attempts) throws InterruptedException {
 for (int i = 0; i < attempts; i++) {
 api.get(url);
 if (api.getStatusCode() == 200 && api.getCrawlbaseStatus() == 200) {
 return true;
 }
 if (api.getStatusCode() >= 400 && api.getStatusCode() < 500) {
 throw new RuntimeException("client error " + api.getStatusCode() + ": " + url);
 }
 // Exponential backoff with jitter
 long ms = (long) (ThreadLocalRandom.current().nextDouble() * Math.pow(2, i) * 1000);
 Thread.sleep(ms);
 }
 return false;
}

异步抓取 + webhook

"一发即弃"模式。传入 "async" → true 和一个 "callback" URL;调用立即返回,Crawlbase 在页面准备就绪后将结果 POST 到您的 webhook。适用于批量任务和较慢的目标站点。

API api = new API("YOUR_TOKEN");

HashMap<String, Object> opts = new HashMap<>();
opts.put("async", true);
opts.put("callback", "https://your-app.com/webhook");
api.get("https://example.com", opts);

// api.getBody() now contains a JSON envelope with { rid: ... }.
// use that to correlate the eventual webhook delivery.
//
// Your Spring / Jakarta servlet receives a POST with:
// { rid, url, original_status, pc_status, body }

对于超大规模(数百万 URL),请使用 Enterprise Crawler,它构建在同一个异步管道之上。

粘性会话

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

API api = new API("YOUR_JS_TOKEN");

String session = "checkout-" + userId;
HashMap<String, Object> opts = new HashMap<>();
opts.put("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);

错误与重试

平台在每个响应中提供两个状态码:SDK 自身的 api.getStatusCode()(发往 Crawlbase 请求的 HTTP 状态)和 api.getCrawlbaseStatus()(Crawlbase 对目标的判定结果 - 完整列表见 Crawling API 错误表)。在决定是否重试时,请始终基于 getCrawlbaseStatus() 进行分支处理 - 目标站点可能返回 200 但响应体为空,此时 getStatusCode()200,而 getCrawlbaseStatus()520

api.get(url);
int pc = api.getCrawlbaseStatus();

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

请注意,所有 SDK 方法在传输失败时都会抛出 RuntimeException(而非受检异常)。请相应地包裹您的重试循环。

所有针对平台的重试均免费 - 只有成功的响应(crawlbaseStatus: 200)才会计入您的配额。

性能与最佳实践

  • 每个 token 复用一个客户端。 将其定义为 Spring bean / CDI 单例 - 每个实例都会打开自己的底层 HTTP 客户端。不要为每个请求构造一个新实例。
  • 使用满足需求的最便宜 token。 不要「以防万一」默认使用 JavaScript token - Normal token 请求更快,占用的并发更少。
  • 优先使用 ajax_wait 而非 page_wait 固定延迟会在每个请求上消耗并发,即便是快速请求也不例外。
  • 注意 API 实例上的共享状态。 由于响应数据存储在 api 对象上(而非返回值上),请勿在多个并发调用的线程间共享同一个 API 实例 - 第二个线程的 api.get() 会在第一个线程读取响应状态的过程中将其覆盖。请为每个工作线程池化一个实例,或使用互斥锁保护。
  • 对于批量任务:使用 async + webhook,或推送到 Enterprise Crawler。 线程池阻塞在同步调用上会迅速占满并发上限;async + webhook 在请求入队的瞬间即释放槽位。

方法参考

所有客户端类共享相同的接口形态。构造函数接受一个 token 字符串;方法名映射底层的 HTTP 方法,并将响应状态写入 api 实例。

new API(String token)
构造函数
初始化 Crawling API 客户端。可选的双参数构造函数用于设置 timeout / proxy。ScraperAPILeadsAPIScreenshotsAPI 形态相同。
api.get(String url)
方法
发送 GET 请求。返回 void;通过 getter 读取响应。
api.get(String url, HashMap<String, Object> options)
方法
发送带选项的 GET 请求。options 将任意 Crawling API 参数名映射到对应的值。
api.post(String url, HashMap<String, Object> data)
方法
发送 POST 请求。data 为表单编码的 body。第三个参数为可选的 options。

响应状态 - 调用后通过 api 实例上的 getter 方法获取:

api.getStatusCode()
int
SDK 向 Crawlbase 发起请求的 HTTP 状态码。
api.getCrawlbaseStatus()
int
Crawlbase 对目标的判定结果。可基于该字段决定是否重试。
api.getOriginalStatus()
int
目标站点返回给 Crawlbase 的 HTTP 状态码。
api.getBody()
String
页面内容(或当使用 format=json / scraper= 时为 JSON 字符串)。对于 ScreenshotsAPI,这是一张 base64 编码的图片 - 请使用 Base64.getDecoder().decode(...) 进行转换。