为什么没有 x-api-key
这类产品的常见做法是计量式 REST API:发放密钥、每天几百次请求、按月收费。我们刻意没有这么做,原因有两个。
那对你更差。我们的数据按周变化,而非按请求变化。查询型接口只会给你一个速率上限和一个需要轮换的密钥,换来的东西你直接取一个文件就能得到。
那对我们也更差。在免费服务上放一个按计算量计费的接口,等于主动招来账单。放在 Cloudflare CDN 上的静态文件对我们而言每次请求都是零成本,而且不可能被人做成有成本 —— 所以我们可以坦然地完全开放,而不必为了自保而限制你。
如果你确实需要服务端查询 —— 边界框、增量时间戳、条件筛选 —— 告个知,我们会评估。那需要独立的 worker、按 IP 限流和硬性成本上限;不是能挂在这上面的东西。
接口
所有路径相对于 https://www.specenvoy.com。全部为 GET,且开放 CORS(Access-Control-Allow-Origin: *),浏览器可直接 fetch()。
/data/vantage/data/meta.json—— 从这里开始。构建日期、schema 版本、每个图层的记录数、精度构成与主要国家,以及带许可信息的完整来源清单。/data/vantage/data/layers/<layerId>.json—— 单个图层的记录。图层 id:npp、icbm、space、radar、cmd、navalbase、airbase、garrison、milbase、dam、power、fab、oilgas、port、choke。/data/vantage/data/base/{land,lakes,places,admin1}-<lod>.json—— 底图,源自 Natural Earth,公有领域。坐标为增量编码的整数;累加后除以q。LOD 0/1/2 分别为粗/中/细。/vantage/live/mil—— 军机实时 ADS-B,约每两分钟刷新。尽力而为,无 SLA,也是我们保留随时关闭权利的唯一接口。上游中断时返回{"stale":true}而不是报错。
版本约定
meta.json 带有 "schema": 1。增量变更 —— 新字段、新图层、新记录 —— 会在 schema 1 内直接发生,不另行通知。
破坏性变更会以新文件名发布(layers/npp-v2.json)并提升 schema;旧文件继续提供服务。所以不必锁定版本,读取 schema 即可,我们不会把你弄坏。
记录的 id 是永久的。自动采集记录的 id 形如 <layer>:q<wikidata-qid>,正是为了在上游改名后依然有效。
许可 —— 按文件区分,且并不相同
每个文件在 licence 字段中标明自身许可。请查看该字段;不能把整个数据集当作同一种许可对待。
- 底图 —— 源自 Natural Earth,公有领域。无附加条件。
- 图层文件 —— 许可并不统一,请逐条查看记录的
src。来自 Wikidata 的记录为 CC0。状态、装机容量或年份来自 Global Energy Monitor 的记录为 CC BY 4.0,再分发时必须署名 GEM —— 约 5,500 条,分布于npp、dam与power图层,每条的src中均注明所用追踪数据集与版本。人工核实的记录与全部撰写的说明文字属本站,署名 SpecEnvoy 后可复用。所引用的政府来源(EIA、美国国防部、CASI)属美国公有领域。 - 实时 ADS-B —— ODbL 1.0,上游为 adsb.lol 贡献者。相同方式共享条款适用于派生数据库,因此它位于独立接口,绝不并入图层文件。署名信息随载荷及
X-Data-Licence响应头一同提供。
建议引用格式:Vantage, SpecEnvoy —— 获取于 <日期>, https://www.specenvoy.com/data/vantage/,并附上你所用文件对应的上游致谢。
值得理解的字段
prec——exact|site|area|approx。位置精度。若不按此字段筛选就直接聚合,得出的数字含义会低于你的预期。sg—— 0–100 的重要度百分位,仅在本图层内部计算。地图据此决定低缩放级别下绘制哪些点;人工整理条目固定为 100。请勿跨图层比较sg:水坝与军用机场的排序基于完全不同的总体,跨层比较没有意义。- 图层文件中的
count与total——count为对外计数,不含approx记录;total为文件实际包含的全部记录。meta.json中对应字段为n与all,并另有countries索引,按 ISO 3166-1 二位国家代码给出跨全部图层的对外计数。 tier——A人工核实,B机器采集。ra—— 为1时,说明文字由所引用的结构化字段生成,而非人工撰写。weak—— 为1时,仅有检索型来源;尚缺权威原始出处。src—— 必定存在,至少一条,且必定带 URL 与日期。conflict—— 当公开来源存在分歧时出现,并附说明。我们记录分歧,而不是替读者选一个答案。ll——[经度, 纬度],WGS84。经度在前。
示例代码
以下代码可直接运行。无需密钥、无需注册、无需构建步骤。
1 —— 先读清单,只重新获取有变化的部分。这是我们唯一的请求:built 字段会告诉你某个图层自上次查看后是否更新。图层按周更新,因此高于每日一次的频率对双方都只是浪费流量。
const meta = await (await fetch(
"https://www.specenvoy.com/data/vantage/data/meta.json"
)).json();
console.log(meta.total, "条记录,共", Object.keys(meta.layers).length, "个图层");
console.log(meta.layers.npp);
// { n: 368, tierA: 0, weak: 368, prec: { site: 368 }, top: ["US:94","CN:32", ...] }
2 —— 取单个图层并按国家筛选。每条记录都带 cc(ISO 3166-1 alpha-2)。
const npp = await (await fetch(
"https://www.specenvoy.com/data/vantage/data/layers/npp.json"
)).json();
const chinese = npp.records.filter(r => r.cc === "CN");
console.log(chinese.map(r => `${r.zn || r.n} —— ${r.cap?.mw ?? "?"} MW`));
3 —— 聚合之前先按精度筛选。若跳过这一步,得出的数字含义会低于你的预期:approx 记录是依据一句描述标出的点,误差 ±50 公里。我们不会把它计入任何对外公布的统计,你也不应该。
const solid = npp.records.filter(r => r.prec === "exact" || r.prec === "site");
const hand = npp.records.filter(r => r.tier === "A"); // 人工核实
const owed = npp.records.filter(r => r.weak); // 仅有检索型来源
4 —— 直接画到地图上。ll 的顺序是 [经度, 纬度] —— 经度在前,与 GeoJSON 一致。多数地图库要求纬度在前,这是最容易出错的一处。
const geojson = {
type: "FeatureCollection",
features: npp.records.map(r => ({
type: "Feature",
geometry: { type: "Point", coordinates: r.ll }, // 已是 [经度, 纬度]
properties: { name: r.n, name_zh: r.zn, status: r.status, precision: r.prec },
})),
};
// Leaflet 需要 [纬度, 经度]:L.marker([r.ll[1], r.ll[0]])
5 —— 也可以用 Python。
import requests, pandas as pd
B = "https://www.specenvoy.com/data/vantage/data"
dams = requests.get(f"{B}/layers/dam.json").json()["records"]
df = pd.DataFrame(dams)
df[["lon", "lat"]] = pd.DataFrame(df["ll"].tolist(), index=df.index)
# 坝高(米)位于 cap.h
df["height_m"] = df["cap"].apply(lambda c: (c or {}).get("h"))
print(df.nlargest(10, "height_m")[["n", "cc", "height_m"]])
6 —— 实时数据,以及如何诚实地解读它。尽力而为、无 SLA,也是我们保留随时关闭权利的唯一接口。上游不可用时它返回 HTTP 200 并带 {"stale": true},而不是报错 —— 请检查该标志,而不是状态码。
const live = await (await fetch("https://www.specenvoy.com/vantage/live/mil")).json();
if (!live.ok || live.stale) {
console.warn("数据降级:", live.detail || "上游不可用");
} else {
console.log("当前正在发射信号的军用航空器:", live.total, "架");
}
// live.caveat 中的说明,请一并传递给你自己的用户。
请务必保留该说明。ADS-B 只显示选择发射信号的航空器;军机是否发射由其自行决定,且欧洲与北美以外的接收站覆盖稀疏。把它当作完整图景呈现,是你能用这些数据做的唯一真正有害的事。
署名。请查看每个文件的 licence 字段 —— 它们确实不同。Vantage, SpecEnvoy —— 获取于 <日期>, https://www.specenvoy.com/data/vantage/,并附上你所用文件对应的上游致谢(Natural Earth、Wikidata、Global Energy Monitor、EIA、adsb.lol)。
合理使用,以及我们唯一的请求
随意取用 —— CDN 就是为此而生。若你在轮询,请先读 meta.json,只重新获取 built 日期发生变化的图层;图层按周更新,因此高于每日一次的频率对双方都只是浪费流量。
请不要把实时数据源大规模转发给你自己的用户 —— 请直接访问 adsb.lol,更好的做法是为他们供数。这套接收站网络是这一切的基础。
另外,请把实时载荷中附带的说明一并传递下去。ADS-B 只显示正在发射信号的航空器;军机是否发射由其自行决定。把这些数据当作完整图景转述出去,是你能用它做的唯一真正有害的事。