Доброго времени суток всем.
Захотелось мне скачать всю мою музыку со ВКонтакте на флешку, как в старые добрые времена. Немного погуглив и не найдя практически ничего более менее приемлемого, я решил действовать своими силами. Спустя пол часа получился вполне себе рабочий скрипт. Итак, начнём.
Для работы нужно скачать модули vk_api и request!
Для начала подключим необходимые модули и объявим некоторые переменные:
import os
import pickle
import vk_api
import requests
from vk_api import audio
from time import time
vk_file = "vk_config.v2.json"
REQUEST_STATUS_CODE = 200
path = 'vk_music/'
Теперь напишем метод авторизации в аккаунт ВКонтакте:
def Auth(new=False):
try:
USERDATA_FILE = r"AppData/UserData.datab" #файл хранит логин, пароль и id
global my_id # объявляем переменную глобально, дабы иметь к ней доступ из других методов
# проверяем, нет ли сохранённых данных авторизации? Если есть, то загружаем
if (os.path.exists(USERDATA_FILE) and new == False):
with open(USERDATA_FILE, 'rb') as DataFile:
LoadedData = pickle.load(DataFile)
login = LoadedData[0]
password = LoadedData[1]
my_id = LoadedData[2]
else: # если есть, но пользователь выбрал новую авторизацию, то удаляем данных и просим ввести новые
if (os.path.exists(USERDATA_FILE) and new == True):
os.remove(USERDATA_FILE)
login = str(input("Введите логин\n> "))
password = str(input("Введите пароль\n> "))
my_id = str(input("Введите id профиля\n> "))
SaveUserData(login, password, my_id)
SaveData = [login, password, my_id]
with open(USERDATA_FILE, 'wb') as dataFile:
pickle.dump(SaveData, dataFile) # сохраняем введённые данные
vk_session = vk_api.VkApi(login=login, password=password)
try:
vk_session.auth() # пробуем авторизоваться, если возникнет исключение, значит у пользователя включена двухфакторная аутентификация. Просим ввести код.
except:
vk_session = vk_api.VkApi(login=login, password=password,
auth_handler=auth_handler) # auth_handler=auth_handler - вызываем метод, см. далее
vk_session.auth()
print('Вы успешно авторизовались.')
vk = vk_session.get_api()
global vk_audio # объявляем глобально, дабы иметь доступ из других методов
vk_audio = audio.VkAudio(vk_session)
except KeyboardInterrupt:
print('Вы завершили выполнение программы.')
Метод будет проверять, не авторизовывались ли мы уже раньше? Если такое было, то можно будет продолжить в этом аккаунте, или авторизоваться по-новой. В этом случае старые данные будут стёрты.
Далее напишем метод auth_handler, который нужен для авторизации в аккаунтах, в которых включена двухфакторная аутентификация:
def auth_handler():
code = input("Введите код подтверждения\n> ")
remember_device = True # True - запоминаем и не просим каждый раз вводить код
return code, remember_device
И так, теперь мы можем авторизоваться во ВКонтакте. В методе Auth упомянался метод SaveUserData(), он нужен для сохранения данных. Напишем его:
def SaveUserData(login, password, profile_id):
USERDATA_FILE = r"AppData/UserData.datab"
if (not os.path.exists("AppData")): # если нет папки AppData - создадим ее
os.mkdir("AppData")
SaveData = [login, password, profile_id] # список данных для сохранения
with open(USERDATA_FILE, 'wb') as dataFile: # собственно записываем данные в файл
pickle.dump(SaveData, dataFile)
Данные будут записаны в бинарном виде, дабы не хранить логин и пароль пользователя в открытом виде.
Осталось написать метод загрузки аудио со ВКонтакте, давайте это и сделаем:
def main():
try:
if (not os.path.exists("AppData")):
os.mkdir("AppData")
if not os.path.exists(path):
os.makedirs(path)
# спросим пользователя, нужно ли авторизоваться по-новой или продолжить старую сессию
auth_dialog = str(input("Авторизоваться заново? yes/no\n> "))
if (auth_dialog == "yes"):
Auth(new=True)
elif (auth_dialog == "no"):
Auth(new=False)
else:
print('Ошибка, неверный ответ.')
main()
print('Подготовка к скачиванию...')
os.chdir(path) #меняем текущую директорию
audio = vk_audio.get(owner_id=my_id)[0]
print('Будет скачано:', len(vk_audio.get(owner_id=my_id)), 'аудиозаписей.')
count = 0
time_start = time()
print("Скачивание началось...\n")
# этим циклом, собственно, и скачиваем нашу музыку.
for i in vk_audio.get(owner_id=my_id):
try:
print('Скачивается: ' + i["artist"] + " - " + i["title"])
count += 1
r = requests.get(audio["url"])
if r.status_code == REQUEST_STATUS_CODE:
print('Скачивание завершено: ' + i["artist"] + " - " + i["title"])
with open(i["artist"] + ' - ' + i["title"] + '.mp3', 'wb') as output_file:
output_file.write(r.content)
except OSError:
print("!!! Не удалось скачать аудиозапись №", count)
time_finish = time()
print("" + vk_audio.get(owner_id=my_id) + " аудиозаписей скачано за: ",
time_finish - time_start + " сек.")
except KeyboardInterrupt:
print('Вы завершили выполнение программы.')
Ну вот и всё. Теперь у нас есть рабочий скрипт для загрузки аудиозаписей из ВКонтакте.
Вот так выглядит весь исходный код:
import os
import pickle
import vk_api
import requests
from vk_api import audio
from time import time
__version__ = 'VK Music Downloader v1.0'
APP_MESSAGE = '''
_ . ___
/\\ | | | \\ | | | \\ / | /
/__\\ | | | \\ | | | \\ / |/
/ \\ |___| |__/ | |___| \\/ |\ '''
vk_file = "vk_config.v2.json"
REQUEST_STATUS_CODE = 200
path = 'vk_music/'
def auth_handler(remember_device=None):
code = input("Введите код подтверждения\n> ")
if (remember_device == None):
remember_device = True
return code, remember_device
def SaveUserData(login, password, profile_id):
USERDATA_FILE = r"AppData/UserData.datab"
SaveData = [login, password, profile_id]
with open(USERDATA_FILE, 'wb') as dataFile:
pickle.dump(SaveData, dataFile)
def Auth(new=False):
try:
USERDATA_FILE = r"AppData/UserData.datab" #файл хранит логин, пароль и id
global my_id
if (os.path.exists(USERDATA_FILE) and new == False):
with open(USERDATA_FILE, 'rb') as DataFile:
LoadedData = pickle.load(DataFile)
login = LoadedData[0]
password = LoadedData[1]
my_id = LoadedData[2]
else:
if (os.path.exists(USERDATA_FILE) and new == True):
os.remove(USERDATA_FILE)
login = str(input("Введите логин\n> "))
password = str(input("Введите пароль\n> "))
my_id = str(input("Введите id профиля\n> "))
SaveUserData(login, password, my_id)
SaveData = [login, password, my_id]
with open(USERDATA_FILE, 'wb') as dataFile:
pickle.dump(SaveData, dataFile)
vk_session = vk_api.VkApi(login=login, password=password)
try:
vk_session.auth()
except:
vk_session = vk_api.VkApi(login=login, password=password,
auth_handler=auth_handler)
vk_session.auth()
print('Вы успешно авторизовались.')
vk = vk_session.get_api()
global vk_audio
vk_audio = audio.VkAudio(vk_session)
except KeyboardInterrupt:
print('Вы завершили выполнение программы.')
def main():
try:
if (not os.path.exists("AppData")):
os.mkdir("AppData")
if not os.path.exists(path):
os.makedirs(path)
auth_dialog = str(input("Авторизоваться заново? yes/no\n> "))
if (auth_dialog == "yes"):
Auth(new=True)
elif (auth_dialog == "no"):
Auth(new=False)
else:
print('Ошибка, неверный ответ.')
main()
print('Подготовка к скачиванию...')
os.chdir(path) #меняем текущую директорию
audio = vk_audio.get(owner_id=my_id)[0]
print('Будет скачано:', len(vk_audio.get(owner_id=my_id)), 'аудиозаписей.')
count = 0
time_start = time() # сохраняем время начала скачивания
print("Скачивание началось...\n")
# собственно циклом загружаем нашу музыку
for i in vk_audio.get(owner_id=my_id):
try:
print('Скачивается: ' + i["artist"] + " - " + i["title"]) # выводим информацию о скачиваемой в данный момент аудиозаписи
count += 1
r = requests.get(audio["url"])
if r.status_code == REQUEST_STATUS_CODE:
print('Скачивание завершено: ' + i["artist"] + " - " + i["title"])
with open(i["artist"] + ' - ' + i["title"] + '.mp3', 'wb') as output_file:
output_file.write(r.content)
except OSError:
print("!!! Не удалось скачать аудиозапись №", count)
time_finish = time()
print("" + vk_audio.get(owner_id=my_id) + " аудиозаписей скачано за: ",
time_finish - time_start + " сек.")
except KeyboardInterrupt:
print('Вы завершили выполнение программы.')
if __name__ == '__main__':
print(APP_MESSAGE)
print(__version__ + "\n")
main()
Я только учусь, поэтому буду рад всем замечаниям в коде. Спасибо за внимание.
vasiaplaton
Есть savefromnet для chorma'а. Открываете его в своей музыке и нажимаете скачать все. Ждете. Profit.
А потом еще можно пронумеровать имя файла что б слушать в том же порядке. Для Linux когда давно писал скрипт.
rpiontik
Ну… готовая тулза не решает всего спектра вопросов, который можно решить скриптом. Например автоматическая синхронизация медиа вконтакте на диск дома или в свое, родное облачко.
vasiaplaton
Вы конечно правы. На то и готовая тулза, что бы решать только типовые задачи.
Free_ze
Не этот ли плагин попалился недавно на воровстве данных юзеров?
Jessy_James
Если своё vk_api подпихнуть, то вполне можно так сделать…
y_durov
Скажу честно — всегда безопаснее написать свой скрипт и быть уверенным, что твои данные останутся при тебе. А savefromnet не опенсорсный, и понять что у него под капотом происходит — нужно немного запариться.
DiffeRT
А вас не смущает savefromnet-у отдавать свои креды от аккаунта? Вы же не знаете что он может еще делать помимо скачивания. Лично я для этого плагина отдельный аккаунт завел и отдельный браузер
ChieF_Of_ReD
Рекомендую к ознакомлению
habr.com/ru/company/globalsign/blog/460987
kAIST
А зачем на каждый чих вызывать vk_audio.get()?
Можно же вызвать один раз и записать в переменную. Или я чего то не понимаю.
Jessy_James
Можно, но в статье написано что человек учится. Все с опытом приходит.
valera5505
Youtube-dl справляется с этой задачей и еще с миллионами подобных. Опен-сорс, данные не крадет, скрипты в браузер ставить не нужно.
Gutt
Справляется ли? Последняя версия получает отлуп с «bad browser», хотя и представляется Хромом.
ChieF_Of_ReD
Вы сейчас абсолютно серьёзно?
Ti_Fix
По ссылке официальный сайт, а не исполняемый файл. Где вы увидели youtube-dl.exe?
ChieF_Of_ReD
По ссылке внутри сайта, что скинули, в разделе скачать, лежит такой миленький экзешник.
yt-dl.org/downloads/2019.09.12.1/youtube-dl.exe
Ti_Fix
На этой же странице ссылка на исходный код и документацию. Почему вас так расстраивает наличие возможности скачать исполняемый файл (один из вариантов)?
ChieF_Of_ReD
Т.е. вы по умолчанию верите, что именно этот исходик использовался при сборке экзешника?
faiwer
Кто-то мешает вам собрать его самостоятельно? Сам факт наличия уже собранной версии по-вашему как-то очерняет программу?
P.S. gentoo?
ChieF_Of_ReD
Посмотрите на этот вопрос немного под другим углом. Имеется три варианты сборки, две из них чисты, один, допустим экзешник с лишними функциями, вы пройдёте мимо него, собрав нужную версию из исходников, обыватель видит, «о, отлично, можно просто установить и использовать, там же ещё код приложен, что может пойти не так это же опенсорс.» и качает файлик затем устанавливает. Таких вот пользователей миллионы, по сути я один из них, чтобы собрать последнюю версию и заставить её работать мне всё же потребуется затратить время, а его жаль. Но тут лежит такой простой *.exe файл, бери, ставь, пользуй.
Надеюсь, у меня получилось донести мысль.
По сути не вы целевая аудитория таких вот схем, а простые обыватели.
Но и опять же, если вам было бы чуть лень заниматься сборкой самостоятельно, то и вы могли бы попасть на подобную удочку.
Паранойя спросите вы? Здравый смысл отвечу я.
faiwer
Повторю вопрос — Gentoo? :)
ChieF_Of_ReD
Поясните, что вы хотите услышать?
faiwer
Обычно паранойа такого уровня это признак гентушника. Если вы до сих пор не знакомы с этой операционной системой, то с вашими взглядами на open source у вас просто нет выбора, — вы созданы друг для друга.
ChieF_Of_ReD
А, вы это имели в виду, нет, не гентушник.
Считаете, что ситуация которую я описал выше нереальна?
Jessy_James
Крайне мала.
faiwer
Более, чем реальна. Но уровень паранойи — это выбор каждого. Я вот скорее скачаю готовый deb пакет из источника к которому питаю доверие, нежели буду качать исходные коды, изучать их под лупой и пересобирать. Свои риски я осознаю, и сам же за них несу ответственность. 99%+ пользователей будет качать уже собранный бинарник, и не по глупости, а целенаправлено. Желающим же большего контроля доступны исходные коды. Вы из вторых — велкам, для вас там всё подготовлено.
Вам не нравится что возможность на свой страх и риск довериться тем кто выложил вместе с исходниками уже готовый бинарь в принципе существует? Гхм, ну селяви. Обратное встречается настолько ускользающе редко, что стоит ли об этом вообще упоминать.
Хехе, представил себе как каждая вторая рабочая станция качает обновления в виде сырсов и ночами пересобирает сама себя. Дивный мир.
Jessy_James
Для таких можно компилятор правильный подсунуть, который будет вкомпиливать правильные дополнения )
ChieF_Of_ReD
Да, с вами я полностью согласен и рад, что мы поняли друг друга.
valera5505
А какое решение вы предлагаете? Всех заставлять ставить из исходников? Ну так мало просто скачать и скомпилировать, надо же еще тогда глазами проверить на то, что код чист. То есть всем надо внезапно стать программистами, способными пропускать через себя десятки и сотни тысяч строк кода, чтобы не стать жертвой какой-нибудь схемы.
ChieF_Of_ReD
Единственное, что я для себя решил — это просто прикидывать риски, финансовые, репутационные допустим. Если вам кровь из носа требуется например скачать музыку из вк, то сами решите, стоит оно того, что вы можете потерять, использую чужой софт, а может и не потеряете.
Посему нужно искать источники, где вы имеете хоть какой-то кредит доверия и некую работу (в частности чистоты кода ) могут взять другие люди. Вот отличный пример эта статья. Десяток человек прошерстили код вдоль и поперёк и самое время его использовать.
Увы, мы максимум, что можем — это сделать эту задачу нерентабельной.
Tihon_V
А можно код хотя бы на gist.github.com выложить?
Max_JK
Я давненько писал бота для скачивания музыки, для себя, vk.com/music_bott некоторые функции уже не работают, но музыку скачать все ещё можно, удобно что не нужно уходить с сайта чтобы скачать музыку, может кому пригодится.
bvn13
Учебный пример — это хорошо. Но в свете последних новшевств музыка ВК действительно того стоит, чтобы ей пользоваться?
Ti_Fix
О каких новшествах идет речь?
Gutt
Да, там можно найти (и утянуть себе на плеер) музыку, которую в других местах найти трудно.
nebularia
В свете последних новшеств как раз и стоит. Плейлисты и большое количество вполне себе легальной музыки (работает с крупными агрегаторами, в результате чего там действительно много контента), а также куча авторских сообществ и тематических пабликов с остальной музыкой (и тоже с альбомами в виде плейлистов) формируют просто отличную библиотеку. Плюс пользовательский контент и возможность загрузки своих файлов. При этом цена на подписку вполне гуманна.
Есть и минусы, конечно — некоторая хаотичность и полная чушь в рекомендациях, да.
w3ga
мне, яндекс.музЫка, недавно (2 дня назад как) порекомендовал сборку в стиле «регги», среди прочего там — песня — «течёт река волга» (не знаю кто поёт, какое-то ВИА или ещё кто), игра на балалайке, парочку песен из бродвейских мюзиклов и прочая муть со всех концов планеты… всё что их объединяет с «регги», так это года — почти все композиции родом из 60х +\-
polar11beer
Оффтоп:
Так всё равно данные можно прочитать hex-редактором, так как они не зашифорованы. Не по теме статьи, но всё же.А за скрипт респект, просто и практично.
Jessy_James
Они блокнотом читаются, проверено ))
Gutt
И, действительно, ноды с id == au_search_items в коде страницы с аудио нет.
x88
Теперь на некоторых пользователях тестируется отдача музыки через HLS (M2TS поток), который поддерживает шифрование, так что придётся использовать инструменты для дальнейшей сборки чанков.
Jessy_James
Недели 2-ве назад видел эту статью в песочнице, код был в ошибках. Скачивалась всегда 1-ая песня под разными именами. Код себе я тогда взял и поправил ошибки… )
UP ошибка то осталась: audio = vk_audio.get(owner_id=my_id)[0]
Gutt
А можно нам исправленную версию?
Jessy_James
github.com/dvjdjvu/vkMusicDownloader
Gutt
Спасибо, работает! Единственное, для юниксов пришлось сделать следующее, чтобы убрать слеши из имени файла:
Нулевой байт убирать смысла не вижу (у меня ни одной записи с ним в имени не нашлось :-). Для других ОС будут инвалидными другие символы, но, думаю, убранный слеш покроет 99 % случаев ошибок записи файлов из-за неверных символов в имени.
Jessy_James
Поправил.