OK, po prawie tygodniu badań, dam tak strzał. Mam plik tekstowy, który wygląda następująco (pokazując 3 oddzielne obiekty JSON jako przykład, ale plik ma 50 tys.):

{
"zipcode":"00544",
"current":{"canwc":null,"cig":7000,"class":"observation"},
"triggers":[178,30,176,103,179,112,21,20,48,7,50,40,57]
}
{
"zipcode":"00601",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[12,23,34,28,100]
}
{
"zipcode":"00602",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[13,85,43,101,38,31]
}

Wiem, jak pracować z JSON obiektami za pomocą biblioteki Pythona JSON, ale mam wyzwanie, jak stworzyć 50 tysięcy różnych obiektów JSON od czytania pliku. (Być może nawet nie myślę o tym prawidłowo, ale ostatecznie muszę się dedykować i załadować do bazy danych), próbowałem ITERTools myśląc, że potrzebuję generatora, więc udało mi się użyć:

with open(file) as f:
    for line in itertools.islice(f, 0, 7): #since every 7 lines is a json object
        jfile = json.load(line)

Ale powyższe oczywiście nie będzie działać, ponieważ nie czytanie 7 linii jako pojedynczego obiektu JSON i nie jestem również pewien, jak następnie iteruje na całym pliku i ładować indywidualne obiekty JSON.

Poniżej przedstawiłoby mi listę, którą mogę pokroić:

list(open(file))[:7]

Każda pomoc byłaby naprawdę doceniona.


Zbliża się do tego, czego potrzebuję i myślę, że dosłownie jeden krok, ale wciąż walczył z iteracją. To wreszcie dostarczy mi iteracyjny wydruk wszystkich danych danych, ale jak mogę to zrobić, abyśmy mogli uchwycić jeden Giant Dataframe ze wszystkimi elementami zasadniczo skoncentratami? Wtedy mogłem wyeksportować tę ostateczną dataframe do CSV itp. (Czy jest również lepszy sposób na przesłanie tego wyniku do bazy danych, a nie tworzenie gigantycznej dataframe?)

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))

def flatten(jfile):
    for k, v in jfile.items():
        if isinstance(v, list):
            jfile[k] = ','.join(v)
        elif isinstance(v, dict):
            for kk, vv in v.items():
                jfile['%s' % (kk)] = vv
            del jfile[k]
            return jfile

with open('deadzips.json') as f:
    for chunk in lines_per_n(f, 7):
        try:
            jfile = json.loads(chunk)
            pd.DataFrame(flatten(jfile).items())
        except ValueError, e:
            pass
        else:
            pass
24
horatio1701d 5 grudzień 2013, 17:05

2 odpowiedzi

Najlepsza odpowiedź

Zamiast tego załaduj 6 dodatkowych wierszy i przekaż string do json.loads():

with open(file) as f:
    for line in f:
        # slice the next 6 lines from the iterable, as a list.
        lines = [line] + list(itertools.islice(f, 6))
        jfile = json.loads(''.join(lines))

        # do something with jfile

json.load() Slurp więcej niż tylko następny obiekt w pliku, a {x1}} odczytuje tylko pierwsze 7 linii, zamiast przeczytać plik w blokach 7-line.

Możesz owinąć do czytania pliku w blokach wielkości n w generatorze:

from itertools import islice, chain

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))

Następnie użyj tego, aby poradzić się z plikiem wejściowym:

with open(file) as f:
    for chunk in lines_per_n(f, 7):
        jfile = json.loads(chunk)

        # do something with jfile

Alternatywnie, jeśli bloki okazują się zmiennej długości, czytaj, aż masz coś, co analizuje:

with open(file) as f:
    for line in f:
        while True:
            try:
                jfile = json.loads(line)
                break
            except ValueError:
                # Not yet a complete JSON value
                line += next(f)

        # do something with jfile
24
Martijn Pieters 5 grudzień 2013, 15:34

Jak stwierdził gdzie indziej, ogólne rozwiązanie jest czytanie pliku w kawałkach, dołącz każdy kawałek do ostatniego i spróbuj przeanalizować ten nowy kawałek. Jeśli nie anarynisz, kontynuuj, aż dostaniesz coś, co robi. Gdy masz coś, co analizuje, zwróć go i uruchom ponownie proces. Rinse-Lather-Powtórz, aż zabraknie danych.

Oto zwięzły generator, który to zrobi:

def load_json_multiple(segments):
    chunk = ""
    for segment in segments:
        chunk += segment
        try:
            yield json.loads(chunk)
            chunk = ""
        except ValueError:
            pass

Użyj tego w ten sposób:

with open('foo.json') as f:
   for parsed_json in load_json_multiple(f):
      print parsed_json

Mam nadzieję, że to pomoże.

9
Jeff Younker 14 lipiec 2016, 12:07