Скачивание видео из постов в вк python
Всем привет!
Стоит задача написать код для скачивания видео из Вконтакте, используя ссылку.
Пример ссылки:
https://m.vk.com/video-28402905_456290220
Никак не могу прийти к толковому решению. Как варианты пробовал использовать сервис savefrom.net и подобные, отправлять на него запросы с помощью requests, но опять же ничего.
Помогите пожалуйста с решением.
Ответы (1 шт):
Что ж, вот алгоритм действий, которые нужно выполнить, чтобы скачать видео:
- Находим ссылку на плейлист;
- Загружаем плейлист со ссылками на видео различного разрешения, открывает и смотрим содержимое;
Вот, для примера ссылка на видео с разрешением 720p.
- Скачиваем плейлист с фрагментами видео, открываем и смотрим названия фрагментов;
Таким образом, именно в данном случае, ссылка на фрагмент видео будет:
Почему в данном случае? Дело в том, что не всегда в плейлистах к фрагментам указаны именно такие ссылки и не всегда именно в этом виде.Таким образом, если писать код под этот, и похожие, случаи, это будет выглядеть примерно вот так:
import os.path
import shutil
from requests import get
from bs4 import BeautifulSoup
headers = {
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 '
'Safari/537.36',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,'
'application/signed-exchange;v=b3;q=0.9 '
}
def rep_symbol(text: str):
tex = text.replace("'", "").replace('"', '').replace('|', '_').replace(' | ', '_').replace('/', '_'). \
replace('\\', '_').replace('*', '_').replace('?', '').replace('<', '').replace('>', '_').replace(':', ''). \
replace(';', '').replace('.', '').strip()
return tex
def get_m3u8(url: str) -> tuple:
req = get(url=url, headers=headers)
soup = BeautifulSoup(req.text, 'lxml')
title = rep_symbol(soup.find('h1', class_='VideoPageInfoRow__title').text).replace(" ", "_")
m3u8 = soup.find('div', class_='VideoPage__video').find_all('source')[0].get('src')
return title, m3u8
def parse_m3u8(m3u8: str) -> dict:
links = {}
res = get(url=m3u8, headers=headers).text.splitlines()
for num in range(0, len(res)):
if "480" in res[num]:
links.update({"480": res[num+1]})
elif "720" in res[num]:
links.update({"720": res[num+1]})
elif "360" in res[num]:
links.update({"360": res[num+1]})
return links
def download_chunk(title: str, links: dict):
dir_vid = os.path.join(os.getcwd(), 'video', title)
if not os.path.exists(os.path.join(os.getcwd(), 'video')):
os.mkdir(os.path.join(os.getcwd(), 'video'))
if not os.path.exists(dir_vid):
os.mkdir(dir_vid)
if "720" in links:
url = links["720"]
find_str = "HIGH"
elif "480" in links:
url = links["480"]
find_str = "MEDIUM"
elif "360" in links["360"]:
url = links["360"]
find_str = "LOW"
else:
return 'Не найдено ссылок для загрузки'
video_name = f'id{url.split("/")[-3]}'
res = get(url=url, headers=headers).text.splitlines()
chunk_path = []
print('\nЗагрузка фрагментов')
for item in res:
print(f'\r - Загружаю: {item}', end='')
if item.startswith(find_str):
chunk = get(url=f'{url}{item}', headers=headers)
with open(os.path.join(dir_vid, item), 'wb') as ch:
chunk_path.append(os.path.join(dir_vid, item))
ch.write(chunk.content)
print('\nКонвертация')
with open(os.path.join(dir_vid, f'{video_name}.ts'), 'wb') as merged:
for cnk in chunk_path:
with open(cnk, 'rb') as mergefile:
shutil.copyfileobj(mergefile, merged)
print(f'{os.path.join(dir_vid, video_name)}.ts')
os.system(f"ffmpeg -i {os.path.join(dir_vid, video_name)}.ts {os.path.join(dir_vid, video_name)}.mp4")
for it_ch in chunk_path:
os.remove(it_ch)
os.remove(f'{os.path.join(dir_vid, video_name)}.ts')
print('\nЗагрузка и конвертирование завершено.')
print(f'Видео сохранено в папку: {dir_vid}')
def main():
url = input('Введите ссылку на страницу видео: ')
if 'https://m.vk.com/video' not in url:
print('Введите корректную ссылку')
return
title, m3u8 = get_m3u8(url)
links = parse_m3u8(m3u8)
download_chunk(title, links)
if __name__ == "__main__":
main()
Извиняюсь за код. Некогда было "облагораживать". Данный код будет загружать видео, для которых справедлива вышеприведенная ссылка, то есть, название в плейлистах с фрагментами соответствует вышеприведенному шаблону. Но, если данному коду попадется плейлист со ссылками на фрагменты подобного рода:
то, он работать не будет. Здесь ссылка будет иметь вид:
То есть, для начала, ее надо еще получить из данного плейлиста, убрать то, что за вопросом, вместе с ним. Ну и то, что прилетит в плейлисте с фрагментами будет выглядеть так:
Теперь, после того, как вы скачали плейлист с названиями фрагментов, вам нужно составить ссылку на фрагменты. А она будет выглядеть следующим образом:
https://pvv4.vkuservideo.net/c509108/video/hls/1/e4eMj86OT0xOzIy/videos/488fd84252/seg-3-f4-v1-a1.ts
Из ссылки на плейлист с фрагментами нужно убрать название плейлиста, и подставить название фрагмента.
Таким образом, что мы получаем. Если вы захотите скачивать почти любое видео из ВК, вам нужно подумать, как вышеприведенный скрипт, сделать более универсальным. Ну или написать на его основе свой. А почему почти любое видео? Потому, что пока, я ссылок или способов на скачивание видео из ВК, которое добавлено туда в виде стрима, не нашел.
Надеюсь, вам поможет это объяснение.
P.S.: Забыл добавить, что после того, как вы загрузите фрагменты, вам их нужно объединить в один файл, что выполняется вот в этой части кода:
with open(os.path.join(dir_vid, f'{video_name}.ts'), 'wb') as merged:
for cnk in chunk_path:
with open(cnk, 'rb') as mergefile:
shutil.copyfileobj(mergefile, merged)
Затем, то, что вы объедините конвертировать в mp4:
os.system(f"ffmpeg -i {os.path.join(dir_vid, video_name)}.ts {os.path.join(dir_vid, video_name)}.mp4")
А затем удалить загруженные фрагменты и объединенный файл. Конвертация происходит посредством утилиты ffmpeg. Таким образом, у вас она должна быть установлена в ОС. Данный код, будет работать в Linux, но для Windows вам нужно поискать, как запускать утилиту из командной строки.
Вот скриншот с загруженным видео, которое у вас в вопросе, с помощью вышеприведенного скрипта:





