JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Code-Stücke können hier veröffentlicht werden.
Antworten
Patricia
User
Beiträge: 14
Registriert: Mittwoch 25. Mai 2022, 08:37

Hallo zusammen

Ich habe einen Code, der bisher gut funktionierte, wenn ich nur einen Wert auslesen wollte:

Code: Alles auswählen

#Lade Datei mit Device ID
df = pd.read_excel ('Device_ID_Zählerstände.xlsx', usecols = "A:F")

#API-URL für Abfrage
base_url =  "https://smart-me.com:443/api/ValuesInPast/"
date = "03.31.2022"
ID = "38a865fc-b8c9-e436-5d2f-71746d3efba6"
url = base_url + ID + "?date=" + date         
Benutzername = 'herreneggB21@gmx.ch'
Passwort = '6417-B21'

api_url = base_url + ID + "?date=" + date         
r = requests.get(api_url, auth=(Benutzername, Passwort))
data = r.json()

#Zählerstand auslesen
Zählerstand_all = data['Values'][0]
Zählerstand1 = int(Zählerstand_all['Value'])
DeviceID = data['DeviceId']
#ID_name = df['Wohnung_Anlage']
#Mieter = df['Mieter']

#Werte in Liste schreiben
ValuesinPast = {'DeviceID': ID, 'Date': date, 'Zählerstand':Zählerstand1}
df2 = pd.DataFrame(ValuesinPast, index=[0])

#Werte zu bestehender Liste hinzufügen
joined_df = pd.merge(df,
                     df2,
                     on = "DeviceID",
                     how = "right")

joined_df

#Als Excel speichern

joined_df.to_excel("Zählerstand per " + date +".xlsx")

Wenn ich das ganze aber nun in einem Loop machen möchte, d.h. ich habe eine Liste mit den Geräte-Nummern, und er soll mir die Werte für all diese Gerätenumemmern auslesen, dann kriege ich zwar in Jupiter Notebook diese Liste, aber am Ende der Liste kommt dann die Fehlermeldung: Expecting value: line 1 column 1 (char 0).

Keine Ahnung was ich falsch mache.
Der Code ist sicher auch viel zu kompliziert geschrieben - bin ein absoluter Beginner in Python!

Wäre cool wenn mir jemand weiterhelfen könnte!

Gruss
Patricia

Code: Alles auswählen

import requests
import pandas as pd
import json

#Lade Datei mit Device ID
df = pd.read_excel ('Device_ID_Zählerstände.xlsx', usecols = "A:F")

#Spalte DeviceID für spätere Verwendung
DeviceID = df["DeviceID"]

#Datum manuell setzen
date = "03.31.2022"

#Loop durch alle DeviceID um Zählerwerte aus API auszulesen
for x in DeviceID:
    #API-URL für Abfrage
    base_url =  "https://smart-me.com:443/api/ValuesInPast/"
    url = base_url + x + "?date=" + date         
    Benutzername = 'xxx'
    Passwort = 'xxx'

    r = requests.get(url, auth=(Benutzername, Passwort))
    data = r.json()
    
    #Zählerstand auslesen
    Zählerstand_all = data['Values'][0]
    Zählerstand1 = int(Zählerstand_all['Value'])
    
   
    #Werte in Liste schreiben
    ValuesinPast = {'DeviceID': x, 'Date': date, 'Zählerstand':Zählerstand1}
    df2 = pd.DataFrame(ValuesinPast, index=[0])

    #Werte zu bestehender Liste hinzufügen
    joined_df = pd.merge(df,
                     df2,
                     on = "DeviceID",
                     how = "right")
    
    #Liste erstellen mit Werten
    print(joined_df)
    
