Python запрашивает случайные разрывы с JSONDecodeError - PullRequest
0 голосов
/ 25 сентября 2018

Я часами отлаживал, почему мой код случайно разрывается с этой ошибкой: JSONDecodeError: Expecting value: line 1 column 1 (char 0)

У меня есть такой код:

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)

И я отлаживал с помощьюпечать requests.get(url) и requests.get(url).text, и я столкнулся со следующими «особыми» случаями:

  1. requests.get(url) возвращает успешный ответ 200, а requests.get(url).text возвращает HTML.Я читал в Интернете, что это не должно работать при использовании requests.get(url).json(), потому что он не сможет читать html, но как-то не сломается.Почему это так?

  2. requests.get(url) возвращает успешный ответ 200, а requests.get(url).text в формате json.Я не понимаю, почему, когда он переходит к строке requests.get(url).json(), он разрывается с JSONDecodeError?

Точное значение requests.get(url).text для случая 2:

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

1 Ответ

0 голосов
/ 25 сентября 2018

Глядя на документацию для этого API, кажется, что единственные ответы представлены в формате JSON, поэтому получение HTML странно.Чтобы повысить вероятность получения ответа JSON, вы можете установить для заголовка «Accept» значение «application / json».

Я много раз пытался запросить этот API с параметрами и не обнаружил JSONDecodeError.Эта ошибка, вероятно, является результатом другой ошибки на стороне сервера.Чтобы справиться с этим, except a json.decoder.JSONDecodeError в дополнение к ошибке ConnectionError вы в настоящее время except и обрабатываете эту ошибку так же, как ConnectionError.

Вот пример со всемиэто имеет в виду:

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']

Я также обернул эту логику в рекурсивную функцию, вместо того, чтобы использовать цикл while, потому что я думаю, что это семантически понятнее.Эта функция также ожидает перед повторной попыткой использования экспоненциального отката (ожидание вдвое дольше после каждого сбоя).

Редактировать: Для Python 2.7 ошибка при попытке анализа плохого json составляет ValueError, а не 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']

, поэтому просто измените эту строку except, чтобы включить ValueError вместо json.decoder.JSONDecodeError.

...