Files
yandex_disk_folder_downloader/README.md
T
2026-08-03 21:44:03 +03:00

13 KiB
Raw Blame History

Yandex Disk Protected Folder Downloader

Скрипт для рекурсивного скачивания большой публичной папки Яндекс Диска, защищённой паролем.

Он получает список объектов через веб-API Яндекс Диска, сохраняет структуру каталогов и скачивает каждый файл отдельно через wget.

Возможности

  • чтение всех пользовательских настроек из файла .env рядом со скриптом;
  • использование готового cookie passToken либо автоматическое получение токена по паролю через Chromium и Playwright;
  • постоянный профиль Chromium с повторным использованием cookies;
  • рекурсивный обход вложенных каталогов;
  • двухэтапная работа: сначала полный список, затем скачивание;
  • сохранение полного списка в yandex-download-manifest.jsonl;
  • исключение служебного элемента текущего каталога из расчёта offset;
  • сохранение исходной структуры каталогов;
  • продолжение прерванной загрузки через wget --continue;
  • автоматический пропуск файлов, размер которых уже совпадает с серверным;
  • проверка итогового размера каждого скачанного файла;
  • паузы между запросами прямых ссылок и периодические длительные паузы;
  • повторные HTTP-запросы при временных ошибках 429, 500, 502, 503 и 504;

Как работает двухэтапная загрузка

Этап 1 — получение полного списка

Скрипт быстро обходит страницы каталога:

0 → 40 → 80 → 120 → ... → completed=True

На этом этапе:

  • download-url не запрашивается;
  • wget не запускается;
  • файлы не скачиваются;
  • для каждого файла сохраняются серверные метаданные и относительный каталог;
  • вложенные каталоги также обходятся полностью;
  • служебное описание текущей папки не учитывается при увеличении offset.

После успешного завершения обхода создаётся:

OUTPUT_DIR/yandex-download-manifest.jsonl

Manifest записывается атомарно: сначала создаётся временный файл .tmp, после чего он заменяет предыдущий manifest.

Пример одной строки:

{"relative_directory":".","item":{"name":"FL_9J1915234BP_1654_40013103010803_V001_S.frf","type":"file","size":793122,"path":"public_hash:/ODIS/Flashdaten/Brand-A/FL_9J1915234BP_1654_40013103010803_V001_S.frf"}}

Этап 2 — скачивание файлов

После получения completed=True скрипт начинает скачивание по полностью собранному плану:

  1. проверяет наличие локального файла;
  2. сравнивает его размер с серверным;
  3. пропускает полностью скачанный файл;
  4. для отсутствующего или неполного файла получает временный download-url;
  5. запускает wget --continue;
  6. проверяет размер после завершения.

Текущая версия сохраняет manifest для контроля и последующего анализа, но при новом запуске всё равно заново выполняет этап 1 и получает актуальный список с Яндекса.

Требования

Поддерживается Linux с Python 3.

Необходимые пакеты:

sudo apt install -y python3 python3-requests wget

Playwright и Chromium для автоматического получения passToken:

python3 -m pip install --user playwright
python3 -m playwright install chromium

Настройка

Все основные параметры находятся в файле sample.env

TARGET_URL

Полная публичная ссылка на нужный каталог:

TARGET_URL="https://disk.yandex.ru/d/cWn4RgSdFcSZXw/ODIS/Flashdaten/Brand-A"

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

Пароль публичной ссылки:

PUBLIC_LINK_PASSWORD="реальный пароль публичной ссылки"

Если оставить значение пустым, программа попытается использовать cookies из постоянного профиля Chromium. Если действующего passToken нет и запуск производится из терминала, пароль будет запрошен без отображения введённых символов.

OUTPUT_DIR

Каталог, куда будут сохранены файлы:

OUTPUT_DIR = "/mnt/hdd1-4TB/ODIS/Flashdaten/Brand-V"

Каталог будет создан автоматически, если у пользователя есть права на его создание. Внутри него также могут появиться:

yandex-download-manifest.jsonl
yandex-captcha-url.txt

Настройки Playwright

PLAYWRIGHT_PROFILE_DIR="./playwright-profile"
PLAYWRIGHT_HEADLESS="false"
PLAYWRIGHT_TIMEOUT="120"
  • PLAYWRIGHT_PROFILE_DIR — постоянный профиль Chromium;
  • PLAYWRIGHT_HEADLESS=false — показывает окно браузера и позволяет вручную пройти CAPTCHA;
  • PLAYWRIGHT_HEADLESS=true — запускает Chromium без окна; при CAPTCHA программа остановится;
  • PLAYWRIGHT_TIMEOUT — максимальное время ожидания получения passToken, в секундах.

