Отслеживание в реальном времени
Готовые к запуску примеры запросов текущих позиций воздушных судов и статистики потока данных. Параметры фильтрации и структура ответа описаны в полном справочнике Отслеживание ВС по ADS-B.
| # | Вопрос | Используемые данные |
|---|---|---|
| 1 | Сколько воздушных судов сейчас в воздухе и какова средняя высота? | /adsb/aircraft/statistics |
| 2 | Какие воздушные суда сейчас летят в воздушном пространстве вокруг KJFK? | /adsb/aircraft |
| 3 | Как распределены воздушные суда по диапазонам высот в ограничивающем прямоугольнике (bbox) над Европой? | /adsb/aircraft |
Требования
x-api-key в каждом запросе (прямая подписка). Подробнее →Установка
Приведённые ниже скрипты используют requests для вызовов API и rich для вывода в терминал. Установите один раз:
pip install requests rich1. Статистика воздушного пространства в реальном времени
Вопрос: Сколько воздушных судов отслеживается прямо сейчас, сколько из них в воздухе и какова средняя высота?
Эндпоинт статистики агрегирует количество по всему потоку данных — параметры не требуются.
import os
import requests
from rich.console import Console
from rich.panel import Panel
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
def fetch_statistics() -> dict:
r = requests.get(
f"{BASE}/adsb/aircraft/statistics",
headers=HEADERS,
timeout=(10, 15),
)
r.raise_for_status()
return r.json()
def main() -> None:
stats = fetch_statistics()
alt = stats.get("altitude_stats") or {}
avg_ft = alt.get("avg_altitude")
max_ft = alt.get("max_altitude")
avg_fl = round(avg_ft / 100) if avg_ft is not None else None
max_fl = round(max_ft / 100) if max_ft is not None else None
lines = [
f"[bold]Total tracked:[/bold] {stats.get('total_aircraft', 0):,}",
f"[bold]Airborne:[/bold] {stats.get('airborne', 0):,}",
f"[bold]On ground:[/bold] {stats.get('on_ground', 0):,}",
]
if avg_ft is not None:
lines.append(f"[bold]Avg altitude:[/bold] {avg_ft:,.0f} ft (FL{avg_fl:03d})")
if max_ft is not None:
lines.append(f"[bold]Max altitude:[/bold] {max_ft:,.0f} ft (FL{max_fl:03d})")
console.print(Panel("\n".join(lines), title="Live ADS-B Statistics", border_style="cyan"))
console.print(
"[dim]ADS-B data refreshes every few seconds — do not cache these results.[/dim]"
)
if __name__ == "__main__":
main()Результат: Панель с общим числом отслеживаемых ВС, числом ВС в воздухе и на земле, средней высотой в ft и FL и максимальной высотой.
Примечание: данные ADS-B быстро устаревают — поток обновляется каждые несколько секунд. Не кэшируйте ответы; в сценариях реального времени всегда запрашивайте свежие данные.
2. Воздушные суда в воздушном пространстве вокруг KJFK
Вопрос: Какие воздушные суда сейчас находятся в воздухе в радиусе 80 km от международного аэропорта имени Джона Ф. Кеннеди?
Отфильтруйте по lat, lon и radius, затем исключите ВС на земле, чтобы видеть только находящиеся в воздухе. Результаты отсортированы по убыванию высоты.
import os
import requests
from rich.console import Console
from rich.table import Table
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
# KJFK coordinates
LAT = 40.6413
LON = -73.7781
RADIUS_KM = 80
LIMIT = 20
def fetch_aircraft_near(lat: float, lon: float, radius: int, limit: int) -> list[dict]:
r = requests.get(
f"{BASE}/adsb/aircraft",
headers=HEADERS,
params={"lat": lat, "lon": lon, "radius": radius, "limit": limit},
timeout=(10, 15),
)
r.raise_for_status()
return r.json().get("aircraft", [])
def main() -> None:
aircraft = fetch_aircraft_near(LAT, LON, RADIUS_KM, LIMIT)
airborne = [
a for a in aircraft
if not a.get("is_on_ground")
]
airborne.sort(key=lambda a: a.get("altitude") or 0, reverse=True)
table = Table(
title=f"Airborne Aircraft within {RADIUS_KM} km of KJFK ({len(airborne)} shown)",
border_style="cyan",
)
table.add_column("Callsign")
table.add_column("ICAO24")
table.add_column("Altitude (ft)", justify="right")
table.add_column("Speed (kt)", justify="right")
table.add_column("Track (°)", justify="right")
table.add_column("Type")
for a in airborne:
alt = f"{int(a['altitude']):,}" if a.get("altitude") is not None else "—"
spd = str(int(a["ground_speed"])) if a.get("ground_speed") is not None else "—"
trk = f"{a['track']:.0f}" if a.get("track") is not None else "—"
table.add_row(
a.get("callsign") or "—",
a.get("icao24") or "—",
alt,
spd,
trk,
a.get("aircraft_type") or "—",
)
console.print(table)
console.print("[dim]On-ground aircraft excluded. ADS-B data refreshes every few seconds.[/dim]")
if __name__ == "__main__":
main()Результат: Таблица воздушных судов в воздухе, отсортированная по убыванию высоты: Позывной | ICAO24 | Высота (ft) | Скорость (kt) | Трек (°) | Тип.
3. Распределение по диапазонам высот в ограничивающем прямоугольнике над Европой
Вопрос: Как сейчас распределены воздушные суда по диапазонам высот в коридоре Париж — Франкфурт?
Запросите ограничивающий прямоугольник через bbox=lat1,lon1,lat2,lon2, затем отнесите каждое ВС к категории Ground / Low / Medium / High. Значения высоты None обрабатываются с помощью флага is_on_ground.
import os
from collections import defaultdict
import requests
from rich.console import Console
from rich.table import Table
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
# Roughly Paris–Frankfurt bounding box
BBOX = "48,2,52,8"
def fetch_bbox(bbox: str) -> list[dict]:
r = requests.get(
f"{BASE}/adsb/aircraft",
headers=HEADERS,
params={"bbox": bbox, "limit": 200},
timeout=(10, 15),
)
r.raise_for_status()
return r.json().get("aircraft", [])
def classify(aircraft: dict) -> str | None:
alt = aircraft.get("altitude")
if alt is None:
return "Ground" if aircraft.get("is_on_ground") else None
if alt < 100:
return "Ground"
if alt < 10_000:
return "Low (<10,000 ft)"
if alt <= 25_000:
return "Medium (10,000–25,000 ft)"
return "High (>25,000 ft)"
def main() -> None:
aircraft = fetch_bbox(BBOX)
bands: dict[str, list[str]] = defaultdict(list)
for a in aircraft:
band = classify(a)
if band is None:
continue
callsign = a.get("callsign") or a.get("icao24") or "?"
bands[band].append(callsign)
order = ["Ground", "Low (<10,000 ft)", "Medium (10,000–25,000 ft)", "High (>25,000 ft)"]
table = Table(title=f"Altitude Distribution — bbox {BBOX}", border_style="cyan")
table.add_column("Band", style="bold")
table.add_column("Count", justify="right")
table.add_column("Example callsigns")
for band in order:
entries = bands.get(band, [])
examples = ", ".join(entries[:3]) if entries else "—"
table.add_row(band, str(len(entries)), examples)
console.print(table)
console.print(
f"[dim]Total aircraft returned: {len(aircraft)}. "
"Aircraft with unknown altitude and not on_ground are excluded.[/dim]"
)
if __name__ == "__main__":
main()Результат: Таблица с четырьмя диапазонами высот, количеством ВС в каждом и не более чем тремя примерами позывных для каждого диапазона.
Лётно-технические характеристики
Интеграция профилей лётно-технических характеристик ВС — данные ICAO Doc 8643 для планирования с учётом дальности, скорости и категории турбулентности следа.
Исторические треки
Интеграция архивов исторических данных ADS-B — поиск рейсов, воспроизведение треков и восстановление картины трафика аэропорта.