主题
GET /api/keepa/productsearch
按关键词搜索 Amazon 产品,结果与 Amazon 搜索页顺序一致(自动剔除广告位),每页最多 100 条。
对应 Keepa 官方接口:Product Search
接口
GET https://mcp.keepamore.com/api/keepa/productsearch也支持 别名 GET /api/keepa/search?type=product(计费/缓存与主路径完全共享),便于从 Keepa 官方代码迁移;type 缺省按 product 处理。
计费
| 项目 | units |
|---|---|
| 任意一次成功调用(不论返回 0 或 100 条) | 5 |
任何参数都不会改变本接口的计费金额;建议批量翻页前先确认关键词拼写,避免无效消耗。
参数(Query String)
标 🛠 的为 Keepamore 增强参数——是我们在 Keepa 原始接口基础上的增强字段,用于减小响应体积、提升 AI 上下文友好度,不会改变本接口的计费。
| 名称 | 类型 | 必填 | 默认 | 约束 | 说明 |
|---|---|---|---|---|---|
domain | integer | ✅ | — | 1–12 | 站点 ID,参见 domain 映射。也可用 domainId 别名 |
term | string | ✅ | — | 非空 | 搜索关键词。框架会自动 URL encode,无需手动转义 |
page | integer | 0 | 0–9 | 0-indexed 页码;每页最多 100 条;最多 10 页(共 1000 条上限) | |
asinsOnly | boolean | false | 0/1 或 true/false | 仅返回 ASIN 字符串数组,不含完整产品对象。响应字段名变为 asinList | |
stats | string | — | 天数 / 日期区间 | 在每个产品里附加 stats 字段(current/min/max/平均价等),写法见下文 | |
history | boolean | false | — | 是否返回完整价格历史 CSV。⚠️ 单条产品体积可能放大数十倍,慎用 | |
update | integer | — | ≥ 0 | 数据新鲜度阈值(小时)。0 强制刷新;不传按默认策略 | |
rating | boolean | false | — | 是否在 CSV 中返回评分 / 评论数历史 | |
🛠 historyDays | integer | — | ≥ 1 | 仅保留最近 N 天的历史 CSV(自动开启 history)。比 history=true 体积小很多 | |
🛠 detailLevel | enum | lite | summary/lite/full | 产品对象精简级别,详见下文 |
detailLevel 取值
| 级别 | 含义 | 适用场景 |
|---|---|---|
summary | 仅核心字段:asin、title、brand、当前价格、评分、销量排名等 | AI 上下文敏感、列表展示、首屏摘要 |
lite(默认) | 移除 csv / salesRanks / variationCSV 等大字段,保留其他全部 | 大多数业务场景的最佳平衡 |
full | 完整原始 product 对象,与 Keepa 官方一致 | 需要离线分析或下游再处理 |
stats 写法补充
- 最近 N 天:
stats=30、stats=180等正整数 - 闭区间(两个时间二选一格式即可):
- ISO8601 日期 / 时间:
stats=2024-01-01,2024-06-01或带时分秒 - Unix 毫秒时间戳:
stats=1704067200000,1717200000000
- ISO8601 日期 / 时间:
历史不足时,实际加权平均区间会比指定的短,这是 Keepa 上游的固有行为。
响应
asinsOnly 缺省时:
json
{
"code": "0000",
"msg": "ok",
"data": {
"products": [
{ "asin": "B0...", "title": "...", "brand": "..." /* 见字段说明 */ }
]
},
"metadata": {
/* 见 errors.md */
}
}asinsOnly=1 时:
json
{
"code": "0000",
"msg": "ok",
"data": {
"asinList": ["B0...", "B0...", "..."]
}
}产品对象字段定义详见 Product Object 字段速查;
stats子对象详见 Statistics Object。
示例
bash
# 请将 km_xxx 替换为你的 API Key
# 仅取 ASIN 列表(最常用,做下游处理)
curl "https://mcp.keepamore.com/api/keepa/productsearch?domain=1&term=wireless+earbuds&asinsOnly=1" \
-H "X-API-Key: km_xxx"
# 取摘要 + 30 天价格统计
curl "https://mcp.keepamore.com/api/keepa/productsearch?domain=1&term=wireless+earbuds&stats=30&detailLevel=summary" \
-H "X-API-Key: km_xxx"
# 取最近 90 天历史 CSV(画图用)
curl "https://mcp.keepamore.com/api/keepa/productsearch?domain=1&term=wireless+earbuds&historyDays=90&detailLevel=lite" \
-H "X-API-Key: km_xxx"js
// 请将 km_xxx 替换为你的 API Key
const base = "https://mcp.keepamore.com/api/keepa/productsearch";
const headers = { "X-API-Key": "km_xxx" };
// 1) 仅取 ASIN 列表
const r1 = await fetch(
`${base}?${new URLSearchParams({ domain: "1", term: "wireless earbuds", asinsOnly: "1" })}`,
{ headers },
);
console.log(await r1.json());
// 2) 摘要 + 30 天统计
const r2 = await fetch(
`${base}?${new URLSearchParams({ domain: "1", term: "wireless earbuds", stats: "30", detailLevel: "summary" })}`,
{ headers },
);
console.log(await r2.json());
// 3) 最近 90 天价格曲线
const r3 = await fetch(
`${base}?${new URLSearchParams({ domain: "1", term: "wireless earbuds", historyDays: "90", detailLevel: "lite" })}`,
{ headers },
);
console.log(await r3.json());python
# 请将 km_xxx 替换为你的 API Key
import requests
URL = "https://mcp.keepamore.com/api/keepa/productsearch"
HEADERS = {"X-API-Key": "km_xxx"}
# 1) 仅取 ASIN 列表
r1 = requests.get(URL, params={"domain": 1, "term": "wireless earbuds", "asinsOnly": 1},
headers=HEADERS, timeout=180)
print(r1.json())
# 2) 摘要 + 30 天统计
r2 = requests.get(URL, params={"domain": 1, "term": "wireless earbuds",
"stats": 30, "detailLevel": "summary"},
headers=HEADERS, timeout=180)
print(r2.json())
# 3) 最近 90 天价格曲线
r3 = requests.get(URL, params={"domain": 1, "term": "wireless earbuds",
"historyDays": 90, "detailLevel": "lite"},
headers=HEADERS, timeout=180)
print(r3.json())php
<?php
// 请将 km_xxx 替换为你的 API Key
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client();
$resp = $client->get('https://mcp.keepamore.com/api/keepa/productsearch', [
'headers' => ['X-API-Key' => 'km_xxx'],
'query' => [
'domain' => 1,
'term' => 'wireless earbuds',
'stats' => 30,
'detailLevel' => 'summary',
],
'timeout' => 180,
]);
echo $resp->getBody();java
// 请将 km_xxx 替换为你的 API Key(Java 11+ 标准库)
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
String term = URLEncoder.encode("wireless earbuds", StandardCharsets.UTF_8);
String url = "https://mcp.keepamore.com/api/keepa/productsearch?domain=1"
+ "&term=" + term + "&stats=30&detailLevel=summary";
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("X-API-Key", "km_xxx")
.timeout(Duration.ofSeconds(180))
.GET()
.build();
HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());go
// 请将 km_xxx 替换为你的 API Key(Go 标准库 net/http)
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"time"
)
func main() {
q := url.Values{}
q.Set("domain", "1")
q.Set("term", "wireless earbuds")
q.Set("stats", "30")
q.Set("detailLevel", "summary")
req, _ := http.NewRequest("GET",
"https://mcp.keepamore.com/api/keepa/productsearch?"+q.Encode(), nil)
req.Header.Set("X-API-Key", "km_xxx")
client := &http.Client{Timeout: 180 * time.Second}
resp, err := client.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}典型配方
| 场景 | 建议参数 |
|---|---|
只要 ASIN,再调 /keepa/product 拉详情 | asinsOnly=1 |
| 列表展示(标题 / 价格 / 评分) | stats=30 + detailLevel=summary |
| 画 90 天价格曲线 | historyDays=90 + detailLevel=lite |
| 翻页采集前 1000 条 | 循环 page=0..9 |
错误处理
通用错误码、metadata 字段定义见 错误码总览。常见情况:
- 缺少
term/domain,或参数取值非法 → HTTP400,code以VALIDATION开头 - 上游 Keepa 拒绝或不可达 → HTTP
502,code = UPSTREAM_ERROR,可携带metadata.errorId联系支持