Выйдите за рамки основ пакета запросов в python

Узнайте, как использовать индикаторы выполнения, возобновлять частично загруженные файлы и проверять файлы в Python

Когда вы привыкнете к пакету python запросов, в приложениях командной строки может оказаться полезным рассмотреть способы проверки файлов, возобновления неполных запросов на получение и использования индикаторов выполнения. Они выходят за рамки базового использования пакета запросов. Мы рассмотрим простые способы сделать это с помощью пакета запроса.

В этой статье вы узнаете

  1. Как подойти к возобновлению загрузки неполных двоичных файлов
  2. Как создать простой валидатор загрузки для передачи файлов / резервного копирования данных.
  3. Как отобразить простой индикатор выполнения в командной строке.

Возобновление загрузок

При загрузке больших файлов они могут прерываться по разным причинам. Иногда нам нужен способ возобновить работу с последнего байта, чтобы восстановить соединение.

В рамках HTTP-запроса на получение от сервера мы получим заголовок и тело данных. Заголовки HTTP для двоичных файлов дают много информации о файле, который мы запрашиваем! Одна из частей, которую мы иногда получаем в зависимости от сервера, на который делается запрос, - это заголовок accept-ranges. Это позволяет клиенту загружать частично загруженные данные.

Ниже приведен пример заголовков двоичного файла, допускающего частичную загрузку файлов.

{'Server': 'VK', 
'Date': 'Wed, 29 Jan 2020 11:47:20 GMT', 
'Content-Type': 'application/pdf', 
'Content-Length': '9713036', 
'Connection': 'keep-alive', 
'Last-Modified': 'Mon, 20 Jan 2020 13:01:17 GMT', 
'ETag': '"5e25a49d-94358c"', 
'Accept-Ranges': 'bytes', 
'Expires': 'Wed, 05 Feb 2020 11:47:20 GMT', 
'Cache-Control': 'max-age=604800', 
'X-Frontend': 'front632904', 
'Access-Control-Expose-Headers': 'X-Frontend',
 'Access-Control-Allow-Methods': 'GET, HEAD, OPTIONS',
 'Access-Control-Allow-Origin': '*', 
'Strict-Transport-Security': 'max-age=15768000'}

С помощью этой возможности мы также можем указать серверу местоположение в файле, из которого мы запрашиваем загрузку. Затем мы можем начать запросы двоичных данных в этой конкретной позиции и загрузить оттуда в дальнейшем.

Теперь, чтобы загрузить небольшую часть двоичного файла, мы должны иметь возможность отправлять заголовки с помощью HTTP-метода запроса. Пакет запросов позволяет нам легко это сделать. Мы хотим получить только определенное количество байтов, мы делаем это, отправляя заголовок range, чтобы указать, сколько байтов нужно получить. Затем мы можем поместить это в переменную и передать это через запрос на получение.

resume_headers = {'Range':'bytes=0-2000000'}
r = request.get(url, stream=True, headers=resume_header)
with open('filename.zip','wb') as f:
  for chunk in r.iter_content(chunk-size=1024)
      f.write(chunk)

Примечания

1. Мы указываем stream = True в методе получения запроса. Это позволяет нам контролировать, когда загружается тело двоичного ответа.

2. Мы используем аргумент заголовков в методе requests.get() для определения позиции байта от 0 до 2000000. Границы заголовка диапазона указаны включительно. Это означает, что будут загружены позиции байта от 0 до 2000000.

4. Мы используем оператор with для записи файла filename.zip. r.iter_content method позволяет нам указать размер данных для загрузки, определяя chunk-size в байтах. В данном случае это 1024 байта.

Мы скачали часть файла. Как это помогает нашей реальной цели возобновить частично загруженный файл?

Когда мы хотим возобновить частично загруженный файл, мы указываем размер файла в заголовках. Это следующий байт, который необходимо загрузить. В этом суть возможности возобновления загрузки в Python.

Нам нужно знать размер частично загруженного файла. Для этого в python есть ряд пакетов, и pathlib - отличный пакет для этого варианта использования. Пожалуйста, смотрите здесь для получения инструкций по использованию pathlib.

Сначала мы импортируем пакет pathlib.

import pathlib

Метод path.stat() возвращает информацию о пути (аналогично os.stat, если вы знакомы с пакетом os). Теперь мы вызываем атрибут st_size метода path.stat(), чтобы получить размер файла (также аналогично пакету ОС).

Теперь мы готовы использовать это

resume_header = {'Range':f'bytes= {path('filename.zip').stat().st_size}-'}

Теперь это нужно распаковать. Символ f перед строкой является f-строкой, это отличный способ форматировать строки. В качестве варианта использования {path.stat().st_size} в фигурных скобках является выражением. Создаваемая нами строка изменяется значением этого выражения в фигурных скобках. Это может быть переменная, но в этом случае мы получаем размер частично загруженного файла. F-строка интерпретирует все, что находится внутри {}, а затем отображает результат в виде строки. В этом случае он печатает нам файл.

