Python json.loads wyświetla ValueError: Extra data

151

Pobieram dane z pliku JSON „new.json” i chcę przefiltrować niektóre dane i zapisać je w nowym pliku JSON. Oto mój kod:

import json
with open('new.json') as infile:
    data = json.load(infile)
for item in data:
    iden = item.get["id"]
    a = item.get["a"]
    b = item.get["b"]
    c = item.get["c"]
    if c == 'XYZ' or  "XYZ" in data["text"]:
        filename = 'abc.json'
    try:
        outfile = open(filename,'ab')
    except:
        outfile = open(filename,'wb')
    obj_json={}
    obj_json["ID"] = iden
    obj_json["VAL_A"] = a
    obj_json["VAL_B"] = b

i otrzymuję błąd, śledzenie to:

  File "rtfav.py", line 3, in <module>
    data = json.load(infile)
  File "/usr/lib64/python2.7/json/__init__.py", line 278, in load
    **kw)
  File "/usr/lib64/python2.7/json/__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "/usr/lib64/python2.7/json/decoder.py", line 369, in decode
    raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 88 column 2 - line 50607 column 2 (char 3077 - 1868399)

Czy ktoś może mi pomóc?

Oto próbka danych w new.json, w pliku jest około 1500 innych takich słowników

{
    "contributors": null, 
    "truncated": false, 
    "text": "@HomeShop18 #DreamJob to professional rafter", 
    "in_reply_to_status_id": null, 
    "id": 421584490452893696, 
    "favorite_count": 0, 
    "source": "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Mobile Web (M2)</a>", 
    "retweeted": false, 
    "coordinates": null, 
    "entities": {
        "symbols": [], 
        "user_mentions": [
            {
                "id": 183093247, 
                "indices": [
                    0, 
                    11
                ], 
                "id_str": "183093247", 
                "screen_name": "HomeShop18", 
                "name": "HomeShop18"
            }
        ], 
        "hashtags": [
            {
                "indices": [
                    12, 
                    21
                ], 
                "text": "DreamJob"
            }
        ], 
        "urls": []
    }, 
    "in_reply_to_screen_name": "HomeShop18", 
    "id_str": "421584490452893696", 
    "retweet_count": 0, 
    "in_reply_to_user_id": 183093247, 
    "favorited": false, 
    "user": {
        "follow_request_sent": null, 
        "profile_use_background_image": true, 
        "default_profile_image": false, 
        "id": 2254546045, 
        "verified": false, 
        "profile_image_url_https": "https://pbs.twimg.com/profile_images/413952088880594944/rcdr59OY_normal.jpeg", 
        "profile_sidebar_fill_color": "171106", 
        "profile_text_color": "8A7302", 
        "followers_count": 87, 
        "profile_sidebar_border_color": "BCB302", 
        "id_str": "2254546045", 
        "profile_background_color": "0F0A02", 
        "listed_count": 1, 
        "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 
        "utc_offset": null, 
        "statuses_count": 9793, 
        "description": "Rafter. Rafting is what I do. Me aur mera Tablet.  Technocrat of Future", 
        "friends_count": 231, 
        "location": "", 
        "profile_link_color": "473623", 
        "profile_image_url": "http://pbs.twimg.com/profile_images/413952088880594944/rcdr59OY_normal.jpeg", 
        "following": null, 
        "geo_enabled": false, 
        "profile_banner_url": "https://pbs.twimg.com/profile_banners/2254546045/1388065343", 
        "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 
        "name": "Jayy", 
        "lang": "en", 
        "profile_background_tile": false, 
        "favourites_count": 41, 
        "screen_name": "JzayyPsingh", 
        "notifications": null, 
        "url": null, 
        "created_at": "Fri Dec 20 05:46:00 +0000 2013", 
        "contributors_enabled": false, 
        "time_zone": null, 
        "protected": false, 
        "default_profile": false, 
        "is_translator": false
    }, 
    "geo": null, 
    "in_reply_to_user_id_str": "183093247", 
    "lang": "en", 
    "created_at": "Fri Jan 10 10:09:09 +0000 2014", 
    "filter_level": "medium", 
    "in_reply_to_status_id_str": null, 
    "place": null
} 
Apoorv Ashutosh
źródło
Jest to błąd, który pojawia się, gdy wejściowy kod JSON ma więcej niż jeden obiekt w wierszu. Wiele odpowiedzi tutaj zakłada, że ​​w wierszu jest tylko jeden obiekt lub konstruuje przykłady, które są zgodne z tym, ale by się zepsuły, gdyby tak nie było.
smci
@smci: Czy możesz wyjaśnić tę kwestięmore than one object per line
aspirująca 1

