2012-05-03 9 views
5

Estoy tratando de analizar un archivo de archivo GitHub con yajl-py. Creo que el formato básico del archivo es una secuencia de objetos JSON, por lo que el archivo en sí no es JSON válido, pero contiene objetos que sí lo son.Yajl análisis error con githubarchive.org secuencia JSON en Python

Para probar esto, he instalado yajl-py y luego se usa el ejemplo de analizador (de https://github.com/pykler/yajl-py/blob/master/examples/yajl_py_example.py) para tratar de analizar un archivo:

python yajl_py_example.py < 2012-03-12-0.json 

donde 2012-03-12-0.json es uno de los ficheros de archivo de GitHub que se ha descomprimido.

Parece que este tipo de cosas debería funcionar desde su implementación de referencia en Ruby. ¿Los paquetes de Python no manejan las transmisiones JSON?

Por cierto, aquí está el error que consigo:

yajl.yajl_common.YajlError: parse error: trailing garbage 
      9478bbc3","type":"PushEvent"}{"repository":{"url":"https://g 
        (right here) ------^ 
+0

"Creo que la básica el formato del archivo es una secuencia de objetos JSON "¿Cómo llegó a esta conclusión? ¿Podríamos inspeccionar el archivo? –

+0

Claro, puede ver el archivo con 'wget http://data.githubarchive.org/2012-03-12-0.json.gz | gzip -d> 2012-03-12-0.json'. Son unos pocos megabytes, por lo que son grandes. – Bialecki

+0

¿Ya entendiste esto? ¿Has probado la opción allow_multiple_values? – Pykler

Respuesta

4

Es necesario utilizar un analizador de flujo para leer los datos. Yajl admite el análisis de flujo continuo, que le permite leer un objeto a la vez desde un archivo/flujo. Habiendo dicho esto, no se ve como Python ha fijaciones de trabajo para Yajl ..

py-yajl ha comentado iterload a cabo, sin saber por qué: https://github.com/rtyler/py-yajl/commit/a618f66005e9798af848c15d9aa35c60331e6687#L1R264

No es una solución de Python, pero se puede utilizar fijaciones de Ruby leer en los datos y emitirla en un formato que necesita:

 
# gem install yajl-ruby 

require 'open-uri' 
require 'zlib' 
require 'yajl' 

gz = open('http://data.githubarchive.org/2012-03-11-12.json.gz') 
js = Zlib::GzipReader.new(gz).read 

Yajl::Parser.parse(js) do |event| 
    print event 
end 
1

el ejemplo no habilita ninguna de las características adicionales Yajl, por lo que busca es necesario tener allow_multiple_values bandera en el analizador. Esto es lo que necesita modificar al ejemplo básico para que analice su archivo.

--- a/examples/yajl_py_example.py 
+++ b/examples/yajl_py_example.py 
@@ -37,6 +37,7 @@ class ContentHandler(YajlContentHandler): 

def main(args): 
    parser = YajlParser(ContentHandler()) 
+ parser.allow_multiple_values = True 
    if args: 
     for fn in args: 
      f = open(fn) 

Yajl-Py es una envoltura delgada alrededor yajl, para que pueda utilizar todas las características Yajl proporciona. Aquí están todos los flags that yajl provides that you can enable:

yajl_allow_comments 
yajl_dont_validate_strings 
yajl_allow_trailing_garbage 
yajl_allow_multiple_values 
yajl_allow_partial_values 

para convertir estas en en yajl-py de hacer lo siguiente:

parser = YajlParser(ContentHandler()) 
# enabling these features, note that to make it more pythonic, the prefix `yajl_` was removed 
parser.allow_comments = True 
parser.dont_validate_strings = True 
parser.allow_trailing_garbage = True 
parser.allow_multiple_values = True 
parser.allow_partial_values = True 
# then go ahead and parse 
parser.parse() 
+0

¿Es posible no imprimir los resultados? El archivo es demasiado grande Solo quiero crear un objeto nuevo, como por ejemplo: data = parser.parse (f) –

-1

Como solución alternativa se puede dividir los archivos GitHub Archive en líneas y luego analizar cada línea como JSON:

import json 
with open('2013-05-31-10.json') as f: 
    lines = f.read().splitlines() 
    for line in lines: 
     rec = json.loads(line) 
     ... 
+0

. Solo hay una línea en los archivos de datos de 2012. –

1

sé que esto ha sido contestada, pero yo prefiero el siguiente enfoque y que no utiliza ningún paquete. El diccionario github está en una sola línea por alguna razón, por lo que no puede suponer un solo diccionario por línea. Esto se ve así:

{"json-key":"json-val", "sub-dict":{"sub-key":"sub-val"}}{"json-key2":"json-val2", "sub-dict2":{"sub-key2":"sub-val2"}} 

Decidí crear una función que busque un diccionario a la vez. Devuelve json como una cadena.

def read_next_dictionary(f): 
    depth = 0 
    json_str = "" 
    while True: 
     c = f.read(1) 
     if not c: 
      break #EOF 
     json_str += str(c) 
     if c == '{': 
      depth += 1 
     elif c == '}': 
      depth -= 1 

     if depth == 0: 
      break 

    return json_str 

que utiliza esta función para recorrer el archivo Github con un bucle while:

arr_of_dicts = [] 
f = open(file_path) 
while True: 
    json_as_str = read_next_dictionary(f) 
    try: 
     json_dict = json.loads(json_as_str) 
     arr_of_dicts.append(json_dict) 
    except: 
     break # exception on loading json to end loop 

pprint.pprint(arr_of_dicts) 

Esto funciona en el puesto conjunto de datos aquí: http://www.githubarchive.org/ (después gunzip)

+0

Su método se rompería en algún lado equivocado. Intenta leer 2012-03-10-22.json.gzip, Comapre con este método: http://stackoverflow.com/questions/36967236/parse-multiple-json-objects- that-are-in-one-line –