Дефис, выделенный полужирным шрифтом после {path.stat().st_size} в строке, означает, что мы получаем данные из байта частичного размера файла и далее до конца файла.

Итак, теперь, когда мы это понимаем, мы можем собрать все это вместе в приведенном ниже коде.

resume_header = {'Range':f'bytes={path('filename.zip').stat().st_size}-'}
r = requests.get(url,stream=True, headers=resume_header)
with open ('filename.zip','ab') as f:
   for chunk in r.iter_content(chunk-size=1024):
     f.write(chunk)

Примечания

  1. Режим «ab» в функции открытия добавляет новый контент в файл. Мы не хотим перезаписывать существующий контент, это вместо "wb"

Проверка файлов

Иногда нам нужно иметь возможность проверять загруженный файл. Если вы возобновили загрузку файла или если это важные данные исследования, которыми вы хотите поделиться с другими. Существует модуль Python, называемый модулем hashlib, который создает хеш-функцию. Хеш-функция принимает данные и преобразует их в уникальную строку цифр и букв. Мы называем это хеш-объектом. Вычисление этой строки выполняется с помощью алгоритмов, которые мы можем указать как часть модуля.

Давайте перейдем к тому, как мы будем проверять загруженный файл. Нам нужно знать, каким должно быть хеш-значение, чтобы иметь возможность его проверить. Мы прочитаем двоичный файл и сгенерируем хэш, который затем можно будет сравнить с известным значением хеш-функции файла. Поскольку хеш-файлы уникальны, мы сможем подтвердить, что это один и тот же файл.

Чтобы создать хеш-значение, нам нужно указать алгоритм, который его создает. Есть много вариантов, но в этом примере мы используем sha256(). Теперь, чтобы создать хеш-значение, мы используем hashlib update()method, который будет принимать только «байтовые» данные, например байты. Чтобы получить доступ к хеш-значению, мы вызываем метод hexdigest(). hexdigest() принимает хэш-объект и предоставляет нам строку, состоящую только из шестнадцатеричных цифр. Эта строка определяется алгоритмом, который мы указали ранее.

Создав хеш-значение, вы не сможете работать в обратном направлении, чтобы получить исходные двоичные данные. Это работает только в одну сторону. Мы можем сравнивать два файла только по их уникальному хэш-значению, что делает их более безопасными при передаче другим людям.

import hashlib
with open('research.zip', 'rb') as f:
    content = f.read()
sha = hashlib.sha256()
sha.update(content)
print(sha.hexdigest())

Выход:

42e53ea0f2fdc03e035eb2e967998da5cb8e2b1235dd2630ffc59e31af866372

Примечания

  1. Модуль hashlib импортирован
  2. Мы читаем файл с помощью оператора with: это гарантирует, что нам не нужно использовать оператор закрытия.
  3. Мы вызываем метод read() для чтения всего содержимого двоичных данных.
  4. Создается переменная sha, которая создает хэш-объект с использованием алгоритма SHA 256 для создания хеш-значения.
  5. Используя метод update(), мы передаем двоичные данные в хеш-объект. Таким образом мы получаем хеш-значение.
  6. Используя метод hexdigest(), мы можем распечатать хеш-значение, фиксированную строку, уникальную для этого двоичного файла.

Итак, теперь у нас есть хеш-значение, когда вы хотите проверить файл. Если вам пришлось скачать его заново или передать данные коллеге. Вам нужно только сравнить созданное вами хеш-значение. Если возобновленная загрузка завершена и имеет правильное хеш-значение, то мы знаем, что это те же данные.

Давайте создадим небольшой скрипт для подтверждения файла, который вам передал ваш друг. Например, у вас есть хеш-значение для ввода.

user_hash = input('Please input hash please: ')
sha = hashlib.sha256()
with open('file.zip' as 'rb') as f:
   chunk = f.read()
   if not chunk:
       break
   sha.update(chunk)
try:
    assert sha.hexdigest() == user_hash
