2016-01-15 18 views
5

Sto raschiando alcuni dizionari JSONP da AWS (dai file javascript). Dopo aver analizzato i dati non elaborati solo per i dati simili a JSON, in alcuni casi ottengo un JSON valido e posso caricarlo correttamente in Python (json_data = json.loads(json_like_data)). Tuttavia, alcuni JSONP di Amazon non includono le virgolette sulle loro chiavi (vedi quanto segue).Python: Bad JSON - Le chiavi non sono quotate

... 
{type:"storageCurrentGen",sizes: 
[{size:"i2.xlarge",vCPU:"4",ECU:"14",memoryGiB:"30.5",storageGB:"1 x 800 SSD",valueColumns:[{name:"linux",prices:{USD:"0.938"}}]}, 
{size:"i2.2xlarge",vCPU:"8",ECU:"27",memoryGiB:"61",storageGB:"2 x 800 SSD",valueColumns:[{name:"linux",prices:{USD:"1.876"}}]}, 
{size:"i2.4xlarge",vCPU:"16",ECU:"53",memoryGiB:"122",storageGB:"4 x 800 SSD",valueColumns:[{name:"linux",prices:{USD:"3.751"}}]}, 
... 

Per JSONP, funziona ancora come la sintassi JavaScript valida. Tuttavia, il codice json.loads(json_str) di Python fallisce in quanto non valido JSON.

C'è un altro modulo Python YAML che può gestire chiavi non quotate, MA deve esserci uno spazio dopo il punto e virgola (:).

Immagino di avere due opzioni.

  1. In qualche modo sostituire il carattere in mezzo una parentesi aperta o virgola ({ | ,) e due punti (:). Quindi utilizzare json.loads(...).
  2. Aggiungere uno spazio dopo mai due punti (:). Quindi analizzare con yaml.load(...).

La mia ipotesi è che l'opzione 2 sia migliore di 1. Tuttavia, sto cercando il suggerimento di una soluzione migliore.

Qualcuno ha riscontrato un JSON mal formattato come questo prima e ha usato Python per analizzarlo?

+4

Anche per JavaScript, è ** non ** valida JSON. È un JavaScript valido, che non è esattamente la stessa cosa. –

+0

@MartijnPieters Ah. Grazie per il chiarimento. – dlstadther

risposta

13

È possibile installare e utilizzare demjson library; che supporta l'analisi JavaScript (citazioni mancanti) validi:

import demjson 

result = demjson.decode(jsonp_payload) 

Solo quando si imposta la bandiera strict=True non demjson rifiuta di analizzare il vostro input:

>>> import demjson 
>>> demjson.decode('{javascript_style:"Look ma, no quotes!"}') 
{u'javascript_style': u'Look ma, no quotes!'} 
>>> demjson.decode('{javascript_style:"Look ma, no quotes!"}', strict=True) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/mjpieters/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/demjson.py", line 5701, in decode 
    return_stats=(return_stats or write_stats)) 
    File "/Users/mjpieters/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/demjson.py", line 4917, in decode 
    raise errors[0] 
demjson.JSONDecodeError: ('JSON does not allow identifiers to be used as strings', u'javascript_style') 

Uso di un'espressione regolare si può provare a regex la tua strada a JSON valido; questo può portare a falsi positivi tuttavia. Il modello potrebbe essere:

import re 

valid_json = re.sub(r'(?<={|,)([a-zA-Z][a-zA-Z0-9]*)(?=:)', r'"\1"', jsonp_payload) 

Questo corrisponde a un { o ,, seguito da un identificatore JavaScript (un personaggio, seguito da più caratteri o cifre), e seguito direttamente da un : colon. Se i valori quotati contengono tali schemi, riceverai JSON non valido.

+0

#impressedwiththatspeed Grazie mille per una risposta così rapida e completa! – dlstadther

2

È anche possibile farlo (in questo caso particolare) con semplice Regex:

ll = '{type:"storageCurrentGen",sizes:\n[{size:"i2.xlarge",vCPU:"4",ECU:"14",memoryGiB:"30.5",storageGB:"1 x 800 SSD",valueColumns:[{name:"linux",prices:{USD:"0.938"}}]},\n{size:"i2.2xlarge",vCPU:"8",ECU:"27",memoryGiB:"61",storageGB:"2 x 800 SSD",valueColumns:[{name:"linux",prices:{USD:"1.876"}}]},\n{size:"i2.4xlarge",vCPU:"16",ECU:"53",memoryGiB:"122",storageGB:"4 x 800 SSD",valueColumns:[{name:"linux",prices:{USD:"3.751"}}]},' 

ll_patched = re.sub('([{,:])(\w+)([},:])','\\1\"\\2\"\\3',ll) 
>>> ll_patched 
'{"type":"storageCurrentGen","sizes":\n[{"size":"i2.xlarge","vCPU":"4","ECU":"14","memoryGiB":"30.5","storageGB":"1 x 800 SSD","valueColumns":[{"name":"linux","prices":{"USD":"0.938"}}]},\n{"size":"i2.2xlarge","vCPU":"8","ECU":"27","memoryGiB":"61","storageGB":"2 x 800 SSD","valueColumns":[{"name":"linux","prices":{"USD":"1.876"}}]},\n{"size":"i2.4xlarge","vCPU":"16","ECU":"53","memoryGiB":"122","storageGB":"4 x 800 SSD","valueColumns":[{"name":"linux","prices":{"USD":"3.751"}}]},'