0
votes

Comment réparer un fichier json éventuellement corrompu? Problèmes avec le caractère entre crochets "{" (Python3)

C'est un problème tellement étrange que je ne sais même pas comment poser, mais je vais essayer. J'ai quelques fichiers json qui contiennent des données Web scrape, plusieurs entrées par fichier et ils ressemblent à ceci:

    # Read the file
    f = codecs.open(file, 'r', encoding='utf-8-sig', errors='replace')
    text = f.read()
    f.close()

    # Check if }{ was found; 
    # this prints nothing for original files but finds everything in a hand written file
    pattern = '}{'
    print('Before editing: ', (re.findall(pattern, text)))

    # Getting rid of excess newlines and whitespaces
    newtext = " ".join(text.split())

    # Check if } { was found;
    # this prints nothing for original files but finds everything in a hand written file
    pattern = '} {'
    print('After editing: ', (re.findall(pattern, newtext)))

    # Put newlines in the right places
    finaltext = re.sub('} {', '}\n{', newtext)

    # Write the new JSON
    newfile = file[:-5]+'_ED.json'
    nf = codecs.open(newfile, 'w', encoding='utf-8', errors='replace')
    nf.write(finaltext)
    nf.close()

J'essayais de les formater pour que chaque entrée soit indépendante ligne, comme ceci:

{"doc_id": blah blah....} 
{"doc_id": blah blah blah...}

J'ai donc fait ceci:

{
"doc_id": "some_number",
"url": "www.seedurl1.com",
"scrape_date": "2019-10-22 16:17:22",
"publish_date": "unknown",
"author": "unknown",
"urls_out": [
"https://www.something.com",
"https://www.sometingelse.com/smth"
],
"text": "lots of text here"
}
{
"doc_id": "some_other_number",
"url": "www.seedurl2.com/smth",
"scrape_date": "2019-10-22 17:44:40",
"publish_date": "unknown",
"author": "unknown",
"urls_out": [
"www.anotherurl.com/smth",
"http://urlx.com/smth.htm"
],
"text": "lots more text over here."
}

Le fait est que le code fonctionne parfaitement sur un fichier de test écrit à la main avec la même structure, mais pas avec les fichiers originaux, ou les fichiers de test plus petits dérivés des originaux.

J'ai essayé de faire une recherche simple pour "}" et "{" séparément dans un éditeur de texte, ce qui s'avère correct. Mais si j'essaye de rechercher "} {" ou "} {", rien n'est trouvé. Bien que je puisse voir qu'ils sont clairement là.

Une dernière découverte: j'ai essayé d'ouvrir la version modifiée de mon petit fichier de test dans Nano sous Linux et je me suis déplacé sur la zone à problèmes. Pour une raison quelconque, il faut deux pressions sur la touche fléchée droite pour se déplacer sur le crochet "{". Il y a donc clairement quelque chose de bizarre là-dedans. Comment savoir quoi? Ou toute autre suggestion qui pourrait vous aider?


8 commentaires

Au lieu de donner le {ou}, pouvez-vous essayer de copier-coller le modèle directement à partir des données? Parfois, il y a des caractères non-utf-8 cachés à la vue de tous.


Pourquoi n'utilisez-vous pas la bibliothèque json de python? C'est beaucoup plus pratique pour les opérations et le débogage comme celui-ci.


@Saharsh Parce que le fichier n'est pas JSON valide?


est-ce que cela aide? pypi.org/project/json-lines


@ cricket_007 mon mauvais. Je ne savais pas que le fichier initial peut avoir la syntaxe définie par OP.


@Saharsh J'ai d'abord essayé de créer un dictionnaire à partir du fichier json avec la bibliothèque, mais cela n'a pas fonctionné.


@morko cela ne fonctionnera que si le fichier est un JSON valide et à partir de votre message, il semble qu'il y ait une possibilité que ce ne soit pas le cas (à cause de votre formatage personnalisé)


".. mais pas avec les fichiers originaux .." Pas comment ? Que se passe-t-il à la place? "Cela n'a pas fonctionné" peut être une description précise, mais cela ne nous aide pas.


3 Réponses :


0
votes

La solution la plus simple serait de créer un tableau JSON pour commencer ...

Sinon, je suggérerais de ne rien remplacer et de compter simplement les crochets correspondants.

{"doc_id": "some_number","url": "www.seedurl1.com","scrape_date": "2019-10-22 16:17:22","publish_date": "unknown","author": "unknown","urls_out": ["https://www.something.com","https://www.sometingelse.com/smth"],"text": "lots of text here"}
{"doc_id": "some_other_number","url": "www.seedurl2.com/smth","scrape_date": "2019-10-22 17:44:40","publish_date": "unknown","author": "unknown","urls_out": ["www.anotherurl.com/smth","http://urlx.com/smth.htm"],"text": "lots more text over here."}

found 2 objects

Pour le texte donné, je me suis retrouvé avec ceci

count = 0
objects = 0
with open('file.txt') as f:
    for i, c in enumerate(f.read()):
      if c == '\n':
        continue
      elif c == '{':
        if i > 0 and count == 0:
          print()  # start new line before printing bracket
        count += 1
      elif c == '}':
        count -= 1
        if count == 0:  # found a complete JSON object
          objects += 1

      print(c, end='')
    print(f'\n\nfound {objects} objects')  # for debugging 


2 commentaires

Cela fonctionnait même avec les fichiers problématiques! Merci beaucoup!


J'ai choisi celle-ci comme réponse acceptée car elle fonctionnait avant de découvrir quel était le problème avec mes fichiers. Après avoir découvert mon problème, la réponse de @Saharsh a également fonctionné et était plus simple (à mon avis).



0
votes

C'est une approche.

{'doc_id': 'some_number', 'url': 'www.seedurl1.com',.....
{'doc_id': 'some_other_number', 'url': 'www.seedurl2.com/smth',.....

Sortie:^

import json

with open(filename) as infile:
    data = json.loads("[" + infile.read().replace("}\n{", "},\n{") + "]")
    for i in data:
        print(i)

p>


0 commentaires

0
votes

Voici une autre solution qui est un peu proche de ce que vous tentiez de tenter

{'doc_id': 'some_number', 'url': 'www.seedurl1.com', 'scrape_date': '2019-10-22 16:17:22', 'publish_date': 'unknown', 'author': 'unknown', 'urls_out': ['https://www.something.com', 'https://www.sometingelse.com/smth'], 'text': 'lots of text here'}
{'doc_id': 'some_number', 'url': 'www.seedurl1.com', 'scrape_date': '2019-10-22 16:17:22', 'publish_date': 'unknown', 'author': 'unknown', 'urls_out': ['https://www.something.com', 'https://www.sometingelse.com/smth'], 'text': 'lots of text here'}

json est utilisé ici pour valider le JSON individuel uniquement. Cela donne

import json

with open('test.txt') as f:
    file = f.readlines()
file = ['{'+i+'}'for i in "".join("".join(file).split("\n"))[1:-1].split("}{")]

for i in file:
    print(json.loads(i))


3 commentaires

Oops. Besoin de gérer l'espace, je pense et nous devrions être d'accord. Laissez-moi travailler là-dessus. Merci @ cricket_007


Mise à jour de la réponse. J'ai complètement oublié d'ajouter \ n dans split () qui supprimait tous les espaces blancs.


J'ai essayé celui-ci et il s'est avéré très utile. Au début, il ne s'est pas divisé en "} {" mais après avoir imprimé le résultat, il m'a montré qu'il y avait un \ ufeff caché entre les accolades, donc split ("} \ ufeff {") a résolu le problème. Merci!