Error de análisis de Yajl con githubarchive.org flujo JSON en Python

Estoy tratando de analizar un archivo de 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.

Para probar esto, instalé yajl-py y luego usó su analizador de ejemplo (de https://github.com/pykler/yajl-py/blob/master/examples/yajl_py_example.py) para intentar analizar un archivo:

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

dónde 2012-03-12-0.json es uno de los archivos de almacenamiento de GitHub que se ha descomprimido.

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

Por cierto, este es el error que me sale:

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

preguntado el 03 de mayo de 12 a las 14:05

"Creo que el formato básico del archivo es una secuencia de objetos JSON" ¿Cómo llegó a esta conclusión? ¿Podemos inspeccionar el archivo? -

Claro, puedes 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 es un poco grande. -

¿Ya te diste cuenta de esto? ¿Probó la opción allow_multiple_values? -

vea mi respuesta a continuación para usar correctamente Yajl-Py para analizar su archivo. -

4 Respuestas

Necesita usar un analizador de flujo para leer los datos. Yajl admite el análisis de secuencias, lo que le permite leer un objeto a la vez desde un archivo/secuencia. Habiendo dicho eso, no parece que Python tenga enlaces que funcionen para Yajl.

py-yajl tiene iterload comentó, no estoy seguro de por qué: https://github.com/rtyler/py-yajl/commit/a618f66005e9798af848c15d9aa35c60331e6687#L1R264

No es una solución de Python, pero puede usar enlaces de Ruby para leer los datos y emitirlos en el formato que necesite:

# gema instalar yajl-ruby requiere 'open-uri' requiere 'zlib' requiere 'yajl' gz = open('http://data.githubarchive.org/2012-03-11-12.json.gz') js = Zlib::GzipReader.new(gz).leer Yajl::Parser.parse(js) hacer |evento| fin del evento de impresión

contestado el 04 de mayo de 12 a las 19:05

El ejemplo no habilita ninguna de las funciones adicionales de Yajl, para lo que está buscando necesita habilitar allow_multiple_values marca en el analizador. Esto es lo que necesita modificar en el 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 de yajl, por lo que puede usar todas las funciones que proporciona Yajl. Aquí están todos los banderas que proporciona yajl que puedes habilitar:

yajl_allow_comments
yajl_dont_validate_strings
yajl_allow_trailing_garbage
yajl_allow_multiple_values
yajl_allow_partial_values

Para activarlos en yajl-py, haga 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()

Respondido el 06 de diciembre de 12 a las 19:12

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

Sé que esto ha sido respondido, pero prefiero el siguiente enfoque y no usa ningún paquete. El diccionario github está en una sola línea por alguna razón, por lo que no puede asumir un solo diccionario por línea. Esto parece:

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

Usé esta función para recorrer el archivo de 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 la publicación del conjunto de datos aquí: http://www.githubarchive.org/ (después de gunzip)

Respondido el 08 de junio de 14 a las 05:06

Su método se rompería en algún extremo equivocado. Intenta leer 2012-03-10-22.json.gzip, Comapre con este método: stackoverflow.com/questions/36967236/… - Frank Wang

Como solución alternativa, puede dividir los archivos de 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)
        ...

contestado el 31 de mayo de 13 a las 23:05

Solo hay una línea en los archivos de datos de 2012. - Frank Wang

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.