#Als Excel speichern
joined_df.to_excel("Zählerstand per " + date +".xlsx")
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Fehlermeldung besagt, dass die gelieferten Daten aus der Abfrage nicht dem JSON-Format entsprechen. Gib dir zu debugging-Zwecken aus, was denn da geliefert wird. Und teste, welchen HTTP-Status-Code dein Response-Objekt hat. Denn das wird nicht die gewuenschte 200 sein. Sondern etwas anderes, wegen falscher ID oder Zugangsdaten.
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Patricia: Anmerkungen zum Quelltext: Das `json`-Modul wird importiert, aber nicht verwendet.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Konstanten werden am Anfang vom Programm definiert, damit man sie leicht finden und anpassen kann. Insbesondere wenn es sich um Konstanten handelt, wo vorgesehen ist, das der Anwender sie anpassen muss.

Man sollte keine Konstanten Werte innerhalb einer Schleife immer und immer wieder definieren. Die ändern sich ja nicht.

Man nummeriert auch keine Namen. Dann will man sich entweder bessere Namen überlegen, oder gar keine Einzelnamen und -werte sondern eine Datenstruktur. Oft eine Liste.

Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. `df`, `x` (für etwas anderes als eine X-Koordinate oder einen generischen Gleitkommawert), `r`, und so weiter, sind schlechte Namen, weil dem Leser nicht vermitteln was der Wert dahinter bedeutet. Genau dafür sind Namen aber gedacht.

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Falsche Kommentare sind schlimmer als keine Kommentare. Ein Kommentar sollen eventuelle Fragen mit dem Code klären, aber wenn dort falsche Informationen drin stehen, oder gar welche die dem Code direkt wiedersprechen, erreicht man genau das Gegenteil. Der Leser weiss dann nicht was falsch ist, der Code oder der Kommentar. Wenn da also steht es werden Werte zu einer Liste hinzugefügt, aber im Code gar keine Liste(n) sondern Wörterbücher und `DataFrame`-Objekte vorkommen, dann schadet der Kommentar sogar.

`DeviceID` beziehungsweise der Konvention entsprechend `device_id` ist ein guter Name für *eine* Geräte-ID, aber nicht für eine ganze Spalte mit Geräte-IDs. Also `x` sollte `device_id` (Einzahl) heissen und die Spalte besser `device_ids` (Mehrzahl).

Man muss auch nicht jedes kleine Zwischenergebnis an einen Namen binden.

URL-Parameter würde man eher nicht selbst als Zeichenkette zusammenbasteln, sondern das `requests` überlassen. Das kann auch mit Sonderfällen richtig umgehen.

`requests.Response`-Objekte haben eine praktische Methode die eine Ausnahme auslöst wenn die Antwort nicht aus dem OK-Statusbereich war.

`joined_df` wird immer aus `df` und den zuletzt erstellten Daten erstellt, das heisst alle bis auf den letzten Zählerstand gehen verloren.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import pandas as pd
import requests

DATE = "03.31.2022"
BASE_URL = "https://smart-me.com:443/api/ValuesInPast"
AUTH_DATA = ("xxx", "xxx")


def main():
    zaehlerstand_tabelle = pd.read_excel(
        "Device_ID_Zählerstände.xlsx", usecols="A:F"
    )
    for device_id in zaehlerstand_tabelle["DeviceID"]:
        response = requests.get(
            f"{BASE_URL}/{device_id}", params={"date", DATE}, auth=AUTH_DATA
        )
        response.raise_for_status()
        zaehlerstand = int(response.json()["Values"][0]["Value"])

        zaehlerstand_tabelle = pd.merge(
            zaehlerstand_tabelle,
            pd.DataFrame(
                {
                    "DeviceID": [device_id],
                    "Date": [DATE],
                    "Zählerstand": [zaehlerstand],
                }
            ),
            on="DeviceID",
            how="right",
        )
        print(zaehlerstand_tabelle)

    zaehlerstand_tabelle.to_excel(f"Zählerstand per {DATE}.xlsx")


if __name__ == "__main__":
    main()
