ValueErrors, ProtocolErrors и ChunkedEncodingErrors при использовании requests.get (). json () - PullRequest
1 голос
/ 25 мая 2020

Я работаю в Python над сбором данных (объем торгов, комиссии за майнинг и т. Д. c.) Из цепочки блоков Bitcoin. Для этого я пытаюсь JSON запрашивать различные страницы на blockchain.info.

После импорта json, запросов и urlopen я начинаю свой код с:

url = "https://blockchain.info/rawblock/00000000000000000000427c2cbfd8868c5bc987603d2483c9637f052316f89f?"
currentblock = requests.get(url, stream = True).json()
prevhash = str(currentblock['prev_block'])

Я выбираю запускать свой код с самого последнего блока (все, что после / rawblock / в URL-адресе - это идентификатор блока), а затем из вывода requests.get(url, stream=True).json() я получаю идентификатор предыдущего блока в цепочке (чтобы затем запросите в следующем цикле / цикле).

I go в for-l oop, где я повторяю процесс сбора информации из каждого блока, получения идентификатора предыдущего блока, а затем продолжая запрашивать в обратном порядке таким образом:

prevhash = str(currentblock['prev_block'])
for num in range(0,2700):
    currenthash = prevhash
    url = "https://blockchain.info/rawblock/" + currenthash + "?"
    print(currenthash)
    try:
        currentblock = requests.get(url, stream = True).json()
    except ValueError:
        print(hashnum)
        print("Response content is not JSON")
    prevhash = currentblock['prev_block']

Причина, по которой я установил попытку, кроме последовательности, состоит в том, что через кажущиеся случайными интервалами я получаю сообщение об ошибке, которое остановит мою программу, которая сказала что-то ответ от requests.get() не JSON. Я обнаружил, что если я просто поймаю эту ошибку, программа снова и снова запрашивает веб-страницу, при второй попытке все работает нормально, и программа продолжает работать.

Однако я только что столкнулся с тем, что выглядит как неприятная цепочка ошибок, и, честно говоря, я понятия не имею, что они означают и как их исправить.

Вот трассировка (с удаленными промежуточными шагами):

Traceback (most recent call last):
  File "C:\Users\Vlad\Desktop\lib\site-packages\urllib3\response.py", line 685, in _update_chunk_length
    self.chunk_left = int(line, 16)
ValueError: invalid literal for int() with base 16: b''

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...
  File "C:\Users\Vlad\Desktop\lib\site-packages\urllib3\response.py", line 689, in _update_chunk_length
    raise httplib.IncompleteRead(line)
http.client.IncompleteRead: IncompleteRead(0 bytes read)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...
  File "C:\Users\Vlad\Desktop\lib\site-packages\urllib3\response.py", line 443, in _error_catcher
    raise ProtocolError("Connection broken: %r" % e, e)
urllib3.exceptions.ProtocolError: ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...
  File "C:\Users\Vlad\Desktop\lib\site-packages\requests\models.py", line 753, in generate
    raise ChunkedEncodingError(e)
requests.exceptions.ChunkedEncodingError: ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))

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

Из любопытства я перезапустил свою программу в точке цепочки прямо перед тем, как произошла указанная выше ошибка - и на этот раз ошибки не было. Он просто продолжал работать без проблем.

Любая помощь была бы чрезвычайно признательна, и, пожалуйста, дайте мне знать, если я смогу более подробно объяснить, что я делаю!

Спасибо

1 Ответ

1 голос
/ 26 мая 2020

Используйте пакет повтора, чтобы повторить запросы, которые завершились ошибкой из-за сетевых ошибок.

import requests
from retry import retry


@retry(exceptions=Exception, tries=5, delay=1)
def get_currentblock(url):
    return requests.get(url)


url = "https://blockchain.info/rawblock/00000000000000000000427c2cbfd8868c5bc987603d2483c9637f052316f89f"
currentblock = get_currentblock(url).json()
prevhash = str(currentblock['prev_block'])
for num in range(0,2700):
    currenthash = prevhash
    url = "https://blockchain.info/rawblock/" + currenthash
    print(currenthash)
    try:
        currentblock = get_currentblock(url).json()
    except ValueError:
        print(hashnum)
        print("Response content is not JSON")
    prevhash = currentblock['prev_block']

Это повторит попытку get() до пяти раз с задержкой в ​​одну секунду для любого Exception. Вы можете захотеть изменить exceptions=Exception на более строгие, так как вы лучше понимаете, с какими исключениями вы можете столкнуться. Метод get_currentblock() просто возвращает ответ, а не компонент JSON, чтобы избежать запуска повторной попытки при ошибке синтаксического анализа JSON, то есть мы только wi sh, чтобы повторить попытку при возникновении сетевой ошибки.

Также обратите внимание, что stream=True был удален из вызова get(), потому что он не имеет никакого эффекта в сочетании с вызовом json(), так как весь ответ должен быть получен перед попыткой синтаксического анализа содержимого как объекта JSON. Запросы потоковой передачи используются для получения итератора по содержимому ответа, чтобы обрабатывать каждую строку по мере ее поступления, но здесь он используется не так.

Наконец, я удалил ? из конца URL. ? обозначает следующие параметры запроса, но не является необходимым, поскольку параметры запроса отсутствуют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...