Zeichenfolge zum Wörterbuch in Python

126

Ich habe viel zu viel Zeit damit verbracht, und es scheint mir, dass es eine einfache Lösung sein sollte. Ich versuche, die Authentifizierung von Facebook zu verwenden, um Benutzer auf meiner Website zu registrieren, und ich versuche, dies serverseitig zu tun. Ich habe den Punkt erreicht, an dem ich mein Zugriffstoken erhalte und wenn ich gehe zu:

https://graph.facebook.com/me?access_token=MY_ACCESS_TOKEN

Ich erhalte die gesuchten Informationen als Zeichenfolge, die wie folgt aussieht:

{"id":"123456789","name":"John Doe","first_name":"John","last_name":"Doe","link":"http:\/\/www.facebook.com\/jdoe","gender":"male","email":"jdoe\u0040gmail.com","timezone":-7,"locale":"en_US","verified":true,"updated_time":"2011-01-12T02:43:35+0000"}

Es scheint, als ob ich nur in der Lage sein sollte, dies zu verwenden, dict(string)aber ich erhalte den folgenden Fehler:

ValueError: dictionary update sequence element #0 has length 1; 2 is required

Also habe ich versucht, Pickle zu verwenden, aber diesen Fehler erhalten:

KeyError: '{'

Ich habe versucht, es django.serializerszu de-serialisieren, hatte aber ähnliche Ergebnisse. Irgendwelche Gedanken? Ich denke, die Antwort muss einfach sein, und ich bin nur dumm. Vielen Dank für jede Hilfe!

LunaCodeGirl
quelle
Wenn Sie die Zeichenfolge als Python bewerten möchten, müssen Sie möglicherweise die Zeichenfolge ändern: "verified":trueschlägt fehl, sofern nichts anderes truedefiniert ist. Oder Sie könnten verwenden "verified":True, oder "verified":"true".
Matt Curtis
2
@Matt: Ich bezweifle, dass er das Ausgabeformat von graph.facebook.com ändern kann.
Fred Nurk
@Fred: Angesichts des Titels der Frage ("String to Dictionary in Python") könnte er sie vermutlich vor dem Aufruf von Python ändern ast.literal_eval(). Ihre (überarbeitete) Antwort ist jedoch richtig - ein JSON-Deserializer ist eine bessere Lösung.
Matt Curtis
1
@MattCurtis: Um dies auf robuste Weise (vor ast.literal_eval) zu ändern, muss es zunächst als JSON analysiert werden. Ich erwähnte ast.literal_eval als den richtigen Weg, um das zu tun, was das OP mit dict (some_string) zu tun versuchte.
Fred Nurk
@Fred: Ich denke, wir sind uns einig :-)
Matt Curtis

Antworten:

237

Diese Daten sind JSON ! Sie können es mit dem integrierten jsonModul deserialisieren, wenn Sie mit Python 2.6+ arbeiten. Andernfalls können Sie das hervorragende simplejsonModul eines Drittanbieters verwenden .

import json    # or `import simplejson as json` if on Python < 2.6

json_string = u'{ "id":"123456789", ... }'
obj = json.loads(json_string)    # obj now contains a dict of the data
Cameron
quelle
5
Warum haben Sie uIhren Beispiel-JSON-String vorgesetzt?
John Machin
2
@ John: Es zeigt eine Unicode-Zeichenfolge an . Ich habe es meistens nur aus Gewohnheit ausgedrückt, aber vermutlich kann die Facebook-API Daten mit Nicht-ASCII-Zeichen zurückgeben. In diesem Fall würden die Daten codiert (wahrscheinlich in UTF-8), und decode()- wenn sie eine unicodeZeichenfolge ergeben würden - das habe ich in meinem Beispiel verwendet. Außerdem wird auf dieser Seite erwähnt, dass JSON immer in Unicode ist (Suche nach dem Begriff, es ist ungefähr auf halber Strecke)
Cameron
3
Es zeigt ein kleines Unicode-Literal in Python an. Gewohnheit ist kein guter Grund. "Die Zeichenkodierung von JSON-Text ist immer Unicode." - [Uu] nicode ist KEINE Codierung. Was json.loads () erwartet, ist das, was Sie "über den Draht" haben, was normalerweise ein in ASCII codiertes str-Objekt ist. Der einzige Fall, in dem Sie json.loads () absichtlich mit einem Unicode-Objekt füttern würden, ist der, in dem eine fremde Person es in UTF-16 übertragen hat, und wie dokumentiert müssen Sie es selbst dekodieren.
John Machin
1
@ John: Ja, small-u unicodeist der Python-Typ, der eine Unicode-Zeichenfolge (big-U-Eigenname) enthält. Ich stimme auch zu, dass Unicode überhaupt keine Codierung ist, daher sollte ich vielleicht nicht auf diese Seite als Referenz verweisen. Es gibt jedoch keinen Grund, die Übergabe von unicodeZeichenfolgen zu vermeiden. In json.loadsden Dokumenten wird eindeutig angegeben, dass dies durchaus akzeptabel ist, und ich verwende gerne eine vordecodierte Zeichenfolge, da diese expliziter ist.
Cameron
8
@ John: Tut mir leid, pedantisch zu sein, json.loads()erwartet aber kein strin ASCII codiertes Objekt - es erwartet entweder ein strin UTF-8 codiertes Objekt oder ein unicodeObjekt (oder ein strObjekt plus eine explizite Codierung)
Cameron
19

Verwenden Sie ast.literal_eval , um Python-Literale auszuwerten. Was Sie jedoch haben, ist JSON (beachten Sie beispielsweise "true"). Verwenden Sie daher einen JSON-Deserializer.

>>> import json
>>> s = """{"id":"123456789","name":"John Doe","first_name":"John","last_name":"Doe","link":"http:\/\/www.facebook.com\/jdoe","gender":"male","email":"jdoe\u0040gmail.com","timezone":-7,"locale":"en_US","verified":true,"updated_time":"2011-01-12T02:43:35+0000"}"""
>>> json.loads(s)
{u'first_name': u'John', u'last_name': u'Doe', u'verified': True, u'name': u'John Doe', u'locale': u'en_US', u'gender': u'male', u'email': u'[email protected]', u'link': u'http://www.facebook.com/jdoe', u'timezone': -7, u'updated_time': u'2011-01-12T02:43:35+0000', u'id': u'123456789'}
Fred Nurk
quelle