Odpowiedzi:

150

Jak widać w poniższym przykładzie, json.loads(i json.load) nie dekoduje wielu obiektów json.

>>> json.loads('{}')
{}
>>> json.loads('{}{}') # == json.loads(json.dumps({}) + json.dumps({}))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\json\__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "C:\Python27\lib\json\decoder.py", line 368, in decode
    raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 1 column 3 - line 1 column 5 (char 2 - 4)

Jeśli chcesz zrzucić wiele słowników, zawiń je w listę, zrzuć listę (zamiast wielokrotnego zrzucania słowników)

>>> dict1 = {}
>>> dict2 = {}
>>> json.dumps([dict1, dict2])
'[{}, {}]'
>>> json.loads(json.dumps([dict1, dict2]))
[{}, {}]
falsetru
źródło
7
Czy możesz wyjaśnić ponownie, odwołując się do kodu, który podałem powyżej? Jestem nowicjuszem i czasami potrzebuję dużo czasu, zanim pojąłem takie rzeczy.
Apoorv Ashutosh
1
@ApoorvAshutosh, Wygląda na to, że new.jsonzawiera plik json i inne nadmiarowe dane. json.load, json.loadsmoże tylko zdekodować plik json. Podnosi a, ValueErrorgdy napotka dodatkowe dane, jak widzisz.
falsetru
Wkleiłem próbkę z new.json i odfiltrowuję z niego niektóre dane, więc nie rozumiem, skąd otrzymuję dodatkowe dane
Apoorv Ashutosh
1
@ApoorvAshutosh, W redagowanym pytaniu powiedziałeś o 1500 takich słownikach więcej . To są dodatkowe dane. Jeśli jesteś tym, który stworzył plik new.json, po prostu umieść pojedynczy plik json w pliku.
falsetru
1
@ApoorvAshutosh, Jeśli chcesz zrzucić wiele słowników jako json, zawiń je w listę i zrzuć listę.
falsetru
100

Możesz po prostu czytać z pliku, jsonifyingkażdą linię w trakcie:

tweets = []
for line in open('tweets.json', 'r'):
    tweets.append(json.loads(line))

Pozwala to uniknąć przechowywania pośrednich obiektów Pythona. Dopóki piszesz jeden pełny tweet na append()połączenie, powinno to działać.

Adam Hughes
źródło
7
Zaakceptowana odpowiedź dotyczy tego, jak naprawić źródło problemu, jeśli kontrolujesz proces eksportowania, ale jeśli używasz danych innych osób i po prostu musisz sobie z tym poradzić, jest to świetna metoda niskiego narzutu.
charlesreid 1
3
Wiele zbiorów danych (np. Zbiór danych Yelp) jest obecnie dostarczanych jako „zestaw” obiektów Json, a Twoim podejściem jest wygodne ładowanie ich.
Gabrer
36

Natknąłem się na to, ponieważ próbowałem załadować plik JSON zrzucony z MongoDB. Dało mi to błąd

JSONDecodeError: Extra data: line 2 column 1

Zrzut MongoDB JSON ma jeden obiekt w każdym wierszu, więc zadziałało dla mnie:

import json
data = [json.loads(line) for line in open('data.json', 'r')]
Nic Scozzaro
źródło
13

Może się to również zdarzyć, jeśli plik JSON nie jest tylko jednym rekordem JSON. Rekord JSON wygląda następująco:

