API Abfrage von smard

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Jrlohni
User
Beiträge: 4
Registriert: Freitag 20. Januar 2023, 09:30

Moin zusammen,

Ich probiere jetzt seit längerem aus das Skript von der Website: https://pypi.org/project/de-smard/#installation--usage zu nutzen um die Daten abrufen zu können.
Speziell geht es mir tatsächlich um etwas andere Daten von der selben API, allerdings hat auch der Datenabruf nicht geklappt.

Zur Fehlerbeschreibung:
In der "Grundform" (Skript kopiert) kommt der Fehler: unexpected ident für das "try:". Natürlich. das "try" wird noch zum "timestamp = 1 gezählt, da die Einrückungen nicht passen.
Ändere ich die Einrückungen so, dass das "try:" zu Zeilenbeginn steht, dann kommt der Fehler zwar nicht mehr, allerdings können die Variablen "filter_copy bis timestamp" nicht mehr zugeordnet werden, diese erhalten immer den Wert von der vorherigen Variable...

Egal was ich teste, es geht leider nicht...

Grundsätzlich möchte ich über diese API: https://smard.api.bund.dev/ die 15-Min-Werte (quarterhour) von erneuerbaren Erzeugung (Wind, Sonne, Wasser, Biomasse, sonstige) gesamt Erzeugung und Marktpreis Deutschland abrufen. Diese würde ich gerne in einer Datei zur (späteren) Weiterverarbeitung speichern. Eventuell auch später mal in einer Datenbank.
Der Abruf von Stundendaten hat geklappt... nicht jedoch von Viertelstunden Daten. Daher habe ich mich nach einer neuen Möglichkeit umgesehen.

Habt ihr eine Idee zur Umsetzung oder Fehlerbehebung?

Beste Grüße
Johannes
Jrlohni
User
Beiträge: 4
Registriert: Freitag 20. Januar 2023, 09:30

Edit (da ich den Beitrag nicht mehr ändern kann): Ein frischer Kopf bringt fischen Wind...! Ich habe die Lösung (nicht für das Problem) aber für mein vorheriges weshalb ich diese Möglichkeit testen wollte...! Es war ein simpler Rechtschreibfehler in der URL für die API...! Wie Ihr in eurem offenen Brief schon schriebt... manchmal kommt die Idee erst nach dem Abschicken und Verfassen eines Posts!

Vielen Dank euch!
Jrlohni
User
Beiträge: 4
Registriert: Freitag 20. Januar 2023, 09:30

Soo... nun hätte ich doch noch ein Anliegen an euch...:

Ich bekomme über die API folgende Daten:

Code: Alles auswählen

"{\"meta_data\":{\"version\":1,\"created\":1674216511448},\"series\": [[1673823600000,60.01],[1673824500000,60.01],[1673825400000,60.01],[1673826300000,60.01],[1673827200000,60.01],[1673828100000,60.01],[1673829000000,60.01],[1673829900000,60.01],[1673830800000,62.72],[1673831700000,62.72],[1673832600000,62.72],[1673833500000,62.72],[1673834400000,56.1],[1673835300000,56.1],[1673836200000,56.1],[1673837100000,56.1],[1673838000000,63.3],[1673838900000,63.3],[1673839800000,63.3],[1673840700000,63.3],[1673841600000,87.0],[1673842500000,87.0],[1673843400000,87.0],[1673844300000,87.0],[1673845200000,154.63],[1673846100000,154.63],[1673847000000,154.63],[1673847900000,154.63],[1673848800000,175.11],[1673849700000,175.11],[1673850600000,175.11],[1673851500000,175.11],[1673852400000,185.99],[1673853300000,185.99],[1673854200000,185.99],[1673855100000,185.99],[1673856000000,170.0],[1673856900000,170.0],[1673857800000,170.0],[1673858700000,170.0],[1673859600000,150.2],[1673860500000,150.2],[1673861400000,150.2],[1673862300000,150.2]]}"
(Nur ein ausschnitt, geht aber genau so immer weiter...)

