Near Earth Objects von der Nasa auslesen

numerische_astronomie
nasa
python
neo
api
Autor:in

Ansgar Schmidt

Veröffentlichungsdatum

10. April 2025

Angesichts der aktuellen Berichterstattung in der Presse über sogenannte “Killerobjekte” aus dem All, möchte ich ein Beispiel aus der numerischen Astronomie vorstellen, um einen besseren Überblick über Near-Earth Objects (NEOs) zu erhalten.

Die NASA stellt über eine öffentlich zugängliche Programmierschnittstelle API die Möglichkeit bereit, auf ihre aktuelle Datenbank zuzugreifen. Dieses Vorgehen fällt unter das Konzept der Open Data, was bedeutet, dass man nicht einmal ein Benutzerkonto benötigt, um diese wertvollen Daten einzusehen und zu nutzen.

Im Folgenden finden Sie einen entsprechenden Python-Quellcode, um auf diese API zuzugreifen. Dieser Code ermöglicht es uns, die von der NASA bereitgestellten Daten abzurufen und wir werden uns diese Daten anschließend genauer ansehen, um beispielsweise Informationen über die Bahnen, Größen und potenziellen Risiken von erdnahen Objekten zu gewinnen.

!pip install requests

Die Bibliothek Requests ist ein hervorragendes Werkzeug, um auf sehr einfache Weise API-Aufrufe in Python auszuführen und die erhaltenen Ergebnisse anschließend als JSON-Objekt zu verarbeiten (zu parsen). Diese Bibliothek gehört jedoch nicht zum Standardumfang der Python-Installation und muss daher in der Regel separat installiert werden, beispielsweise über den Paketmanager pip.

import time
import requests
from   datetime import datetime, timedelta

Zuerst importieren wir die notwendigen Bibliotheken für Python, um einen API-Aufruf durchzuführen. In diesem Beispielcode verzichten wir bewusst auf die üblichen und wichtigen Überprüfungen der Rückgabewerte des API-Aufrufs. Dies tun wir, um den Code so einfach wie möglich zu halten und uns primär auf das Wesentliche zu konzentrieren: die erfolgreiche Abfrage der Daten von der NASA-API. In einer realen Anwendung wäre es natürlich unerlässlich, die Antwort des Servers auf Fehler oder unerwartete Ergebnisse zu überprüfen, um die Stabilität und Zuverlässigkeit des Programms zu gewährleisten.

days_to_fetch = 7
begin_obj     =  datetime.today()
end_obj       = (datetime.today() + timedelta(days = days_to_fetch))
begin_str     = begin_obj.strftime('%Y-%m-%d')
end_str       = end_obj.strftime('%Y-%m-%d')

Die Variablen begin_str und end_str enthalten nun zwei Zeichenketten, die jeweils ein Datum im Format Jahr-Monat-Tag repräsentieren. begin_str speichert dabei das aktuelle Datum, während end_str das Datum in genau einer Woche enthält. Diese beiden Variablen werden verwendet, um den Zeitraum für die Abfrage von Daten über Near-Earth Objects (NEOs) an die NASA-API zu definieren. Indem wir einen Start- und Endzeitpunkt festlegen, können wir die Ergebnisse auf einen bestimmten Zeitraum eingrenzen, in diesem Fall auf die aktuelle Woche.

print(f"Vom {begin_str} bis zum {end_str}")
Vom 2025-04-09 bis zum 2025-04-16
NASA_URL      = f"https://api.nasa.gov/neo/rest/v1/feed?start_date={begin_str}&end_date={end_str}&api_key=DEMO_KEY"
request_raw   = requests.get(NASA_URL, timeout = 10)
json_data     = request_raw.json()

Damit haben wir nun die Informationen über die nächsten 7 Tage als JSON-Objekt erhalten. Dieses Objekt enthält wahrscheinlich eine strukturierte Sammlung von Daten über alle erdnahen Objekte (NEOs), die in diesem Zeitraum erwartet werden oder deren Beobachtungen stattgefunden haben. Jetzt können wir uns den Inhalt dieses JSON-Objekts einmal genauer ansehen, um zu verstehen, welche spezifischen Informationen uns die NASA-API liefert. Dies könnte beispielsweise eine Liste von NEOs mit Details zu ihrer Größe, Geschwindigkeit, ihrer nächsten Erdannäherung und der Wahrscheinlichkeit eines Einschlags umfassen. Die genaue Struktur des JSON-Objekts zu untersuchen ist der nächste wichtige Schritt, um die relevanten Daten für unsere Analyse oder Übersicht zu extrahieren.

sorted(json_data.keys())
['element_count', 'links', 'near_earth_objects']

Wunderbar, die relevanten Informationen über die erdnahen Objekte (NEOs) finden wir unter dem Schlüssel near_earth_objects innerhalb des JSON-Objekts. Dieser Schlüssel dient als zentraler Zugriffspunkt, um auf die eigentlichen Daten über die NEOs zuzugreifen. Es ist sehr wahrscheinlich, dass der Wert, der diesem Schlüssel zugeordnet ist, eine weitere Struktur enthält, beispielsweise ein Dictionary, in dem die einzelnen Tage innerhalb des von uns abgefragten Zeitraums als Schlüssel dienen und die Werte Listen von NEO-Objekten für den jeweiligen Tag darstellen. Um also die spezifischen Daten zu den NEOs zu erhalten, müssen wir in unserem Python-Code auf dieses Element mit dem Namen near_earth_objects zugreifen.

