2016-01-15 24 views
5

Bazı JSONP sözlüklerini AWS'den (javascript dosyalarından) kazıyorum. Ham verileri sadece JSON benzeri veriler için ayrıştırdıktan sonra, bazı durumlarda geçerli bir JSON alıyorum ve bunu Python'da (json_data = json.loads(json_like_data)) başarıyla yükleyebilirim. Bununla birlikte, Amazon'un JSONP'lerinden bazıları anahtarlarının etrafında tırnak içermemektedir (aşağıdakilere bakınız).Python: Hatalı JSON - Anahtarlar iletilemiyor

... 
{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"}}]}, 
... 

JSONP için, bu geçerli JavaScript sözdizimi olduğu gibi çalışır. Bununla birlikte, Python'un json.loads(json_str), geçerli değil JSON.

Belirtilmemiş anahtarların işlenebileceği başka bir Python modülü YAML vardır, ANCAK noktalı virgüllerden sonra bir boşluk olmalıdır (:).

İki seçeneğim olduğunu düşünüyorum. (| ,{) ve iki nokta (:)

  1. şekilde açık bir mesnet veya virgül arasında karakteri değiştirmek. Sonra json.loads(...) kullanın.
  2. Sonsuza kadar boşluk bırakarak (:). Daha sonra yaml.load(...) ile ayrıştırın.

Benim tahminim bu seçenek 2'nin 1'den daha iyi olmasıdır. Ancak, daha iyi bir çözüm önerisi arıyorum.

Daha önce olduğu gibi bu şekilde biçimlendirilmiş bir JSON ile karşılaştı ve onu ayrıştırmak için Python'u kullandı mı?

+4

bile JavaScript için, öyle ** değil ** geçerli JSON. Aynı şey değil, geçerli bir JavaScript. –

+0

@MartijnPieters Ah. Bu açıklama için teşekkürler. – dlstadther

cevap

13

demjson library; o geçerli bir JavaScript (eksik tırnak) ayrıştırma destekler:

import demjson 

result = demjson.decode(jsonp_payload) 

Eğer strict=True bayrak demjson girişinizi ayrıştırmak çöp kurulmuştur Yalnızca: yolunuzu regex deneyebilirsiniz normal ifade kullanma

>>> 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') 

geçerli JSON'a; Ancak bu yanlış pozitif sonuçlara yol açabilir.

import re 

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

Bu (daha fazla karakter veya rakam gelen bir karakteri,) bir JavaScript tanımlayıcı ardından { veya ,, maçlar ve bir : iki nokta üst üste doğrudan ardından: desen olurdu. Aldığınız değerler böyle bir kalıp içeriyorsa, geçersiz JSON alırsınız.

+0

#impressedwiththatspeed Böyle hızlı ve eksiksiz bir yanıt için çok teşekkür ederim! – dlstadther

2

Ayrıca basit Regex ile (bu özel durumda) yapabilirsiniz:

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"}}]},'