Kann mir jemand verraten was das für eine Struktur sein soll? Ich würde es gerne nach den "timestamps" - also z.B.: "1673823600000" filtern und den Wert hinter dem jeweiligen Komma, in diesem Fall: "60.01" erhalten.

Wie kann ich danach filtern? Habe schon mit dem json Package rumprobiert. Aber ich komme da leider nicht weiter...

Beste Grüße und vielen Dank!
Johannes
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist aber JSON. Da muesstest du dann schon konkreter werden, was du probiert hast.
Benutzeravatar
grubenfox
User
Beiträge: 602
Registriert: Freitag 2. Dezember 2022, 15:49

Jrlohni hat geschrieben: Freitag 20. Januar 2023, 13:56 Kann mir jemand verraten was das für eine Struktur sein soll?
Hilft https://github.com/bundesAPI/smard-api/ ... enapi.yaml ?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

@grubenfox: wie kommst du denn auf YAML? Da sind doch klar geschweifte Klammern rund um den Datensatz. Das ist schon JSON, was ein simples "json.loads" auch bestaetigt.
Benutzeravatar
grubenfox
User
Beiträge: 602
Registriert: Freitag 2. Dezember 2022, 15:49

Das ist halt die Doku der API. Also u.a. der Aufrufe und der zurückgelieferten Strukturen.
Jrlohni
User
Beiträge: 4
Registriert: Freitag 20. Januar 2023, 09:30

Moin zusammen,

also die API Doku kenne ich schon. Laut Abfrage ist es ja auch ein .json. Allerdings hab ich das Gefühl das die Doku "sowieso" nicht richtig stimmt bzw. die API auch ein bisschen spinnt. Man achte auf die Kopie der Werte "Filter" und "Region". Dort ist ja bereits die rede vom kaputten API-Design - oder verstehe ich da was falsch?
Noch dazu kann ich nicht mit allen "filtern" die URL für die TimeSeries2 mit "table_data/...." abfragen. Alle Werte funktionieren nur mit "Chart_data"... Eigentlich schade, da "table_data" die "schönere" Rückgabe erzeugt.

Um die Werte aus der Liste auszulesen habe ich z.B. tuple probiert. (Ja ich weiß, ist nicht im JSON package) Nun erstmal noch mit "len("json")" um erstmal drauf zugreifen zu können. Leider komme ich aber nicht so "tief" ins Dict, das ich nur die "value"-Werte auslesen kann. Er gibt mir immer nur alle Werte des Dict's zurück...

Ich würde also gerne die Rückgaben (welche ich mittlerweile "lesbarer" Sortiert habe) nach dem Wert "timestamp" auslesen und weiter verarbeiten.


Mein Programmcode:

Code: Alles auswählen

#import os
import json
import requests
#import time


# Rückgabe der Strompreise und WindOnshoreProduktion in Viertelstundenauflösung ab Montag dem 23.01.2023 00:00 Uhr
response1 = requests.get("https://www.smard.de/app/table_data/4067/DE/4067_DE_quarterhour_1674428400000.json")
response2 = requests.get("https://www.smard.de/app/chart_data/4169/DE/4169_DE_quarterhour_1674428400000.json")

# Ausgabe ob Abruf geklappt hat
print(response1.status_code)

print("\n")

print(response2.status_code)
#print(response2.json())

# Auslesen des aktuellen Wertes für den Strompreis (TODO)
    #print(len(response2.series.values))

# Sortieren der Rückgaben und schreiben in Datei
def jprint1(obj):
    json.dump(obj,open('smard_wind_onshore_4067.json','w'),indent=4, sort_keys=True)
    # Debugging
    #text = json.dumps(obj, sort_keys=True, indent=4)
    #print(text)

jprint1(response1.json())


def jprint2(obj):
    json.dump(obj,open('smard_prices_4169.json','w'),indent=4, sort_keys=True)
    # Debugging
    #text = json.dumps(obj, sort_keys=True, indent=4)
    #print(text)

jprint2(response2.json())

Ausschnitt der Rückgabe von "table_data":

Code: Alles auswählen