sorted(json_data['near_earth_objects'].keys())
['2025-04-09',
 '2025-04-10',
 '2025-04-11',
 '2025-04-12',
 '2025-04-13',
 '2025-04-14',
 '2025-04-15',
 '2025-04-16']

Dann schauen wir mal in das aktuelle Datum:

type(json_data['near_earth_objects'][begin_str])
list
sorted(json_data['near_earth_objects'][begin_str][0].keys())
['absolute_magnitude_h',
 'close_approach_data',
 'estimated_diameter',
 'id',
 'is_potentially_hazardous_asteroid',
 'is_sentry_object',
 'links',
 'name',
 'nasa_jpl_url',
 'neo_reference_id']

Wunderbar hier haben wir alle Daten.

json_data['near_earth_objects'][begin_str][0]
{'links': {'self': 'http://api.nasa.gov/neo/rest/v1/neo/3407680?api_key=DEMO_KEY'},
 'id': '3407680',
 'neo_reference_id': '3407680',
 'name': '(2008 FW6)',
 'nasa_jpl_url': 'https://ssd.jpl.nasa.gov/tools/sbdb_lookup.html#/?sstr=3407680',
 'absolute_magnitude_h': 21.0,
 'estimated_diameter': {'kilometers': {'estimated_diameter_min': 0.1677084622,
   'estimated_diameter_max': 0.3750075218},
  'meters': {'estimated_diameter_min': 167.7084621628,
   'estimated_diameter_max': 375.0075217981},
  'miles': {'estimated_diameter_min': 0.1042091748,
   'estimated_diameter_max': 0.2330187988},
  'feet': {'estimated_diameter_min': 550.2246310023,
   'estimated_diameter_max': 1230.3396778159}},
 'is_potentially_hazardous_asteroid': True,
 'close_approach_data': [{'close_approach_date': '2025-04-09',
   'close_approach_date_full': '2025-Apr-09 06:42',
   'epoch_date_close_approach': 1744180920000,
   'relative_velocity': {'kilometers_per_second': '26.7882567653',
    'kilometers_per_hour': '96437.7243550494',
    'miles_per_hour': '59922.6515582806'},
   'miss_distance': {'astronomical': '0.4365028102',
    'lunar': '169.7995931678',
    'kilometers': '65299890.654934274',
    'miles': '40575470.5434060212'},
   'orbiting_body': 'Earth'}],
 'is_sentry_object': False}

Als Nächstes wollen wir das Objekt identifizieren, das in den nächsten 7 Tagen die dichteste Annäherung an die Erde aufweist. Um dies zu bewerkstelligen, müssen wir die Daten, die wir unter dem Schlüssel near_earth_objects gefunden haben, genauer untersuchen. Es ist wahrscheinlich, dass für jeden Tag innerhalb des von uns abgefragten Zeitraums eine Liste von NEOs vorhanden ist, und jedes dieser Objekte wiederum detaillierte Informationen über seine vorhergesagten oder beobachteten Annäherungen an die Erde enthält. Wir werden also diese Daten durchgehen und nach dem Eintrag suchen, der die geringste Distanz zur Erde innerhalb der nächsten sieben Tage angibt. Diese Distanz wird üblicherweise in astronomischen Einheiten (AU) oder in Monddistanzen angegeben.

distance = float('inf')
neo      = None

for days in range(days_to_fetch):
    work_date     = (datetime.today() + timedelta(days = days))
    work_date_str = work_date.strftime('%Y-%m-%d')

    if work_date_str in json_data['near_earth_objects']:
      for i in json_data['near_earth_objects'][work_date_str]:
        miss      = float(i['close_approach_data'][0]['miss_distance']['kilometers'])
        hazardous = i['is_potentially_hazardous_asteroid']

        if hazardous and miss < distance:
          distance = miss
          neo      = i

Was wollen wir genau von diesem Objekt wissen? Name, URL, Groesse , Datum, Abstand mit dem das Objekt an uns vorbeifliegt

name          = neo['name']
url           = neo['nasa_jpl_url']
size_min      = neo['estimated_diameter']['meters']['estimated_diameter_min']
size_max      = neo['estimated_diameter']['meters']['estimated_diameter_max']
size_avr      = size_min + ((size_max - size_min) / 2)
approach_date = neo['close_approach_data'][0]['close_approach_date_full']
distance      = float(neo['close_approach_data'][0]['miss_distance']['kilometers'])

print(f"{name} \nGroesse von: {size_avr:.2f} Metern \nDatum: {approach_date} \nDistance: {distance:.2f} Kilometer")
(2025 FP10) 
Groesse von: 696.21 Metern 
Datum: 2025-Apr-12 03:55 
Distance: 4168566.74 Kilometer

Und hier sind die genauen Daten vom JPL fuer 2025 FP10

Zurück nach oben