Für jeden Zählerstand einen `DataFrame` mit genau einer Zeile zu erstellen und den dann zu mergen ist ziemlich krass. Man würde da eher die "DeviceID" zum Index machen und die Zählerstände dann einfach darüber in den ursprünglichen `DataFrame` eintragen.

Und das Datum sollte keine Zeichenkette sein. Das Ergebnis wird als Exceltabelle gespeichert, und Excel kennt Zeitstempel als Datentyp.

Das Format ist auch für Dateinamen unpraktisch, wenn man die beispielsweise lexikografisch sortiert, sind die nicht zeitlich korrekt geordnet. Wobei das Beispieldatum auch ziemlich schräg ist. Das sieht nach amerikanischer Konvention aus erst den Monat und dann den Tag zu schreiben, verwendet aber Punkte statt Schrägstriche um die Komponenten zu trennen. In der Informationsverarbeitung ist das ISO-Format Jahr-Monat-Tag üblich also "2022-03-31".
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Patricia
User
Beiträge: 14
Registriert: Mittwoch 25. Mai 2022, 08:37

Wow so viel Hilfe super!!
Und so viel Fehler wie ich noch mache... :shock:
Also Code 200 als response habe ich erhalten.
Deine anderen Anmerkungen werde ich nun in Ruhe durchgehen und mich wieder melden.
Schon mal vielen Dank!
Patricia
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn das code 200 ist (auch bei der ID, bei der es nicht geht), dann ist das ein schlecht programmierter Service. Aber kannst du ja nix fuer. Der Punkt ist: da kommt nicht das, was du (bzw das Skript) erwartet. Das muss an irgendwas liegen. Entweder falscher Zugriff, Fehlkonfiguration (dass fuer die ID die Daten nicht abgerufen werden duerfen), oder gleich eine nicht-existierende ID.
Patricia
User
Beiträge: 14
Registriert: Mittwoch 25. Mai 2022, 08:37

Super Danke für die Rückmeldung.
Wie gesagt, bei einem Wert funktionierts.
Ich denke es hat was mit der Struktur der Daten zu tun.
Wenn ich die Abfrage mache bevor ich die Daten umstrukturiere (letzte Zeile)..

i

Code: Alles auswählen

mport pandas as pd
import requests

DATE = "03.31.2022"
BASE_URL = "https://smart-me.com:443/api/ValuesInPast"
AUTH_DATA = ("xxx", "xxx")

Code: Alles auswählen

def main():
    zaehlerstand_tabelle = pd.read_excel(
        "Device_ID_Zählerstände.xlsx", usecols="A:F"
    )
    for device_id in zaehlerstand_tabelle["DeviceID"]:
        response = requests.get(
            f"{BASE_URL}/{device_id}", params={"date", DATE}, auth=AUTH_DATA
        )
        response.raise_for_status()
        zaehlerstand = int(response.json()["Values"][0]["Value"])
.. dann erhalte ich diese Liste:

{'DeviceId': '72bcabd2-f1c7-48be-8d48-f23b1606e65e',
'Date': '2022-03-31T00:00:00Z',
'Values': [{'Obis': '1-0:1.8.0*255', 'Value': 31152575.458999995},
{'Obis': '1-0:1.8.1*255', 'Value': 31152575.458999995},
{'Obis': '1-0:1.8.2*255', 'Value': 0.0},
{'Obis': '0-0:0.0.0*0', 'Value': 0.0},
{'Obis': '1-0:2.8.0*255', 'Value': 2702.813},
{'Obis': '1-0:2.8.1*255', 'Value': 2702.813},
{'Obis': '1-0:2.8.2*255', 'Value': 0.0}]}

Mit dem Code..

Code: Alles auswählen

zaehlerstand = int(response.json()["Values"][0]["Value"])
..möchte ich dann einfach nur den ersten Wert auslesen (also den Zählerstand) - also hier die 31152575.
Ich denke das ist evtl. nicht korrekt.

Aber ich denke das ist wohl alles etwas zum kompliziert, ich werde weiter daran rumkknobbeln!

