Seite 1 von 1

Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 15:05
von Haolong
Guten Tag,

ich versuche mir Python anzueignen und erledige dazu Übungsaufgaben aus einem "Buch". Nun wird von mir verlangt eine API in mein Programm einzubinden und zwar: http://api.open-notify.org/astros.json

Habe jetzt einige Zeit im Internet geforscht, komme aber immer noch nicht auf einen einheitlichen Strang, wie man dieses Thema angeht. Unter anderem habe ich versucht den Post: viewtopic.php?f=1&t=37811&p=289985&hili ... rl#p289985 nachzuvollziehen, jedoch ohne Erfolg.

Ich arbeite in Pycharm mit Python 3.

Versucht habe ich das ganze mit:

Code: Alles auswählen

import urllib.request
import json
url = "http://api.open-notify.org/astros.json"

response = urllib.request.urlopen(url).read()
print(response)
data = json.load(response)
der print Befehl gibt mir:

Code: Alles auswählen

b'{\n  "message": "success", \n  "number": 6, \n  "people": [\n    {\n      "craft": "ISS", \n      "name": "Mikhail Kornienko"\n    }, \n    ...
wenn ich diesen Salat jedoch mit json.load umwandeln möchte, bekomme ich die Fehlermeldung:

Code: Alles auswählen

AttributeError: 'bytes' object has no attribute 'read'
Könnte mir jemand erklären, was ich Schritt für Schritt zu tun habe, um mit den Code der Seite etwas anzufangen?

p.s: das ist hier meiner erster Post, deswegen weß ich nicht wie man den Code in einer schöneren Ansicht darstellt.

Gruß,

Hao

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 15:18
von BlackJack
@Haolong: `json.load()` will keine Bytes sondern ein Dateiobjekt mit einer `read()`-Methode. Deshalb genau diese Fehlermeldung. Also entweder darfst Du nicht selber `read()` auf dem Ergebnis von `urlopen()` aufrufen sondern *das* `json.load()` übergeben, oder Du muss `json.loads()` verwenden (und gegebenfalls die Bytes vorher in eine Zeichenkette dekodieren).

Ich persönlich verwende ja gerne die `requests`-Bibliothek, da kann man JSON-Antworten schon dekodiert abfragen.

Edit: Ich sehe gerade das der Beitrag auf den Du Dich beziehst gar kein `read()` macht, das hast Du dazugeschrieben.

Edit2: Mit `requests` (Python 2, aber das ist egal weil die API bei Python 3 gleich ist):

Code: Alles auswählen

In [3]: requests.get('http://api.open-notify.org/astros.json').json()
Out[3]: 
{u'message': u'success',
 u'number': 6,
 u'people': [{u'craft': u'ISS', u'name': u'Mikhail Kornienko'},
  {u'craft': u'ISS', u'name': u'Scott Kelly'},
  {u'craft': u'ISS', u'name': u'Sergey Volkov'},
  {u'craft': u'ISS', u'name': u'Yuri Malenchenko'},
  {u'craft': u'ISS', u'name': u'Timothy Kopra'},
  {u'craft': u'ISS', u'name': u'Timothy Peake'}]}

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 15:23
von /me
Du hast zwei Probleme. Zuerst einmal bekommst du ein bytes-Objekt zurück aus dem du noch einen String machen musst. Dafür musst du wissen, wie die Daten kodiert worden sind. Ich nehme in meinem Beispielcode einfach mal UTF-8 an, aber Encodings zu raten ist grundsätzlich eine blöde Idee.

Dein zweites Problem ist, dass du json.load statt json.loads verwendest. Schau dir mal an, was für Parameter die beiden Funktionen jeweils haben möchten.

Folgendes Codefragment sollte dir einen Einstieg geben.

Code: Alles auswählen

response = urllib.request.urlopen(url).read()
data = json.load(response.decode('UTF-8'))

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 16:01
von Haolong
Mit dem read() habe ich herumexperimentiert. Ohne read() bekomme ich dieses Objekt zurück:

Code: Alles auswählen

<http.client.HTTPResponse object at 0x0349FAD0>
Ist das gar kein JSON response? Muss ich ein anders Modul nehmen?

Code: Alles auswählen

response = urllib.request.urlopen(url).read()
data = json.load(response.decode('UTF-8'))
damit hat es leider auch nicht geklappt

Code: Alles auswählen

AttributeError: 'HTTPResponse' object has no attribute 'decode'
Wenn wir jetzt mal meinen Code völlig vergessen, wie würdet ihr an das Problem herangehen?

Edit: jetzt habe ich es noch mit dem "requests"-Modul ausprobiert und das klappt super :)

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 16:10
von /me
Die angegebene Exception entspricht nicht dem gezeigten Code. Das kann nur kommen wenn du das read() vergessen hast.

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 16:10
von BlackJack
@Haolong: Fehlermeldung und Code passen nicht zusammen. Da würde wieder die Fehlermeldung mit dem `read`-Attribut kommen, weil auch Zeichenketten keine solche Methode haben.

Von `urlopen()` bekommst Du ein Objekt das die HTTP-Anwort modelliert, also die Header und unter anderem eine Methode um die Daten, die vom Server kommen, zu lesen: `read()`. Entweder gibt man dieses Objekt an `json.load()`, denn das erwartet etwas was eine `read()`-Methode hat, oder man liest die Daten selber mit `read()`, dekodiert die gelesenen Bytes in eine Zeichenkette und übergibst die `json.loads()`. Man beachte den kleinen aber wichtigen Unterschied zwischen `load()` und `loads()`!

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 16:31
von Haolong

Code: Alles auswählen

import json
import urllib.request

url = "http://api.open-notify.org/astros.json"