except AssertionError:
    print('File is corrupt, delete it and restart program'
else: 
   print('File is validated')

Примечания

  1. Мы просим пользователя ввести хеш-значение, и этому значению присваивается переменная user-hash.
  2. Переменная sha создается, и создается хеш-объект, когда мы указываем алгоритм
  3. Мы открываем файл, который хотим проверить, используя оператор with. Мы определяем блок переменной и назначаем ему двоичные данные с помощью метода чтения.

4. Мы используем метод hashlib update() для создания хеш-объекта для этого фрагмента.

5. Мы создаем хеш-значение для этого фрагмента, используя sha.hexdigest().

6. Мы используем ключевое слово assert, которое оценивает выражение на предмет истинности. В этом случае сравнивайте хеш-значение загруженных данных с введенным хеш-значением.

7. Указываем исключение AssertionError. Это вызывается, когда утверждение assert ложно и указывает сообщение об ошибке.

8. В операторе else, если переменная user_hash совпадает с хеш-значением файла, мы печатаем, что файл проверен.

Итак, здесь мы создали очень простой инструмент проверки загруженных файлов.

Индикаторы прогресса

Есть много пакетов для отображения прогресса в вашем программном коде. Здесь мы поговорим о простом способе добавления индикатора выполнения при загрузке файлов! Это может быть полезно, если вы загружаете массово и хотите видеть прогресс по мере продвижения. Индикаторы выполнения могут быть полезны разными способами не только для загрузки файлов.

Tqdm - это сторонний пакет Python, который может работать с индикаторами выполнения. Для меня это лучший способ думать о python: начать с как можно меньшего количества кода, чтобы получить то, что вы хотите.

Прежде всего вы захотите установить tqdm с помощью pip.

pip install tqdm

Затем мы захотим импортировать tqdm. Теперь это метод tqdm, который мы хотим использовать для отображения прогресса данных. Модуль tqdm может интерпретировать каждый фрагмент и отображать прогресс файла.

Чтобы включить индикатор выполнения в загрузку файлов. Во-первых, мы должны создать несколько переменных, самая важная из которых - размер файла. Для этого мы можем использовать пакет запроса. Мы берем двоичные заголовки и внутри "content-length". Прокрутите вверх до двоичных заголовков в другом разделе, чтобы увидеть. Связанное с ним значение - это количество байтов данных, которые мы запросили с сервера. Ответ представляет собой строку, и мы должны преобразовать ее в числовой формат при использовании ее для индикатора выполнения.

Другая важная часть - это имя файла. Мы можем разделить URL-адрес на список и довольно просто выбрать последний элемент.

Затем мы указываем модуль tqdm, когда у нас настроены все переменные.

Оператор with означает, что он закрывается после завершения операции, а функция open записывает данные. Затем мы используем метод tqdm и указываем аргументы для отображения загружаемых данных. Имейте в виду, что аргументы довольно подробны! Давайте рассмотрим их один за другим.

  1. Аргумент total - это размер файла, который мы определили.
  2. Аргумент unit - это строка, которую мы указываем для определения единицы измерения каждой итерации блока данных. В данном случае мы указываем B для байтов.
  3. Аргумент desc отображает имя файла
  4. Аргумент initial указывает, откуда начинать индикатор выполнения в данном случае 0.
  5. Аргумент ascii указывает, что мы используем для заполнения индикатора выполнения. Если установлено значение false, вместо этого предполагается, что Unicode заполняет индикатор выполнения.

Теперь, когда мы объяснили, что делаем, давайте посмотрим на код:

from tqdm import tqdm
url = "insert here"
file = url.split('/')[-1]
r = requests.get(url, stream=True, allow_redirects=True)
total_size = int(r.headers.get('content-length'))
initial_pos = 0
with open(file,'wb') as f: 
    with tqdm(total=total_size, unit=B, 
               unit_scale=True,                      desc=file,initial=initial_pos, ascii=True) as pbar:
      for ch in r.iter_content(chunk_size=1024),                             
              if ch:
                  f.write(ch) 
                  pbar.update(len(ch))

Выход:

filename.zip 100%|#################################################| 3.71M/3.71M [00:26<00:00, 254kB/s]

Примечания

  1. Импортируем метод tqdm из модуля tqdm.
  2. URL-адрес переменной определен.
  3. Переменная файла определена, мы используем метод разделения строки, чтобы разбить URL-адрес на список. Аргумент (‘/’) - это то, что сообщает методу split, что нужно разделить строку между символами / ’URL-адреса. Здесь мы хотим получить последний индекс списка, так как это будет желаемое имя файла.
  4. Переменная r используется для указания HTTP-запроса на получение, которому мы разрешаем иметь открытый поток данных и разрешаем перенаправления.
  5. Переменная total_size определена и использует пакет запроса для получения двоичных заголовков. Используя метод get, мы получаем значение ‘content-length’, которое представляет собой размер двоичных файлов. Теперь это возвращает строку, и мы превращаем ее в число с помощью int ().
  6. Переменной initial_pos присвоено значение 0, что важно указать для метода tqdm.
  7. Мы обращаемся к методу tqdm с помощью оператора with. Мы указываем несколько пунктов в аргументах.
  8. r.iter_content разбивает данные на части. Мы определяем ch как кусок размером 1024 байта, и если он доступен, мы записываем его в файл.
  9. Мы вызываем атрибут update метода tqdm, чтобы обновить этот фрагмент до индикатора выполнения и отобразить его для нас.

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

Спасибо за прочтение!

Об авторе

Я врач, который очень интересуется преподаванием, питоном, технологиями и здравоохранением. Я живу в Великобритании, преподаю онлайн-клиническое образование, а также веду веб-сайты www.coding-medics.com.

Вы можете связаться со мной по адресу [email protected] или в твиттере здесь, все комментарии и рекомендации приветствуются! Если вы хотите поговорить о каких-либо проектах или сотрудничать, это было бы здорово.

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