关于 scraperapi-ruby-sdk
scraperapi-ruby-sdk 是面向 Ruby 开发者的 ScraperAPI SDK 使用指南,涵盖同步抓取、请求参数和错误处理。它还说明了批量请求使用异步端点及通过结构化数据端点获取 JSON 的方法。
主要功能
- 01使用 Ruby 客户端抓取 URL
- 02配置渲染、代理与地理定位
- 03通过会话复用代理 IP
- 04提交异步批量任务
- 05请求结构化数据端点
适用场景
- 01获取网页 HTML 内容
- 02抓取 JavaScript 渲染的页面
- 03处理同一域名的分页流程
- 04批量抓取 20 个以上 URL
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ scraperapi/ scraperapi-skills --skill scraperapi-ruby-sdk安装后在 Claude Code 中输入/scraperapi-ruby-sdk确认已加载。
详细介绍
ScraperAPI — Ruby SDK 最佳实践
要求: Ruby >= 2.0,gem install scraperapi(或在 Gemfile 中使用 gem 'scraperapi'),SCRAPERAPI_API_KEY 环境变量。
设置
require "scraper_api"
client = ScraperAPI::Client.new(ENV["SCRAPERAPI_API_KEY"])
切勿将 API 密钥硬编码。每次都从环境变量中读取。
基本用法
# Simple GET — returns raw HTML string via .raw_body
html = client.get("https://example.com/").raw_body
puts html
# With a single parameter
html = client.get("https://example.com/", render: true).raw_body
# With multiple parameters
html = client.get(
"https://example.com/",
render: true,
country_code: "us"
).raw_body
参数以关键字参数的形式传入 URL 后。.raw_body 会从响应对象中提取 HTML 字符串。
决策指南
| 情况 | 方法 |
|---|---|
| 单个 URL,同步请求 | client.get(url, **params).raw_body |
| 页面通过 JavaScript 加载内容 | 传入 render: true |
| 网站会拦截数据中心代理 | 传入 premium: true |
| 最强反机器人保护 | 传入 ultra_premium: true |
| 同一域名上的多步骤/分页流程 | 使用 session_number: |
| 20 个以上的 URL 或批处理作业 | 通过 Net::HTTP 或 Faraday 使用异步端点 |
| 受支持的平台(Amazon、Google 等) | 直接使用结构化数据端点 |
参数参考
渲染
# Render JavaScript before returning HTML
# Use when: page is a React/Vue/Angular SPA, or initial scrape returns empty/partial content
# Cost: +10 credits
html = client.get("https://spa-site.com/", render: true).raw_body
# Wait for a specific DOM element (requires render: true)
html = client.get(
"https://spa-site.com/",
render: true,
wait_for_selector: ".product-list"
).raw_body
默认不要添加 render: true——先尝试不使用它。它会增加费用和延迟。
代理和地理定位
# Route through a country-specific proxy — no extra credit cost
html = client.get("https://example.com/", country_code: "gb").raw_body
# Premium residential/mobile IPs — for sites that block datacenter proxies
# Cost: 10 credits (25 with render: true)
html = client.get("https://hard-site.com/", premium: true).raw_body
# Ultra-premium — for the toughest anti-bot protections
# Cost: 30 credits (75 with render: true)
# Note: incompatible with keep_headers — custom headers are discarded
html = client.get("https://hardest-site.com/", ultra_premium: true).raw_body
premium 和 ultra_premium 互斥——切勿同时传入。
升级顺序:标准(1 个积分)→ 渲染(10 个积分)→ premium(10 个积分)→ ultra_premium(30 个积分)。
会话(粘性代理)
# Reuse the same proxy IP across requests — useful for pagination and multi-step flows
# Sessions expire 15 minutes after last use; any integer is a valid session ID
html1 = client.get("https://example.com/page1", session_number: 42).raw_body
html2 = client.get("https://example.com/page2", session_number: 42).raw_body
标头和设备类型
# Forward custom headers to the target site
# Note: keep_headers is ignored when ultra_premium: true
html = client.get(
"https://example.com/",
keep_headers: true
# Pass additional headers via the underlying request object as needed
).raw_body
# Emulate a mobile or desktop browser user-agent
html = client.get("https://example.com/", device_type: "mobile").raw_body
自动解析
# Return structured JSON instead of HTML for supported sites
# Use for Amazon, Google, and other supported platforms when you want clean data
json_result = client.get("https://amazon.com/dp/B09V3KXJPB", autoparse: true).raw_body
升级阶梯
始终从成本最低的选项开始,仅在遭到拦截时升级。
def scrape_with_escalation(client, url)
tiers = [
{},
{ render: true },
{ premium: true },
{ premium: true, render: true },
{ ultra_premium: true },
]
tiers.each do |params|
result = client.get(url, **params).raw_body
return result if result&.include?("<html")
end
nil
end
异步作业(用于批处理)
此 SDK 为同步模式——每次 client.get 都会阻塞,直到收到响应(最长 70 秒)。
对于 20 个以上的 URL,请通过 REST 端点提交异步作业。
require "net/http"
require "json"
API_KEY = ENV["SCRAPERAPI_API_KEY"]
def submit_job(url, api_params = {})
uri = URI("https://async.scraperapi.com/jobs")
payload = { apiKey: API_KEY, url: url, apiParams: api_params }
response = Net::HTTP.post(uri, payload.to_json, "Content-Type" => "application/json")
JSON.parse(response.body) # { "id" => "...", "statusUrl" => "..." }
end
def poll_job(job, max_wait: 120, interval: 5)
deadline = Time.now + max_wait
while Time.now < deadline
uri = URI(job["statusUrl"])
data = JSON.parse(Net::HTTP.get(uri))
return data.dig("response", "body") if data["status"] == "finished"
raise "Job #{job['id']} failed" if data["status"] == "failed"
sleep interval
end
raise "Job #{job['id']} timed out"
end
# Submit all URLs, then collect results
urls = ["https://example.com/page1", "https://example.com/page2"]
jobs = urls.map { |u| submit_job(u) }
results = jobs.map { |j| poll_job(j) }
结构化数据端点
对于受支持的平台,请使用结构化端点获取干净的 JSON,无需解析 HTML。
require "net/http"
require "json"
def structured_get(vertical, params = {})
query = URI.encode_www_form({ api_key: API_KEY }.merge(params))
uri = URI("https://api.scraperapi.com/structured/#{vertical}?#{query}")
response = Net::HTTP.get_response(uri)
raise "Error #{response.code}" unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body)
end
# Google SERP
results = structured_get("google/search", { query: "ruby web scraping" })
# Amazon product details
product = structured_get("amazon/product", { asin: "B09V3KXJPB" })
# eBay search
listings = structured_get("ebay/search", { query: "mechanical keyboard" })
错误处理
HTTP 错误会使 SDK 抛出异常。请检查状态码以确定正确的处理方式。
def safe_scrape(client, url, params = {})
client.get(url, **params).raw_body
rescue => e
status = e.respond_to?(:response) ? e.response&.code&.to_i : nil
case status
when 401 then raise "Invalid API key — check SCRAPERAPI_API_KEY"
when 403 then raise "Blocked or out of credits — try premium: true or ultra_premium: true"
when 429 then raise "Rate limit hit — reduce concurrency or switch to async"
when 500, 503 then raise "Transient error — retry with exponential backoff"
else raise
end
end
状态码参考:200 表示成功,401 表示密钥无效,403 表示遭到拦截/没有积分,404 表示未找到目标, 429 表示速率限制,500/503 表示暂时性错误(不收费,可安全重试)。
积分费用参考
| 请求类型 | 积分 |
|---|---|
| 标准 | 1 |
render: true | 10 |
premium: true | 10 |
premium: true, render: true | 25 |
ultra_premium: true | 30 |
ultra_premium: true, render: true | 75 |