response = urllib.request.urlopen(url).read()
data = json.load(response.decode('UTF-8'))

print(data)
ergibt diese Meldung;

Code: Alles auswählen

AttributeError: 'str' object has no attribute 'read'
1:1 aus meinem Pycharm kopiert, stimmt was mit meinen Modulen nicht ?

Auch wenn ich noch nicht voll hinter das thema read() load() und loads() gestiegen bin, kann ich nun mit derm requests Modul weiter machen. Danke schonmal dafür.

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 16:57
von Sirius3
@Haolong: wie BlackJack schon geschrieben hat, es muß

Code: Alles auswählen

response = urllib.request.urlopen(url).read()
data = json.loads(response.decode('UTF-8'))
oder

Code: Alles auswählen

response = urllib.request.urlopen(url)
data = json.load(response)
heißen.

Re: Verwertung von JSON response

Verfasst: Dienstag 26. Januar 2016, 17:01
von Haolong
ok sorry, mit loads() funktioniert es tatsächlich :)

Re: Verwertung von JSON response

Verfasst: Freitag 29. Januar 2016, 10:05
von Haolong
Habe nun meine letzte Aufgabe gut durch das "requests" Modul lösen können. Bei der nächsten Aufgabe gibt es jedoch schon wieder Probleme :(

Von https://www.flickr.com/services/feeds/d ... os_public/ soll ich mir Bilder mit einem bestimmten Tag anzeigen lassen. Durch https://api.flickr.com/services/feeds/p ... ormat=json bekomme ich im Browser eine JSON-Rückmeldung.

In Python requeste ich mit:

Code: Alles auswählen

import requests
url = "https://api.flickr.com/services/feeds/photos_public.gne"+"?format=json"
data = requests.get(url)
print(data)
Rückmeldung:

Code: Alles auswählen

<Response [200]>
Wenn ich das ganze jedoch mit .json() umwandeln möchte:

Code: Alles auswählen

json_data = data.json()
bekomme ich die Fehlermeldung:
Traceback (most recent call last):
File "C:/Users/Haolong/PycharmProjects/Programmier Aufgaben/Aufgaben Skripte/Aufgabe 49.py", line 9, in <module>
data = requests.get(url).json()
File "C:\Users\Haolong\AppData\Roaming\Python\Python35\site-packages\requests\models.py", line 808, in json
return complexjson.loads(self.text, **kwargs)
File "C:\UsersHaolong\AppData\Local\Programs\Python\Python35-32\lib\json\__init__.py", line 319, in loads
return _default_decoder.decode(s)
File "C:\Users\Haolong\AppData\Local\Programs\Python\Python35-32\lib\json\decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\Haolong\AppData\Local\Programs\Python\Python35-32\lib\json\decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Ich kann damit leider wenig anfangen. Habe auch die anderen bereits genannten Methoden von diesem Thread ausprobiert, aber immer stoße ich auf Fehler.

Hoffe ihr könnt mir das Thema nochmal kurz erklären.

Gruß,

Hao

Re: Verwertung von JSON response

Verfasst: Freitag 29. Januar 2016, 10:21
von Dav1d
Wenn du dir https://api.flickr.com/services/feeds/p ... ormat=json anschaust, am Anfang ist ein JS-Callback: `jsonFlickrFeed`. Der ist kein valides JSON, es gibt sicher in der API eine Option um das abzudrehen.

-> Geht tatsächlich https://api.flickr.com/services/feeds/p ... callback=1

Re: Verwertung von JSON response

Verfasst: Freitag 29. Januar 2016, 10:49
von Haolong
Danke für die Hilfe. Nun kann ich per .json() den response verwerten. Ab und zu bekomme ich den Fehler (in unterschiedlichen lines):
File "C:\Users\Haolong\AppData\Local\Programs\Python\Python35-32\lib\json\decoder.py", line 355, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Invalid \escape: line 145 column 550 (char 11242)
Der lässt sich jedoch mit ner while Schleife und try - except umgehen.

Re: Verwertung von JSON response

Verfasst: Freitag 29. Januar 2016, 11:12
von Haolong
ich merke, dass der workaround doch nicht so toll ist, da es sehr lange dauern kann, bis ich eine gültige Rückmeldung bekomme. Warum ist sie manchmal valid und manchmal nicht? Muss ich mit dem response noch etwas machen bevor ich .json() verwende?

Re: Verwertung von JSON response

Verfasst: Freitag 29. Januar 2016, 13:58
von Dav1d
Du kannst wahrscheinlich vom JSONDecoder erben und ihn dazu bringen, dass er die Escapes akzeptiert (wahrscheinlich \x00 escapes).

Re: Verwertung von JSON response

Verfasst: Freitag 29. Januar 2016, 20:26
von BlackJack
Ich hab's gerade mal ausprobiert und das JSON hat \'-Escapes die nicht der JSON-Spezifikation entsprechen und an den Stellen wo ich sie gefunden habe (innerhalb von in "-Eingefassten Zeichenketten), auch völlig unnötig wären, falls sie denn erlaubt wären.

Re: Verwertung von JSON response

Verfasst: Montag 1. Februar 2016, 09:09
von Haolong
bedeutet das, ich kann den Response nicht ordentlich verwerten, da er nicht ordentlich erstellt wurde? Gibt es einen einfachen Weg die Escapes zu umgehen, oder muss ich mir den response in einem anderen Format ausgeben lassen?

Re: Verwertung von JSON response

Verfasst: Montag 1. Februar 2016, 14:55
von BlackJack
@Haolong: Du könntest diese fehlerhaften Escape-Sequenzen ersetzen und dann auf dem Ergebnis davon `json.loads()` aufrufen.