JSONArray et liste python : comment manipuler ces deux types

Lou_2044 Messages postés 11 Statut Membre -  
 toyo -

Bonjour,

J'ai écrit un script python qui permet de récupérer et transférer des données au format JSON.

Pour étudier mon problème, je vais partager uniquement deux de mes fonctions.

La première :

def create_cts(nwd, idd):

    headers = {
        'Authorization': 'Bearer xxx',
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json;charset=utf-8',
    }

    obs = search_obs(idd)

    # we check that the obs are not empty
    if obs != "[]":

        # removal of unwanted chevrons at the beginning and end
        json_data = obs[1:-1]
        obj_python = json.loads(json_data)

        response = requests.post(f'http://xxx/api/case/{nwd}/artifact', headers=headers, json=obj_python)

        if response.status_code != 201 and response.status_code != 200:
            print('ko: {}/{}'.format(response.status_code, response.text))
            sys.exit(0)

Elle permet d'envoyer des données à un serveur, au format json.

Les deux paramètres sont des entiers qui aident à gérer les types de données concernées.

La fonction fait appel à celle-ci :

def search_obs(cid):
    # Call the API
    response = api_i.get_case_obs(caseId, query={}, sort=['-stte', '+ioc'], range='all')

    if response.status_code == 200 or response.status_code == 201:
        # Get response data
        list = json.dumps(response.json())
        return list
    else:
        print('Failure: {}/{}'.format(response.status_code, response.text))

Elle prend en paramètre un entier et retourne une liste contenant les données au format JSONArray.

Cependant, elle retourne un str et non JSONArray.

Dans le cas où la liste récupérée est dans ce format :

[
 {
  "_id": "~81940632", 
  "id": "~81940632", 
  "createdBy": "xxxxx", 
  "createdAt": 1672847636169, 
  "_type": "case_artifact", 
  "dataType": "ip", 
  "data": "xxxxxxxx", 
  "startDate": 1672847636169, 
  "tlp": 2, 
  "tags": ["ip"], 
  "ioc": false, 
  "sighted": false, 
  "message": "nonne", 
  "reports": {}, 
  "stats": {}, 
  "ignoreSimilarity": false
 }
]

Cela fonctionne sans erreur, par contre, lorsqu'il y a plusieurs objets JSON, comme ceci :

[
 {"_id": "~81940632", 
  "id": "~81940632", 
  "createdBy": "xxxx", 
  "createdAt": 1672847636169, 
  "_type": "case_artifact", 
  "dataType": "ip", 
  "data": "xxxx", 
  "startDate": 1672847636169, 
  "tlp": 2, 
  "tags": ["ip"], 
  "ioc": false, 
  "sighted": false, 
  "message": "nonne", 
  "reports": {}, 
  "stats": {}, 
  "ignoreSimilarity": false}, 
 {
  "_id": "~196840", 
  "id": "~196840", 
  "createdBy": "xxxx", 
  "updatedBy": "xxxxx", 
  "createdAt": 1672741863059, 
  "updatedAt": 1672843716872, 
  "_type": "case_artifact", 
  "dataType": "domain", 
  "data": "***@***", 
  "startDate": 1672741863059, 
  "tlp": 2, 
  "tags": ["domai"], 
  "ioc": true, 
  "sighted": false, 
  "message": "", 
  "reports": {}, 
  "stats": {}, 
  "ignoreSimilarity": false
 }
]

Voici l'erreur :

json.decoder.JSONDecodeError: Extra data: line 1 column 332 (char 331)

J'ai cherché un peu comment faire, l'idée serait de faire un "for" sur le JSONArray mais le problème c'est que je récupère toujours la liste en "str" ou en liste (après modification du code).

J'ai aussi essayé de retourner directement le "json.dumps" pour avoir le type JSON, mais cela ne fonctionne pas.

A voir également:

3 réponses

toyo
 

Bonsoir, ce qui est étonnant dans ton json est qu'il y a des true et false, et à mon avis c'est ce qui fait que ça foire, en python c'est True et non true qui devrait alors être un string et donc devrait être quoté, enfin je vois que ça, tente de remplacer true par True, idem pour false.

Et si ça foire encore, essaie ce qui indiqué dans ce post :

https://stackoverflow.com/questions/48140858/json-decoder-jsondecodeerror-extra-data-line-2-column-1-char-190#answer-64515116

0
Lou_2044 Messages postés 11 Statut Membre
 

