Ruby
Crawlbase 平台的官方 Ruby gem。在 Ruby 2.7+ 和 JRuby 上提供地道的 Ruby 体验,同一个 gem 覆盖所有 API,默认值贴合大多数 Rails 应用手动配置的结果。
SDK 的设计形态
Ruby gem 是对 API Reference 中所记录的同一 HTTP API 的轻量封装。在原始 HTTP 调用中作为查询字符串附加的每个 Crawling API 参数,都可以作为关键字参数在 gem 中调用,名称、默认值和行为一一对应。gem 不会增加任何参数,也不会隐藏任何参数。
相比直接使用 Net::HTTP / Faraday,使用 gem 的好处:
- URL 编码、参数校验和响应解析开箱即用,应用代码可以专注于业务逻辑。
- 地道的 Ruby 接口:关键字参数、snake_case 参数命名、传输失败时抛出异常、朴素的 Ruby 响应对象。
- 每个 Crawlbase API 对应一个客户端类,所有类共享相同的构造器 / 调用形态。
- 合理的默认值(90 秒超时、自动解析
format=json响应、UTF-8 编码的响应体)—— 与大多数团队首次集成时手动配置的结果一致。
源码位于 github.com/crawlbase/crawlbase-ruby。欢迎提交 Issues 和 PR。
安装
最新版本发布在 RubyGems 上。已在 Ruby 2.7、3.0、3.1、3.2、3.3 + JRuby 上测试通过。
gem install crawlbase
# Or in your Gemfile
gem 'crawlbase'身份认证
每个 Crawlbase API 都使用相同的 token 认证模型。同一个账号下有两种 token:
- Normal Token (TCP) —— 用于静态 HTML、JSON 端点等不需要浏览器的场景。更快、更便宜。
- JavaScript Token
—— 用于 SPA、懒加载信息流,以及任何将内容隐藏在客户端渲染之后的场景。使用
page_wait、ajax_wait、scroll和css_click_selector时必须使用此 token。
在生产环境中,使用 Rails credentials(Rails.application.credentials.crawlbase_token)或环境变量。gem 本身不会读取它们,这是有意为之,便于您完全掌控凭据的来源。模式如下:
require 'crawlbase'
# Pick the right token at instantiation; the gem doesn't switch
# tokens per-call, so keep two clients if you alternate.
api = Crawlbase::API.new(token: ENV.fetch('CRAWLBASE_TOKEN'))
js = Crawlbase::API.new(token: ENV.fetch('CRAWLBASE_JS_TOKEN'))
api.get('https://github.com/anthropic')
js.get('https://feed.example.com', page_wait: 2000)完整的 token 模型与控制台位置见 Authentication 页面。
快速开始
从 require 到爬取 HTML,只需三行:
require 'crawlbase'
api = Crawlbase::API.new(token: 'YOUR_TOKEN')
res = api.get('https://github.com/anthropic')
puts res.body if res.status_code == 200在决定是否重试时,基于 .status_code(gem 到 Crawlbase 的 HTTP 状态)和 .pc_status(Crawlbase 的判定结果,详见下方 Errors)进行分支判断。传入 format: 'json' 可获得 JSON 包装的响应,而非原始页面内容。
所有 API 集于一个 gem
每个 Crawlbase API 都有对应的类。相同的构造器、相同的 get / post 方法。
require 'crawlbase'
token = { token: 'YOUR_TOKEN' }
crawl = Crawlbase::API.new(**token) # general-purpose page fetch
scraper = Crawlbase::ScraperAPI.new(**token) # parsed JSON for supported sites
leads = Crawlbase::LeadsAPI.new(**token) # domain-scoped email extraction (legacy)
shots = Crawlbase::ScreenshotsAPI.new(**token) # screenshots of any URL
storage = Crawlbase::StorageAPI.new(**token) # Cloud Storage CRUD
# Push high-volume async jobs to the Enterprise Crawler via the Crawling API:
# api.get(url, async: true, callback: '...', crawler: 'YourCrawler').
# See /docs/crawler for the queue workflow.常见模式
JavaScript 渲染
对于 SPA、懒加载的 feed,以及初始 HTML 为空的页面,请使用 JavaScript token 实例化,并传入 page_wait、ajax_wait、scroll 和 css_click_selector 的任意组合。建议的思考顺序:先固定等待,再等待网络空闲,然后滚动以触发懒加载,最后点击任何门控的 UI 元素。
api = Crawlbase::API.new(token: 'YOUR_JS_TOKEN')
res = api.get('https://spa.example.com',
page_wait: 2000,
ajax_wait: true,
scroll: true)使用内置 scraper
在受支持的网站上完全跳过解析器。传入 scraper: 'NAME',响应体就会变成一个 JSON 字符串,包含对应 scraper 页面所记录的结构化字段。
require 'crawlbase'
require 'json'
api = Crawlbase::ScraperAPI.new(token: 'YOUR_TOKEN')
res = api.get('https://www.amazon.com/dp/1098145356',
scraper: 'amazon-product-details')
data = JSON.parse(res.body)
puts data['name'], data['price']地理路由
传入 country: 'ISO' 即可通过该国家的出口节点路由爬取请求。当目标网站根据 IP 提供本地化内容时使用。
api = Crawlbase::API.new(token: 'YOUR_TOKEN')
# Hit the German Amazon catalog from a German residential IP
res = api.get('https://www.amazon.com/dp/1098145356', country: 'DE')带退避的重试
推荐的重试方案:指数退避,上限 3-5 次,只对临时性错误重试(5xx 或空响应体),不对 4xx 重试。
require 'crawlbase'
api = Crawlbase::API.new(token: 'YOUR_TOKEN')
def crawl(api, url, attempts: 5)
attempts.times do |i|
res = api.get(url)
return res if res.status_code == 200 && res.pc_status.to_i == 200
raise "client error: %d" % res.status_code if (400..499).include?(res.status_code)
sleep(rand * (2**i)) # exponential backoff with jitter
end
raise "Failed: %s" % url
end异步爬取 + webhook
即发即弃模式。gem 调用立即返回一个 rid;页面就绪后 Crawlbase 会以 POST 方式将结果发送到您的回调 URL。适合批处理任务和响应较慢的目标。
api = Crawlbase::API.new(token: 'YOUR_TOKEN')
res = api.get('https://example.com',
async: true,
callback: 'https://your-app.com/webhook')
rid = res.rid # correlate the eventual webhook delivery
# Your Rails / Sinatra webhook receives a POST with:
# { rid, url, original_status, pc_status, body }对于超大规模(数百万 URL),请使用 Enterprise Crawler,它位于这套异步管道的前端。
粘性会话
某些流程需要在多次调用中复用同一个住宅 IP。传入带稳定标识符的 cookies_session,Crawlbase 会在约 30 分钟内复用同一个出口节点。
api = Crawlbase::API.new(token: 'YOUR_JS_TOKEN')
session = "checkout-#{user_id}"
api.get('https://shop.example.com/cart', cookies_session: session)
api.get('https://shop.example.com/checkout', cookies_session: session)
api.get('https://shop.example.com/confirm', cookies_session: session)错误处理与重试
平台在每个响应中都会返回两个状态码:gem 自身的 .status_code(请求到 Crawlbase 本身的 HTTP 状态)和 .pc_status(Crawlbase 对目标站点的判定结果,完整列表见 Crawling API errors table)。在决定是否重试时,请始终基于 .pc_status 进行判断:目标站点可能返回 200 但响应体为空,此时 .status_code 为 200,而 .pc_status 为 520。
res = api.get(url)
pc = res.pc_status.to_i
case pc
when 200
use(res.body)
when 520, 525
# 520 = empty body, 525 = anti-bot couldn't be solved.
# Switch to JS token and retry.
retry_with_js_token(url)
when 521, 522, 523
# Target unreachable or timed out. Retry with backoff.
schedule_retry(url)
else
Rails.logger.error('crawl failed', url: url, pc_status: pc)
end针对平台的所有重试都是免费的,只有成功响应(pc_status: 200)才会计入您的配额。
性能与最佳实践
- 每个 token 复用一个客户端。 构造器开销很小,但每个实例都会打开自己的连接。在应用启动时构建一次(Rails initializer 是自然的位置),然后在所有请求间共享。
- 使用能跑通的最便宜的 token。 不要为了「以防万一」而默认使用 JavaScript token,Normal token 的请求更快、占用并发更少。仅当 Normal 响应为空或被反爬拦截时再升级到 JS。
- 优先使用
ajax_wait而不是page_wait。 固定延迟会在每次请求上消耗并发额度,即使是很快的请求也不例外。 - 批处理任务:使用异步 + webhook,或推送到 Enterprise Crawler。 Sidekiq worker 同步调用 gem 会很快打满您的并发上限;异步 + webhook 在请求被排队的瞬间就释放了占用槽位。
- 关注响应头中的
remaining。 它会返回您剩余的并发槽数,主动退避,在触及上限之前提前调整,而不是被动应对 429。
方法参考
所有客户端类共享相同的接口。构造器接受关键字参数;方法名与底层 HTTP 方法对应。
timeout,以秒为单位(默认 90)。options 将任何 Crawling API 参数映射为对应的值。返回响应对象。data 是 body:传入哈希为 form-encoded,传入字符串为原始数据。响应结构 —— 响应对象上的方法:
format=json / scraper= 时为 JSON 字符串)。async: true 或 store: true 时)。