Java
Crawlbase 平台的官方 Java 客户端。JDK 8+,依赖精简 - 同一个 artifact,所有 API,合理默认值。
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_wait、ajax_wait、scroll和css_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_wait、ajax_wait、scroll 和 css_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 实例。
ScraperAPI、LeadsAPI、ScreenshotsAPI 形态相同。options 将任意 Crawling API 参数名映射到对应的值。data 为表单编码的 body。第三个参数为可选的 options。响应状态 - 调用后通过 api 实例上的 getter 方法获取:
format=json / scraper= 时为 JSON 字符串)。对于 ScreenshotsAPI,这是一张 base64 编码的图片 - 请使用 Base64.getDecoder().decode(...) 进行转换。