раздел 03
Скачать файл на сервер
У вас есть download_url нужного файла из прошлого раздела. Сама по себе ссылка не отдаст файл - она требует авторизации. Есть два документированных способа передать токен.
Два способа авторизации
- Параметр в ссылке. Добавить к
download_urlquery-параметрaccess_tokenс вашим токеном. - Заголовок. Отправить заголовок
Authorization: Bearer ACCESS_TOKENпри запросе наdownload_url.
Оба варианта рабочие, выбирайте удобный. По ссылке отдаётся настоящий медиафайл (mp4, m4a и т.д.), но через редирект - поэтому клиент должен идти за редиректами.
curl
Способ через заголовок. Флаг -L обязателен - он велит curl идти за редиректами до реального файла. -o задаёт имя файла на сервере.
curl -L -H "Authorization: Bearer ACCESS_TOKEN" \
"https://api.zoom.us/v2/recording/download/FILE_PATH" \
-o "2026-05-14-weekly-call.mp4"
Способ через параметр в ссылке - то же самое, но токен в URL:
curl -L \
"https://api.zoom.us/v2/recording/download/FILE_PATH?access_token=ACCESS_TOKEN" \
-o "2026-05-14-weekly-call.mp4"
Python
Для больших видео не держите файл целиком в памяти: качайте потоком и пишите по чанкам. У requests для этого есть stream=True и iter_content.
import requests
def download_recording(download_url: str, token: str, out_path: str):
headers = {"Authorization": f"Bearer {token}"}
with requests.get(download_url, headers=headers, stream=True, allow_redirects=True) as resp:
resp.raise_for_status()
with open(out_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=1024 * 1024):
if chunk:
f.write(chunk)
return out_path
allow_redirects=True у requests стоит по умолчанию, но для записей Zoom оно критично - оставляйте включённым.
Имя файла
Чтобы потом находить записи, собирайте имя из данных встречи: дата плюс тема. Тему придётся почистить от символов, недопустимых в имени файла.
import re
from datetime import datetime
def make_filename(meeting: dict, file: dict) -> str:
start = meeting.get("start_time", "")
date = start[:10] if start else datetime.now().strftime("%Y-%m-%d")
topic = re.sub(r"[^\w\- ]", "", meeting.get("topic", "meeting")).strip()
topic = re.sub(r"\s+", "-", topic).lower()
ext = file.get("file_extension", "mp4").lower()
return f"{date}-{topic}.{ext}"
Проверка, что скачали целиком
В объекте файла есть file_size в байтах. После скачивания сравните его с размером файла на диске - так вы поймаете обрыв загрузки до того, как удалите оригинал из Zoom.
import os
expected = file["file_size"]
actual = os.path.getsize(out_path)
if actual != expected:
raise RuntimeError(f"Размер не совпал: ждали {expected}, получили {actual}")
Дальше - куда складывать файлы и как сделать так, чтобы они скачивались сами.