[{"some data": value, "next key": "another value"}]

Otwiera się i zamyka nawiasem [], w nawiasach są nawiasy {}. Może być wiele par nawiasów, ale wszystko kończy się nawiasem zamykającym]. Jeśli plik json zawiera więcej niż jeden z nich:

[{"some data": value, "next key": "another value"}]
[{"2nd record data": value, "2nd record key": "another value"}]

wtedy load () nie powiedzie się.

Sprawdziłem to na moim własnym pliku, który się nie udał.

import json

guestFile = open("1_guests.json",'r')
guestData = guestFile.read()
guestFile.close()
gdfJson = json.loads(guestData)

To działa, ponieważ 1_guests.json ma jeden rekord []. Oryginalny plik all_guests.json, którego używałem, miał 6 rekordów oddzielonych znakiem nowej linii. Usunąłem 5 rekordów (które już sprawdziłem, aby były zaksięgowane w nawiasach) i zapisałem plik pod nową nazwą. Następnie instrukcja obciążenia zadziałała.

Błąd był

   raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 2 column 1 - line 10 column 1 (char 261900 - 6964758)

PS. Używam słowa rekord, ale to nie jest oficjalna nazwa. Ponadto, jeśli twój plik zawiera znaki nowej linii, takie jak mój, możesz zapętlić go, aby załadować () jeden rekord na raz do zmiennej JSON.

VISQL
źródło
2
Czy istnieje sposób na json.loadsodczytanie fragmentów JSON rozdzielonych znakami nowej linii? To znaczy zachowywać się jak [json.loads(x) for x in text.split('\n')]? Powiązane: Czy istnieje gwarancja, json.dumpsktóra nie uwzględni dosłownych znaków nowej linii w wynikach z domyślnymi wcięciami?
Ben
1
@Ben, domyślnie json.dumpszmieni znaki nowej linii w treści tekstowej na "\n", zachowując json do jednej linii.
jchook
7

Cóż, może to komuś pomóc. właśnie otrzymałem ten sam błąd, podczas gdy mój plik json jest taki

{"id":"1101010","city_id":"1101","name":"TEUPAH SELATAN"}
{"id":"1101020","city_id":"1101","name":"SIMEULUE TIMUR"}

i stwierdziłem, że jest źle sformułowany, więc zmieniłem go na coś w rodzaju

{
  "datas":[
    {"id":"1101010","city_id":"1101","name":"TEUPAH SELATAN"},
    {"id":"1101020","city_id":"1101","name":"SIMEULUE TIMUR"}
  ]
}
Akbar Noto
źródło
1
ładowanie tak samo jak twoje, json.load (infile)
Akbar Noto
6

Jedna linijka dla twojego problemu:

data = [json.loads(line) for line in open('tweets.json', 'r')]
Nihal
źródło
1
Nie jest to rozwiązanie ogólne, zakłada się, że dane wejściowe mają jeden obiekt JSON w każdym wierszu i nie działają.
smci
3

Jeśli chcesz rozwiązać to w dwuwierszowym, możesz to zrobić w ten sposób:

with open('data.json') as f:
    data = [json.loads(line) for line in f]
coreehi
źródło
1

Myślę, że zapisywanie dykt na liście nie jest idealnym rozwiązaniem proponowanym przez @falsetru.

Lepszym sposobem jest iterowanie przez dykty i zapisywanie ich w .json przez dodanie nowej linii.

nasze 2 słowniki to

d1 = {'a':1}

d2 = {'b':2}

możesz napisać je do .json

import json
with open('sample.json','a') as sample:
    for dict in [d1,d2]:
        sample.write('{}\n'.format(json.dumps(dict)))

i możesz czytać plik json bez żadnych problemów

with open('sample.json','r') as sample:
    for line in sample:
        line = json.loads(line.strip())

proste i wydajne

murat yalçın
źródło
Nie jest to rozwiązanie ogólne, zakłada się, że dane wejściowe mają jeden obiekt JSON w każdym wierszu i nie działają.
smci