从 Brave Search API 免费层切换到 Scavio 需要大约 15 分钟的代码更改,并消除了阻碍大多数生产工作负载的每月 2,000 次查询的上限。本教程将引导您逐步完成迁移:将 Brave 响应字段映射到 Scavio 等效项、更新 HTTP 调用、调整错误处理以及验证下游逻辑是否适用于新的响应格式。
前置条件
- 您想要迁移的现有 Brave Search API 集成
- Scavio API 密钥(在 scavio.dev 上免费 250 个积分/月)
- Python 3.9+ 或 Node.js 18+
操作指南
步骤 1: 审核您当前的 Brave Search 使用情况
在迁移之前,请审核您当前如何调用 Brave API。请注意端点、标头、查询参数以及代码实际使用的响应字段。大多数集成仅使用 Web 搜索结果中的标题、URL 和描述,这使得迁移变得简单。
# Typical Brave Search API call you are replacing
import requests
BRAVE_API_KEY = 'your_brave_key'
resp = requests.get(
'https://api.search.brave.com/res/v1/web/search',
headers={'X-Subscription-Token': BRAVE_API_KEY},
params={'q': 'best crm for startups 2026', 'count': 10}
)
data = resp.json()
for result in data.get('web', {}).get('results', []):
print(result['title'], result['url'], result.get('description', ''))步骤 2: 将 Brave 响应字段映射到 Scavio 等效字段
Scavio 在有机数组而不是 web.results 下返回结果。字段名称略有不同:Brave 使用描述,而 Scavio 使用片段。创建映射,以便您可以一次性更新所有引用。
# Field mapping: Brave -> Scavio
# data.web.results -> data.organic
# result.title -> item.title (same)
# result.url -> item.url (same)
# result.description -> item.snippet
# result.extra_snippets -> (not applicable)
# params.q -> json body: query
# params.count -> json body: num
# header X-Subscription-Token -> header x-api-key步骤 3: 替换 API 调用
将 Brave GET 请求替换为 Scavio POST 请求。 Scavio API 使用 JSON 正文代替查询参数,并使用 x-api-key 标头代替 X-Subscription-Token。
import requests
SCAVIO_API_KEY = 'your_scavio_api_key'
def search(query, num=10):
resp = requests.post(
'https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_API_KEY},
json={'query': query, 'num': num}
)
resp.raise_for_status()
data = resp.json()
return [
{
'title': item.get('title', ''),
'url': item.get('url', ''),
'description': item.get('snippet', ''),
}
for item in data.get('organic', [])
]步骤 4: 更新错误处理和速率限制
当您达到免费等级上限时,Brave 将返回 429。 Scavio 返回标准 HTTP 错误代码并包含速率限制标头。更新您的重试逻辑以读取 x-ratelimit-remaining 标头并在达到限制之前而不是之后退出。
import time
def search_with_retry(query, num=10, max_retries=3):
for attempt in range(max_retries):
resp = requests.post(
'https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_API_KEY},
json={'query': query, 'num': num}
)
if resp.status_code == 200:
return resp.json()
if resp.status_code == 429:
wait = 2 ** attempt
print(f'Rate limited, waiting {wait}s...')
time.sleep(wait)
continue
resp.raise_for_status()
raise Exception('Max retries exceeded')步骤 5: 验证输出奇偶校验
在查询示例上并行运行两个 API 并比较结果以验证下游逻辑是否正常工作。检查标题、URL 和描述是否已填充,以及您的解析代码是否可以正确处理新格式。
test_queries = [
'best crm for startups 2026',
'python web scraping tutorial',
'saas pricing page examples',
]
for q in test_queries:
results = search(q, num=5)
print(f'Query: {q}')
print(f' Results: {len(results)}')
for r in results:
assert r['title'], 'Missing title'
assert r['url'], 'Missing url'
print(f' - {r["title"][:60]}')
print()Python 示例
import requests
import time
SCAVIO_API_KEY = 'your_scavio_api_key'
def search(query, num=10, max_retries=3):
for attempt in range(max_retries):
resp = requests.post(
'https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_API_KEY},
json={'query': query, 'num': num}
)
if resp.status_code == 200:
data = resp.json()
return [
{
'title': item.get('title', ''),
'url': item.get('url', ''),
'description': item.get('snippet', ''),
}
for item in data.get('organic', [])
]
if resp.status_code == 429:
time.sleep(2 ** attempt)
continue
resp.raise_for_status()
raise Exception('Max retries exceeded')
# Validate migration
test_queries = [
'best crm for startups 2026',
'python web scraping tutorial',
'saas pricing page examples',
]
for q in test_queries:
results = search(q, num=5)
print(f'Query: {q} -> {len(results)} results')
for r in results:
print(f' {r["title"][:60]}')JavaScript 示例
const SCAVIO_API_KEY = 'your_scavio_api_key';
async function search(query, num = 10, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, num }),
});
if (resp.ok) {
const data = await resp.json();
return (data.organic || []).map(item => ({
title: item.title || '',
url: item.url || '',
description: item.snippet || '',
}));
}
if (resp.status === 429) {
await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
continue;
}
throw new Error(`API error: ${resp.status}`);
}
throw new Error('Max retries exceeded');
}
async function main() {
const testQueries = [
'best crm for startups 2026',
'python web scraping tutorial',
'saas pricing page examples',
];
for (const q of testQueries) {
const results = await search(q, 5);
console.log(`Query: ${q} -> ${results.length} results`);
for (const r of results) {
console.log(` ${r.title.slice(0, 60)}`);
}
}
}
main();预期输出
Query: best crm for startups 2026 -> 5 results
The 10 Best CRMs for Startups in 2026 - Detailed Comparison
...
Query: python web scraping tutorial -> 5 results
...
Query: saas pricing page examples -> 5 results
...