Vielen Dank!!!!!!
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Patricia: Das was Du da bekommst ist keine Liste sondern ein Wörterbuch (`dict`) und der Code um den Zählerstand dort heraus zu holen klappt problemlos, wie man einfach in einer Python-Shell ausprobieren kann:

Code: Alles auswählen

In [6]: data = {'DeviceId': '72bcabd2-f1c7-48be-8d48-f23b1606e65e', 
   ...: 'Date': '2022-03-31T00:00:00Z', 
   ...: 'Values': [{'Obis': '1-0:1.8.0*255', 'Value': 31152575.458999995}, 
   ...: {'Obis': '1-0:1.8.1*255', 'Value': 31152575.458999995}, 
   ...: {'Obis': '1-0:1.8.2*255', 'Value': 0.0}, 
   ...: {'Obis': '0-0:0.0.0*0', 'Value': 0.0}, 
   ...: {'Obis': '1-0:2.8.0*255', 'Value': 2702.813}, 
   ...: {'Obis': '1-0:2.8.1*255', 'Value': 2702.813}, 
   ...: {'Obis': '1-0:2.8.2*255', 'Value': 0.0}]}                               

In [7]: int(data["Values"][0]["Value"])                                         
Out[7]: 31152575
Da kann man das auch interaktiv in den einzelnen Schritten nachvollziehen/entwickeln:

Code: Alles auswählen

In [8]: data                                                                    
Out[8]: 
{'DeviceId': '72bcabd2-f1c7-48be-8d48-f23b1606e65e',
 'Date': '2022-03-31T00:00:00Z',
 'Values': [{'Obis': '1-0:1.8.0*255', 'Value': 31152575.458999995},
  {'Obis': '1-0:1.8.1*255', 'Value': 31152575.458999995},
  {'Obis': '1-0:1.8.2*255', 'Value': 0.0},
  {'Obis': '0-0:0.0.0*0', 'Value': 0.0},
  {'Obis': '1-0:2.8.0*255', 'Value': 2702.813},
  {'Obis': '1-0:2.8.1*255', 'Value': 2702.813},
  {'Obis': '1-0:2.8.2*255', 'Value': 0.0}]}

In [9]: data["Values"]                                                          
Out[9]: 
[{'Obis': '1-0:1.8.0*255', 'Value': 31152575.458999995},
 {'Obis': '1-0:1.8.1*255', 'Value': 31152575.458999995},
 {'Obis': '1-0:1.8.2*255', 'Value': 0.0},
 {'Obis': '0-0:0.0.0*0', 'Value': 0.0},
 {'Obis': '1-0:2.8.0*255', 'Value': 2702.813},
 {'Obis': '1-0:2.8.1*255', 'Value': 2702.813},
 {'Obis': '1-0:2.8.2*255', 'Value': 0.0}]

In [10]: data["Values"][0]                                                      
Out[10]: {'Obis': '1-0:1.8.0*255', 'Value': 31152575.458999995}

In [11]: data["Values"][0]["Value"]                                             
Out[11]: 31152575.458999995

In [12]: int(data["Values"][0]["Value"])                                        
Out[12]: 31152575
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Patricia
User
Beiträge: 14
Registriert: Mittwoch 25. Mai 2022, 08:37

Hallo

Ja das habe ich schon probiert und das hat wie gesagt auch sehr gut geklappt (auch einzelne Teile davon im Jupiter Notebook).
Einfach in der Schlaufe geht es nicht.

Aber wie gesagt, ich bleibe dran!

Danke und schönen Abend!
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie sehen denn die Daten aus, die beim Request, der nicht mehr klappt, zurückkommen?
Patricia
User
Beiträge: 14
Registriert: Mittwoch 25. Mai 2022, 08:37