Относительный путь профиля вычисляется относительно каталога, где находится .env и скрипт.

Задержки между страницами

PAGE_DELAY_MIN="0.5"
PAGE_DELAY_MAX="1.5"

Эти задержки используются только на этапе 1 между запросами fetch-list.

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

Задержки между файлами

FILE_DELAY_MIN="1.5"
FILE_DELAY_MAX="3.5"

Случайная пауза перед каждым запросом download-url на этапе 2.

Длительные паузы

COOLDOWN_EVERY_FILES="100"
COOLDOWN_MIN="60"
COOLDOWN_MAX="120"

После каждых 100 запросов download-url программа дополнительно ждёт от 60 до 120 секунд.

Чтобы отключить длительные паузы:

COOLDOWN_EVERY_FILES="0"
COOLDOWN_MIN="0"
COOLDOWN_MAX="0"

HTTP-таймауты и повторы

CONNECT_TIMEOUT="30"
READ_TIMEOUT="120"
HTTP_RETRIES="5"
  • CONNECT_TIMEOUT — таймаут установки соединения;
  • READ_TIMEOUT — таймаут чтения ответа API;
  • HTTP_RETRIES — число автоматических повторов временных ошибок.

Пример вывода

Получение токена

[AUTH] Открываю защищённую ссылку в Chromium...
[AUTH] Используется passToken из сохранённого профиля.

Либо:

[AUTH] Поле пароля найдено (input[type="password"]).
[AUTH] Ввожу пароль публичной ссылки...
[AUTH] Пароль введён; отправляю форму...
[AUTH] passToken получен.

Этап 1

[INFO] Открываю исходную ссылку...
[INFO] Папка открыта.
[INFO] Корневой hash: public_hash:/ODIS/Flashdaten/Brand-A
[INFO] Этап 1/2: получаю полный список файлов...

[DIR ] /mnt/hdd1-4TB/ODIS/Flashdaten/Brand-A
[PAGE] получено API=41, дочерних=40, служебных=1, offset=0->40, completed=False
[WAIT] 0.8 с перед следующей страницей
[PAGE] получено API=10, дочерних=9, служебных=1, offset=12080->12089, completed=True
[INFO] Полный список получен: 12089 файлов.
[INFO] Manifest сохранён: /mnt/hdd1-4TB/ODIS/Flashdaten/Brand-A/yandex-download-manifest.jsonl

Этап 2

[INFO] Этап 2/2: начинаю скачивание по сохранённому списку...
[SKIP] /mnt/hdd1-4TB/ODIS/Flashdaten/Brand-A/FL_0DL300014F_3123_idMA_sw.frf (2.14 MiB)
[GET ] /mnt/hdd1-4TB/ODIS/Flashdaten/Brand-A/FL_9J1915234BP_1654_40013103010803_V001_S.frf (774.53 KiB)
[WAIT] 2.6 с перед запросом ссылки
2026-08-03 URL:https://s684vla.storage.yandex.net/rdisk/... [793122/793122]

Итоговая статистика

================ РЕЗУЛЬТАТ ================
Найдено файлов:       12089
Скачано сейчас:       529
Уже было скачано:     11560
Ошибок:               0
Известный общий объём: 49.04 GiB
===========================================

CAPTCHA

При большом количестве запросов Яндекс может вернуть CAPTCHA.

Скрипт распознаёт ответ:

{
  "type": "captcha"
}

После этого загрузка немедленно прекращается.

Будет выведена ссылка:

ЯНДЕКС ПОТРЕБОВАЛ CAPTCHA

Открой ссылку ниже в обычном браузере с того же внешнего IP:

https://disk.yandex.ru/showcaptcha?...

Ссылка также сохраняется в файл:

/mnt/hdd1-4TB/ODIS/Flashdaten/Brand-V/yandex-captcha-url.txt

Ошибка 409 Conflict

Внутренний API /public/api/fetch-list может вернуть 409 Conflict, если серверное состояние пагинации изменилось или стало недействительным.

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

409 не следует считать признаком конца каталога. Если он всё же возник на этапе 1:

  1. не удаляйте уже скачанные файлы;
  2. повторно запустите программу;
  3. скрипт получит новый sk и начнёт перечисление заново;
  4. на этапе 2 существующие файлы будут пропущены.

Полным считается только обход, завершившийся серверным признаком:

completed=True

Коды завершения

Скрипт использует следующие коды выхода:

Код Значение
0 загрузка завершена без ошибок
1 загрузка завершена с ошибками
2 ошибка конфигурации или отсутствует wget
75 Яндекс потребовал CAPTCHA
130 процесс остановлен через Ctrl+C

Проверить код после завершения:

echo $?