Ciąg do słownika w Pythonie

126

Więc spędziłem nad tym dużo czasu i wydaje mi się, że powinno to być proste rozwiązanie. Próbuję użyć uwierzytelniania Facebooka, aby zarejestrować użytkowników w mojej witrynie i próbuję to zrobić po stronie serwera. Doszedłem do punktu, w którym otrzymuję token dostępu, a kiedy idę:

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

Informacje, których szukam, otrzymuję jako ciąg, który wygląda następująco:

{"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"}

Wygląda na to, że powinienem być w stanie użyć dict(string)tego, ale otrzymuję ten błąd:

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

Więc próbowałem użyć Pickle, ale otrzymałem ten błąd:

KeyError: '{'

Próbowałem użyć django.serializersdo de-serializacji, ale miałem podobne wyniki. jakieś pomysły? Czuję, że odpowiedź musi być prosta, a ja po prostu jestem głupi. Dzięki za pomoc!

LunaCodeGirl
źródło
Jeśli chcesz oszacować łańcuch jako Python, być może będziesz musiał zmienić swój ciąg: "verified":truenie powiedzie się, chyba że truejest zdefiniowany. Lub możesz użyć "verified":True, lub "verified":"true".
Matt Curtis,
2
@Matt: Wątpię, czy może zmienić format wyjściowy graph.facebook.com.
Fred Nurk,
@Fred: Biorąc pod uwagę tytuł pytania („Ciąg do słownika w Pythonie”), myślę, że mógłby zmienić go z Pythona, zanim zadzwoni ast.literal_eval(). Twoja (poprawiona) odpowiedź jest jednak poprawna - deserializator JSON jest lepszym rozwiązaniem.
Matt Curtis,
1
@MattCurtis: Zmiana tego w niezawodny sposób (przed ast.literal_eval) wymagałaby najpierw przeanalizowania go jako JSON. Wspomniałem ast.literal_eval jako właściwy sposób na zrobienie tego, co OP próbował zrobić z dict (some_string).
Fred Nurk,
@Fred: Myślę, że zgadzamy się na to :-)
Matt Curtis,

Odpowiedzi:

239

Te dane to JSON ! Możesz deserializować go za pomocą wbudowanego jsonmodułu, jeśli korzystasz z Pythona 2.6+, w przeciwnym razie możesz użyć doskonałego simplejsonmodułu innej firmy .

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
źródło
5
Dlaczego umieściłeś uprzed przykładowym ciągiem JSON?
John Machin,
2
@John: Wskazuje ciąg Unicode . Stawiam to głównie z przyzwyczajenia, ale prawdopodobnie API Facebooka może zwrócić dane ze znakami spoza ASCII; w takim przypadku dane zostałyby zakodowane (prawdopodobnie w UTF-8), a decode()-ing dałoby unicodeciąg znaków - czego użyłem w moim przykładzie. Ta strona wspomina również, że JSON jest zawsze w Unicode (wyszukaj termin, jest mniej więcej w połowie)
Cameron,
3
Wskazuje na literał Unicode small-u w Pythonie. Nawyk nie jest dobrym powodem. „Kodowanie znaków tekstu JSON to zawsze Unicode”. - [Uu] nicode NIE jest kodowaniem. To, czego oczekuje json.loads (), to to, co masz "over the wire", czyli zazwyczaj obiekt str zakodowany w ASCII. Jedynym przypadkiem, w którym celowo przesłałbyś json.loads () obiekt Unicode, jest sytuacja, w której jakaś obca osoba przesłała go w UTF-16 i zgodnie z dokumentacją musisz go zdekodować samodzielnie.
John Machin,
1
@John: Tak, small-u unicodeto typ Pythona, który zawiera ciąg znaków Unicode (duży-U). Zgadzam się również, że Unicode wcale nie jest kodowaniem, więc może nie powinienem wskazywać tej strony jako odniesienia. Nie ma jednak powodu, aby unikać przekazywania unicodeciągów do json.loads- dokumentacja jasno stwierdza, że ​​jest to całkowicie akceptowalne, a ja lubię używać wstępnie zdekodowanego ciągu, ponieważ jest bardziej wyraźny.
Cameron,
8
@John: Przepraszam, że jestem pedantyczny, ale json.loads()nie oczekuję strobiektu zakodowanego w ASCII - oczekuje strobiektu zakodowanego w UTF-8 lub unicodeobiektu (lub strobiektu plus jawne kodowanie)
Cameron,
19

Użyj ast.literal_eval do oceny literałów Pythona. Jednak to, co masz, to JSON (na przykład uwaga „prawda”), więc użyj deserializatora JSON.

>>> 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
źródło