{
    "meta_data": {
        "created": 1674463615878,
        "version": 1
    },
    "series": [
        {
            "values": [
                {
                    "timestamp": 1674428400000,
                    "versions": [
                        {
                            "name": null,
                            "value": 1024.75
                        }
                    ]
                },
                {
                    "timestamp": 1674429300000,
                    "versions": [
                        {
                            "name": null,
                            "value": 1045.5
                        }
                    ]
                },
                {
                    "timestamp": 1674430200000,
                    "versions": [
                        {
                            "name": null,
                            "value": 1046.75
                        }
                    ]
                },
                {
                    "timestamp": 1674431100000,
                    "versions": [
                        {
                            "name": null,
                            "value": 1031.75
                        }
                    ]
                },
                {
                    "timestamp": 1674432000000,
                    "versions": [
                        {
                            "name": null,
                            "value": 1039.5
                        }
                    ]
                },

Ausschnitt der Rückgabe von "chart_data":

Code: Alles auswählen

{
    "meta_data": {
        "created": 1674389006725,
        "version": 1
    },
    "series": [
        [
            1674428400000,
            148.96
        ],
        [
            1674429300000,
            148.96
        ],
        [
            1674430200000,
            148.96
        ],
        [
            1674431100000,
            148.96
        ],
        [
            1674432000000,
            149.0
        ],
        [
            1674432900000,
            149.0
        ],
        [
            1674433800000,
            149.0
        ],
        [
            1674434700000,
            149.0
        ],
        [
            1674435600000,
            148.4
        ],
        [
            1674436500000,
            148.4
        ],
        [
            1674437400000,
            148.4
        ],
        [
            1674438300000,
            148.4
        ],
Beste Grüße!
Benutzeravatar
grubenfox
User
Beiträge: 602
Registriert: Freitag 2. Dezember 2022, 15:49

Jrlohni hat geschrieben: Montag 23. Januar 2023, 10:20 also die API Doku kenne ich schon. Laut Abfrage ist es ja auch ein .json. Allerdings hab ich das Gefühl das die Doku "sowieso" nicht richtig stimmt bzw. die API auch ein bisschen spinnt. Man achte auf die Kopie der Werte "Filter" und "Region". Dort ist ja bereits die rede vom kaputten API-Design - oder verstehe ich da was falsch?
Noch dazu kann ich nicht mit allen "filtern" die URL für die TimeSeries2 mit "table_data/...." abfragen. Alle Werte funktionieren nur mit "Chart_data"... Eigentlich schade, da "table_data" die "schönere" Rückgabe erzeugt.
So richtig warm geworden bin ich mit dieser Art der API-Beschreibung auch noch nicht und das man bei manchen Abfragen bestimmte Werte doppelt angeben muss, ist ja auch irgendwie "doppelt gemoppelt" bzw. einfach kaputt.
Über Schönheit ließe sich ja vielleicht streiten.... zu viel überflüssiges Dictionary-Gehampel bei den "table_Data" für meinen Geschmack. Bei "Chart_data" habe ich die Daten, helfen mir die "values", "timestamp", "versions", "value" und "name" beim table_data-Format irgendwie weiter? Verkomplizieren IMHO nur die Auswertung der Daten unnötig.

a.) Bei chart_data ist es eine Liste von Listen die jeweils die gesuchten Daten enthalten

b.) bei table_Date offenbar ein Dictionary mit nur einem Element und das Element besteht aus einer Liste von Dictionaries mit jeweils zwei Elementen, ein einfacher Timspamp und eine Liste mit nur einem Dictionary mit zwei Elementen von denen das eine irgendwie tot bzw. null ist.

Ich vermute mal dass sich a. deutlich leichter auswerten lässt als die Variante von b.

Aber nichtsdestrotrotz finde ich die API an sich schon interessant und würde die Daten vielleicht auch gerne mal abfragen und auswerten. Wenn ich nur wüsste wie darstellen bzw. was ich dann mit den Daten eigentlich machen möchte.
Sirius3
User
Beiträge: 18253
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich finde nicht wirklich eine Frage in Deinem Text. Der Aufbau der Datenstruktur mit Wörterbüchern und Listen sollte Dir klar werden, also dass series eine Liste ist und Values ebenso eine Liste:

Code: Alles auswählen

for series in response1['series']:
    for value in series['values']:
        print(value)
Benutzeravatar
DeaD_EyE
User
Beiträge: 1224
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Ich habe mal den 2. Link genommen.

Code: Alles auswählen

import datetime
import requests
import matplotlib.pyplot as plt


data = requests.get(
    "https://www.smard.de/app/chart_data/4169/DE/4169_DE_quarterhour_1674428400000.json"
).json()

x, y = [], []
for timestamp, value in data["series"]:
    timestamp = datetime.datetime.fromtimestamp(timestamp / 1e3)
    if value is None:
        break
    x.append(timestamp)
    y.append(value)
plt.plot_date(x, y, "-")
plt.show()

sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
sistar_hh
User
Beiträge: 2
Registriert: Sonntag 13. Oktober 2024, 15:33

danke @DeaD_EyE. Das Skript (und das API) funktioniert.
Allerdings funktioniert es scheinbar nur mit bestimmten epoch_ms Werten:

a=1627855200000
print(f"{a} {datetime.fromtimestamp(a/1e3)}")
b=1674428400000
print(f"{b} {datetime.fromtimestamp(b/1e3)}")
c=b+3600000*24
print(f"{c} {datetime.fromtimestamp(c/1e3)}")

a 1627855200000 2021-08-02 00:00:00
b 1674428400000 2023-01-23 00:00:00
c 1674514800000 2023-01-24 00:00:00

a 1627855200000 und b 1674428400000 funktionieren. c 1674514800000 und alles andere, was ich versucht habe aber nicht.
Begehe ich einen Denkfehler?
Danke Ralf
Benutzeravatar
__blackjack__
User
Beiträge: 14004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sistar_hh: Was genau soll denn „funktioniert nicht“ denn heissen? Einen Fehler bekommst Du ja nicht, also hast Du anscheinend etwas anderes als Ergebnis erwartet‽ Was? Und warum?

Wobei ich das Rechnen dann mit `datetime`- und `timedelta`-Objekten machen würde und nicht mit den Ganzzahlen.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
sistar_hh
User
Beiträge: 2
Registriert: Sonntag 13. Oktober 2024, 15:33

Danke für Deine Rückfrage. Die API wirft dann einen 404.

Nach einigem probieren (und anschauen der HTTP Calls aus der Web-Anwendung) habe ich heraus gefunden, dass die API immer einen 404 wirft, wenn man nicht mit einem Timestamp Montag 12:00:00 AM CE(S)T abfragt.
Mit dem folgenden Code funktioniert die Abfrage der aktuellen Woche. Noch fehlende Werte werden für den Timestamp mit dem Value Null im JSON zurück gegeben.

Code: Alles auswählen

with smard.ApiClient(configuration) as api_client:
    api_instance = default_api.DefaultApi(api_client)
    filter = 1223  # Stromerzeugung: Braunkohle
    filter_copy = 1223
    region = "DE"
    region_copy = "DE"
    resolution = "hour"
    # Get the current time in Germany timezone
    now = datetime.datetime.now(pytz.timezone('Europe/Berlin'))
    
    # Calculate the number of days to subtract to get to the last Monday
    days_to_subtract = (now.weekday() + 1) % 7 + 6
    
    # Calculate last Monday at midnight
    last_monday_midnight = now - datetime.timedelta(days=days_to_subtract)
    last_monday_midnight = last_monday_midnight.replace(hour=0, minute=0, second=0, microsecond=0)
    
    # Convert to Unix timestamp in milliseconds
    timestamp = int(last_monday_midnight.timestamp() * 1000)
    
    print(f"Last Monday midnight timestamp: {timestamp}")
    try:
        api_response = api_instance.filter_region_filter_copy_region_copy_resolution_timestamp_json_get(
            filter=filter, filter_copy=filter_copy, region=region, region_copy=region_copy, resolution=resolution, timestamp=timestamp
        )
        print(f"response: {api_response}")
Antworten