Jupii!! Den ganzen Tag etwas gebastelt daran und nun geht's - zumindest für die Abfrage 1 Wertes:
die URL war noch falsch (beim Datum hat es ? und = gebraucht, und ich durfte es nicht als param eingeben.

Code: Alles auswählen

import pandas as pd
import requests

DATE = '03.31.2022'
ID = '38a865fc-b8c9-e436-5d2f-71746d3efba6'
BASE_URL = 'https://smart-me.com:443/api/ValuesInPast'
AUTH_DATA = ('xxx', 'xxx'')

def main():
    zaehlerstand_tabelle = pd.read_excel(
        'Device_ids.xlsx', usecols='A:F'
    )
    
    response = requests.get(
        f'{BASE_URL}/{ID}?date={DATE}', auth=AUTH_DATA)
    response.raise_for_status()
    zaehlerstand = int(response.json()["Values"][0]["Value"])
    
    zaehlerstand_tabelle = pd.merge(
        zaehlerstand_tabelle,
        pd.DataFrame(
            {
                'DeviceID': [ID],
                'Date': [DATE],
                'Zählerstand': [zaehlerstand],
            }
        ),
        on='DeviceID',
        how='right',
    )
    print(zaehlerstand_tabelle)

    zaehlerstand_tabelle.to_excel(f"Zählerstand single per {DATE}.xlsx")

if __name__ == "__main__":
    main()

Ich habe dann versucht, das ganze für die dynamische Abfrage aller Geräte laufen zu lassen.
Der Code läuft eigentlich durch, aber..

Code: Alles auswählen

import pandas as pd
import requests

DATE = '08.25.2022'
BASE_URL = 'https://smart-me.com:443/api/ValuesInPast'
AUTH_DATA = ('xxx', 'xxx'')


def main():
    zaehlerstand_tabelle = pd.read_excel(
        "Device_ids.xlsx", usecols="A:F"
    )
    for device_id in zaehlerstand_tabelle["DeviceID"]:
        response = requests.get(
            f'{BASE_URL}/{device_id}?date={DATE}', auth=AUTH_DATA
        )
        response.raise_for_status()
        zaehlerstand = int(response.json()["Values"][0]["Value"])

        zaehlerstand_tabelle = pd.merge(
            zaehlerstand_tabelle,
            pd.DataFrame(
                {
                    "DeviceID": [device_id],
                    "Date": [DATE],
                    "Zählerstand": [zaehlerstand],
                }
            ),
            on="DeviceID",
            how="right",
        )
        print(zaehlerstand_tabelle)

    zaehlerstand_tabelle.to_excel(f"Zählerstand alle per {DATE}.xlsx")


if __name__ == "__main__":
    main()
..ich bekomme nach jeder Ausgabe der Werte eine Meldung die so heisst:

C:\Users\marc_\AppData\Local\Temp/ipykernel_1032/3308018132.py:21: FutureWarning: Passing 'suffixes' which cause duplicate columns {'Date_x', 'Zählerstand_x'} in the result is deprecated and will raise a MergeError in a future version.
zaehlerstand_tabelle = pd.merge(

Und ganz am Ende, nachdem er alle Werte am PC ausgegeben hat noch diese Meldung:
HTTPError: 400 Client Error: Bad Request for url: https://smart-me.com:443/api/ValuesInPa ... 08.25.2022

Das Excel File wird nicht erstellt.

Ich muss jetzt leider weg und kann erst morgen wieder rein schauen.

Vielleicht hat ja jemand von euch Genies eine Idee?

Vielen vielen Dank für alles geleistete bisher!! Ihr seid super.

Grüsse
Patricia
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Patricia: Warum denkst Du das Datum nicht über `params` angeben zu können? Fang nicht an Dir irgendwelchen Aberglauben anzugewöhnen und deswegen nicht den vorgesehenen sauberen, robusteren Weg zu nehmen.

`pandas.merge()` ist halt nicht die richtige Operation. Damit kannst Du *neue* Spalten, die es noch nicht gibt, hinzufügen. Das willst Du hier aber gar nicht. Beziehungsweise falls es "Date" und "Zählestand" in der Ursprungsdatei nicht gibt, willst Du das *einmal* machen, mit *allen* Daten und Zählerständen. Das wäre ja bisher, selbst wenn es so ginge ja wie schon gesagt eine ineffiziente Lösung. Falls es die Spalten noch nicht gibt, würde ich einfach die Daten für die neuen Spalten sammeln und am Ende dann eben diese Spalten zu dem `DateFrame` hinzufügen.

Nachdem alle Werte ausgegeben wurden kann ja nicht sein, sondern nach dem alle Werte bis zu dem für den es die Ausnahme gibt, ausgegeben wurden. Mindestens der fehlt dann ja noch. Stimmt die ID? Kannst Du den Wert manuell im Browser für diese URL abfragen?

Eventuell würde es auch Sinn machen grundsätzlich Fehler/Ausnahmen für jede Abfrage abzufangen und einen NaN-Wert für den Fehlerstand zu speichern. Eventuell auch eine zusätzliche Spalte für eine optionale Fehlermeldung vorzusehen und/oder die Ausnahme zu protokollieren. Protokollieren entweder mit dem `logging`-Modul aus der Standardbibliothek oder mit einer externen Bibliothek wie `loguru`.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Patricia
User
Beiträge: 14
Registriert: Mittwoch 25. Mai 2022, 08:37

Ich bin wirklich ein absoluter Anfänger sorry - und ich würde mich gerne auf deine/eure Tipps vertrauen, sicher!
Es ist nur so, dass der Code nicht läuft wenn ich das mit den params mache.
Ich bekomme dann die Meldung:
too many values to unpack (expected 2)

Ich habs so versucht:

Code: Alles auswählen

DATE = '03.31.2022'
ID = '38a865fc-b8c9-e436-5d2f-71746d3efba6'
BASE_URL = 'https://smart-me.com:443/api/ValuesInPast'
AUTH_DATA = ('herreneggB21@gmx.ch', '6417-B21')

def main():
    zaehlerstand_tabelle = pd.read_excel(
        'Device_ids.xlsx', usecols='A:F'
    )
    
    response = requests.get(
        f'{BASE_URL}/{ID}', params= {'?date=', DATE}, auth=AUTH_DATA)
und so

Code: Alles auswählen

DATE = '03.31.2022'
ID = '38a865fc-b8c9-e436-5d2f-71746d3efba6'
BASE_URL = 'https://smart-me.com:443/api/ValuesInPast'
AUTH_DATA = ('herreneggB21@gmx.ch', '6417-B21')

def main():
    zaehlerstand_tabelle = pd.read_excel(
        'Device_ids.xlsx', usecols='A:F'
    )
       response = requests.get(
        f'{BASE_URL}/{ID}', params= {'date', DATE}, auth=AUTH_DATA)
Ging leider beides nicht. Daher hatte ich es ohne params versucht.

Ich hab alt auf der swagger Seite wo ich die URL erhalte, halt gesehen dass es beim Datum dieses ? und = dabei hat.
ich habe die Daten auch schon im Excel mit Query heruntergeladen, und da musste ich das auch genauso eingeben.
Nur ist Excel zu langsam wenn ich in einem File zu viele Daten runterlade.

Das andere mit dem pandas.merge und mit der neuen Spalte verstehe ich noch nicht so ganz was du meinst.
Muss da morgen wohl mal etwas googeln um eine andere Lösung zu finden.

Schönen Abend!

Patricia
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Patricia: Okay, da hatte ich einen Tippfehler: `params` muss natürlich ein Wörterbuch (`dict`) sein, und keine Menge (`set`): ``{"date": DATE}``.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

@Patricia: Params ist ein dict. Das passt super, weil sich damit die GET-Parameter perfekt abbilden lassen. Das sind nämlich auch Schlüssel-Wert-Paare.
Antworten