15 votes

les requêtes python s'interrompent aléatoirement avec JSONDecodeError

J'ai débogué pendant des heures pour savoir pourquoi mon code s'interrompt aléatoirement avec cette erreur : JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Voici le code que j'ai :

while True:
    try:
        submissions = requests.get('http://reymisterio.net/data-dump/api.php/submission?filter[]=form,cs,'+client+'&filter[]=date,cs,'+since).json()['submission']['records']
        break
    except requests.exceptions.ConnectionError:
        time.sleep(100)

Et j'ai débogué en imprimant requests.get(url) y requests.get(url).text et j'ai rencontré les cas "particuliers" suivants :

  1. requests.get(url) renvoie une réponse 200 réussie et requests.get(url).text renvoie du html. J'ai lu en ligne que cela devrait échouer lorsque l'on utilise requests.get(url).json() Il n'y a pas de problème, car il ne pourra pas lire le code html, mais il n'y a pas de problème. Comment cela se fait-il ?

  2. requests.get(url) renvoie une réponse 200 réussie et requests.get(url).text est au format json. Je ne comprends pas pourquoi, lorsqu'il passe à l'adresse requests.get(url).json() la ligne est interrompue par l'erreur JSONDecodeError ?

La valeur exacte de requests.get(url).text pour le cas 2 est :

{
  "submission": {
    "columns": [
      "pk",
      "form",
      "date",
      "ip"
    ],
    "records": [
      [
        "21197",
        "mistico-form-contacto-form",
        "2018-09-21 09:04:41",
        "186.179.71.106"
      ]
    ]
  }
}

11voto

Henry Woody Points 6546

En regardant le documentation pour cette API, il semble que les seules réponses soient au format JSON, recevoir du HTML est donc étrange. Pour augmenter la probabilité de recevoir une réponse JSON, vous pouvez définir l'en-tête 'Accept' sur 'application/json'.

J'ai essayé d'interroger cette API plusieurs fois avec des paramètres et je n'ai pas rencontré d'erreur. JSONDecodeError . Cette erreur est probablement le résultat d'une autre erreur du côté du serveur. Pour la traiter, except a json.decoder.JSONDecodeError en plus de la ConnectionError l'erreur que vous commettez actuellement except et traiter cette erreur de la même manière que l'option ConnectionError .

Voici un exemple avec tout cela en tête :

import requests, json, time, random

def get_submission_records(client, since, try_number=1):
    url = 'http://reymisterio.net/data-dump/api.php/submission?filter[]=form,cs,'+client+'&filter[]=date,cs,'+since
    headers = {'Accept': 'application/json'}
    try:
        response = requests.get(url, headers=headers).json()
    except (requests.exceptions.ConnectionError, json.decoder.JSONDecodeError):
        time.sleep(2**try_number + random.random()*0.01) #exponential backoff
        return get_submission_records(client, since, try_number=try_number+1)
    else:
        return response['submission']['records']

J'ai également intégré cette logique dans une fonction récursive, plutôt que d'utiliser la fonction while boucle parce que je pense que c'est sémantiquement plus clair. Cette fonction attend également avant de réessayer en utilisant le backoff exponentiel (attendre deux fois plus longtemps après chaque échec).

Edita: Pour Python 2.7, l'erreur due à l'analyse d'un mauvais json est une erreur de type ValueError et non un JSONDecodeError

import requests, time, random

def get_submission_records(client, since, try_number=1):
    url = 'http://reymisterio.net/data-dump/api.php/submission?filter[]=form,cs,'+client+'&filter[]=date,cs,'+since
    headers = {'Accept': 'application/json'}
    try:
        response = requests.get(url, headers=headers).json()
    except (requests.exceptions.ConnectionError, ValueError):
        time.sleep(2**try_number + random.random()*0.01) #exponential backoff
        return get_submission_records(client, since, try_number=try_number+1)
    else:
        return response['submission']['records']

donc changez juste ça except pour inclure un ValueError au lieu de json.decoder.JSONDecodeError .

-1voto

Essayez ceci. Cela pourrait fonctionner

while True:
        try:
            submissions = requests.get('http://reymisterio.net/data-dump/api.php/submission?filter[]=form,cs,'+client+'&filter[]=date,cs,'+since).json()['submission']['records']
            sub = json.loads(submissions.text)
            print(sub)
            break
        except requests.exceptions.ConnectionError:
            time.sleep(100)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X