Merci pour ton aide, cependant, en remplaçant les "False" et "True" j'ai toujours la même erreur. Apparemment (d'après internet), l'erreur provient du fait que j'ai plusieurs objets dans le JSON, c'est pour cela que j'ai parlé de l'idée d'utiliser un "for" pour pouvoir séparer ces objets.

0
Lou_2044 Messages postés 11 Statut Membre > Lou_2044 Messages postés 11 Statut Membre
 

Bon, si je remplace la variable "obs" par :

observables = '[{}, {}]'

Cela fonctionne, donc ce que j'ai dit plus haut ne fonctionne pas. Cela doit être autre chose qui bloc

0
Lou_2044 Messages postés 11 Statut Membre
 

Ok, en fait le problème c'est que je fais :

json_data = obs[1:-1]

Avant de faire json.loads, donc il ne comprend plus le JSON. Mais, le problème est que je suis obligée de supprimer ces crochets de début et de fin pour la requête, sinon il me créé une autre erreur.

Alors là je ne sais vraiment pas comment faire, car je reçois un JSON array du type [{},{}] que je mets dans un string et auquel je dois garder les crochets pour le "json.loads" mais ensuite les supprimer ... Cependant, une fois que je fais :

obj_python = json.loads(json_data)

Je ne peux plus supprimer les crochets, car cela devient une liste. (Ou alors je ne sais pas comment faire)

La requête POST, avec le paramètre JSON, doit ajouter automatiquement les crochets, c'est probablement pour ça que ça me créé une erreur. Je vais donc chercher comment envoyer des données brutes

0
toyo
 

Je n'arrive pas à reproduire ton bug, ni même ton problème avec ton json.

Un simple server lancé rapidos.
 

python3 -m http.server 8080

Puis dans un interpétreur, je récupère ton json.

guili@maman:~$ python3.7
Python 3.7.3 (default, Oct 31 2022, 14:04:00)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> import requests
>>> response = requests.get('http://localhost:8080/list.json')
>>> response.status_code
200
>>> type(response.json())
<class 'list'>
>>> json.dumps(response.json())
'[{"_id": "~81940632", "id": "~81940632", "createdBy": "xxxx", "createdAt": 1672847636169, "_type": "case_artifact", "dataType": "ip", "data": "xxxx", "startDate": 1672847636169, "tlp": 2, "tags": ["ip"], "ioc": false, "sighted": false, "message": "nonne", "reports": {}, "stats": {}, "ignoreSimilarity": false}, {"_id": "~196840", "id": "~196840", "createdBy": "xxxx", "updatedBy": "xxxxx", "createdAt": 1672741863059, "updatedAt": 1672843716872, "_type": "case_artifact", "dataType": "domain", "data": "***@***", "startDate": 1672741863059, "tlp": 2, "tags": ["domai"], "ioc": true, "sighted": false, "message": "", "reports": {}, "stats": {}, "ignoreSimilarity": false}]'
>>>
>>>
>>> type(response.text)
<class 'str'>
>>> json.loads(response.text)
[{'_id': '~81940632', 'id': '~81940632', 'createdBy': 'xxxx', 'createdAt': 1672847636169, '_type': 'case_artifact', 'dataType': 'ip', 'data': 'xxxx', 'startDate': 1672847636169, 'tlp': 2, 'tags': ['ip'], 'ioc': False, 'sighted': False, 'message': 'nonne', 'reports': {}, 'stats': {}, 'ignoreSimilarity': False}, {'_id': '~196840', 'id': '~196840', 'createdBy': 'xxxx', 'updatedBy': 'xxxxx', 'createdAt': 1672741863059, 'updatedAt': 1672843716872, '_type': 'case_artifact', 'dataType': 'domain', 'data': '***@***', 'startDate': 1672741863059, 'tlp': 2, 'tags': ['domai'], 'ioc': True, 'sighted': False, 'message': '', 'reports': {}, 'stats': {}, 'ignoreSimilarity': False}]
>>>


Donc, on constate bien avoir avec la méthode json de Response une liste, json.dumps sur response.json retourne bien un str, et comme prévu un json.loads de response.text retourne bien un json utilisable dans un code.

Mais est-ce bien le module requests que tu utilises ?
Que ce soit get ou post le retour sera identique, tu devrais quand même regarder les types des objets que tu manipules pour comprendre ce qui fait que ça déconne, où alors tenter de donner ici un exemple reproductible du problème.

Bonne chance.

0