yt-dlp и Instagram: «login required», пустой результат и чем заменить
yt-dlp — отличный инструмент, а Instagram — сайт, с которым он справляется хуже всего, и не по своей вине: Instagram отдаёт страницы за стеной логина всему, что не похоже на залогиненный браузер, а серверный IP не похож никогда. Это руководство объясняет, что означает ошибка, почему привычные решения деградируют и как та же ссылка выглядит через API скачивания — измерено, а не заявлено.
Обновлено
Что на самом деле говорит ошибка
Сообщение сваливает три разные ситуации в одну строку: пост недоступен, ваш IP упёрся в лимит или Instagram хочет сессию. На адресе дата-центра это почти всегда третье — запрос не доходит до поста, он сначала упирается в стену логина. yt-dlp снаружи не может их различить, поэтому его совет — «попробуйте cookie».
Terminal$ yt-dlp https://www.instagram.com/reel/ABC123/ ERROR: [Instagram] ABC123: Requested content is not available, rate-limit reached or login required. Use --cookies, --cookies-from-browser, --username and --password, or --netrc
Почему cookie помогают лишь на время
Экспорт сессии браузера работает в тот же день и перестаёт через несколько дней: Instagram ротирует токены сессии, привязывает их к IP и устройству, с которых они пришли, и помечает аккаунты, тянущие сотни постов с сервера. Решение превращается в ротацию аккаунтов и прокси, которой надо управлять, — это скрейпинг-операция, а не команда скачивания.
Что мы измерили с серверного IP
Перед тем как убрать yt-dlp из собственного пайплайна, мы прогнали через него 13 публичных reels с адреса Hetzner: 0 успешных, отдельные вызовы тянулись до 45 секунд перед падением. Собственный embed-эндпоинт Instagram не лучше — 0 из 11. Ссылки были в порядке; домашнее подключение их разрешило. Дело в адресе, а не в инструменте.
Та же ссылка через API
Один GET, никаких cookie с вашей стороны, никакого браузера. Разрешение происходит в цепочке источников, не зависящих от сессии Instagram, а ответ имеет одну форму для reel, поста, карусели и истории. Медианное время ответа измеряется вживую и показано на главной странице.
Terminalcurl -s "https://api.saveapi.org/v1/instagram" \ -H "Authorization: Bearer sk_live_xxxx" \ -G --data-urlencode "url=https://www.instagram.com/reel/ABC123/"
Прямая замена в Python
Если ваш код вызывал yt-dlp ради URL, а файл скачивал сам, это тот же контракт: передаёте ссылку, получаете прямые URL медиа, забираете байты с CDN. Что вы теряете — выбор формата yt-dlp; в ответе на каждое медиа Instagram приходит один вариант, так что выбирать нечего.
Pythonimport httpx
def resolve(link: str) -> list[str]:
"""yt-dlp o'rniga: havoladan to'g'ridan-to'g'ri media URL'lar."""
r = httpx.get(
"https://api.saveapi.org/v1/download",
params={"url": link},
headers={"Authorization": "Bearer sk_live_xxxx"},
timeout=30,
)
data = r.json()
if not data["success"]:
raise RuntimeError(data["error"]["code"])
return [m["url"] for m in data["medias"]]Вопросы перед началом
- yt-dlp вообще ещё качает Instagram?
- С домашнего подключения и свежими cookie — часто да. С сервера, по нашему измерению, — нет, а для бота или бэкенда важен именно серверный случай.
- API использует мой аккаунт Instagram?
- Нет. Нет логина, нет cookie, ваш аккаунт не участвует; запрос — только ссылка и ваш API-ключ.
- Сколько стоит неудачная ссылка?
- Ссылка, которую отверг сам Instagram — закрытая или удалённая, — стоит 0.1 кредита и возвращается со стабильным кодом. Всё, что упало с нашей стороны, не стоит ничего, и ответ говорит, что именно произошло.
Платформы, использованные здесь
Другие руководства
Запустите это руководство со своим ключом
Ключ за минуту. 1 000 бесплатных кредитов, без карты и без срока.