Первую часть пути мы пройдем окольным путем: чтобы чему-то научиться откажемся от использования неофициальной библиотеки yandex-music-api и получим данные своими руками. Во второй части пути к нам на помощь придет библиотека spotipy, которая перенесет в Спотифай все личные плейлисты, лайкнутые треки и альбомы. Поехали!
Переносим альбомы
У Яндекс.Музыки (ЯМ) нет API. Совсем. Поэтому данные нам придется брать со страниц ЯМ. Перейдем на свою страницу ЯМ в раздел альбомы и начнем поиск информации, открыв инструменты разработчика ( Ctrl + Shift + i в Chrome и FireFox).
В теле страницы с альбомами есть JSON-массив Mu , который в двух ключах содержит все, что нам нужно знать об альбоме: его ID, название и имя исполнителя:
C массивом Mu будем работать постоянно, так как в нем содержится самое ценное – ID альбомов, плейлистов и треков, по которому мы получаем всю необходимую информацию. Поэтому ID будет нашей целью на всем пути следования.
- Первый ключ – albumIds – содержит ID всех альбомов, но нам нужно будет дополнительно переходить на страницу каждого альбома и получать его название и имя исполнителя из тегов.
- Второй ключ – albums – сразу выдает название альбома и имя исполнителя, но только первые 150 пар (это ограничение распространяется на плейлисты тоже).
Мы воспользуемся первым ключом, чтобы перенести все альбомы.
Как вывести json в более читаемом виде, как на картинке выше?
Через функцию pprint :
Как получить название альбома и имя исполнителя?
Получив ID, перейдем на страницу альбома https://music.yandex.ru/album/ID_альбома . Из тегов узнаем название альбома и имя исполнителя. Допустим, в нашей фонотеке есть альбом «Greatest Hits In Japan» – Queen. Откроем страницу альбома .
В браузере перейдем в инструменты разработчика и выберем инструмент Селектор ( Ctrl + Shift + C ):
И просто кликнем по названию альбома на странице:
Тег <h1> с названием альбома найдется автоматически:
Тег <a> с именем исполнителя:
Автоматизация получения данных, Selenium
Библиотека Selenium умеет управлять браузером и часто используется для автоматизации тестирований. С помощью Selenium мы автоматизируем действия браузера: открытие страниц плейлистов, альбомов и треков.
Установим драйвер Chrome:
Chromedriver установится в /usr/lib/chromium-browser/chromedriver
Алгоритм получения данных об альбоме:
- Зайти на страницу со своими/чужими альбомами.
- Получить ID альбомов из массива Mu .
- Перейти на страницу альбома и найти в тегах название альбома и имя исполнителя.
Создадим в корневой директории папку proglib , а в ней файл get_music_data.py .
Импортируем Selenium и напишем функцию run_driver() , запускающую браузер:
- ‘chromedriver’ – путь к драйверу. Либо можем записать полный путь: ‘/usr/lib/chromium-browser/chromedriver’ .
Дальше идет небольшой велосипед. Дело в том, что Selenium при извлечении массива Mu со страницы ЯМ выдает ошибку:
Пауза после загрузки, чтобы страница загрузилась до конца и листание в конец страницы не помогли, другие подходы – тоже. Оказалось, если сохранить страницу на локальной машине, то можно вытащить всю информацию из массива Mu без каких-либо проблем. Сделаем это.
Алгоритм следующий:
- Обратиться к странице ЯМ.
- Создать локальную html-страницу и скопировать в нее содержимое страницы ЯМ.
- Извлечь массив Mu .
- Удалить локальную страницу.
Напишем функцию create_local_html_page() , которая создает локальный html-файл и заполняет ее содержимым страницы из ЯМ:
- page_filename – название html-файла.
- page_source – код страницы ЯМ.
Теперь напишем функцию get_local_html_page() , которая с помощью Selenium открывает локальную страницу:
- yandex_username – имя пользователя ЯМ.
- page_filename – название html-файла.
- url – ссылка на ЯМ.
И, наконец, функция delete_local_html_page() удаляет локальную страницу:
- page_path – путь к html-файлу.
Получим название альбома и имя исполнителя. Создадим функцию get_albums() :
В этом блоке кода мы:
- Создаем ссылку на страницу альбомов ЯМ пользователя.
- Создаем локальную страницу всех альбомов.
- Получаем всю информацию об альбомах из массива Mu .
- Получаем ID всех альбомов.
- Создаем словарь albums_for_spotify , в который запишем название альбома и имя исполнителя.
Здесь происходит следующее:
- Переходим на страницу альбома ЯМ.
- Создаем вложенный словарь для каждого альбома, в который записываем название альбома и имя исполнителя.
- Метод xpath позволяет искать вложенные друг в друга теги и извлекать из них текст. С его помощью найдем в коде страницы тег <h1> с классом deco-typo . И получим текст, содержащийся в теге с помощью .text .
- Записываем в словарь название альбома и имя исполнителя.
- Удаляем локальную страницу со всеми альбомами ЯМ.
- Закрываем браузер
В итоге словарь выглядит так:
Данные получили, как их перенести?
За перенос треков отвечает библиотека spotipy. Установим ее:
Для начала нужно создать приложение в Спотифай, получить client_id и client_secret . Зайдем на страницу developer.spotify.com/dashboard
И кликнем на Create an app :
Создание приложения в Spotify
заполним поля и нажмем Create :
После создания приложения кликнем по нему и найдем Client ID и Client Secret :
Получение Client ID и Client Secret в приложении Spotify
Зайдем в настройки приложения:
и впишем в поле Redirect URIs адрес http://localhost:8888/callback/ :
Редактирование поля Redirect URIs в приложении Spotify
Сохраним и закроем.
Дальше нам понадобится второй файл transfer.py для авторизации в Spotify через библиотеку spotify и для переноса альбомов (а также плейлистов, но об этом позже).
Запишем в transfer.py следующие строчки:
- scope – права приложения.
- redirect_uri – ссылка, которая откроется (и сразу закроется) в браузере при получении прав доступа.
- username – имя пользователя в Спотифай.
Напишем функцию get_album_id() , которая ищет в спотифай ID альбома:
- sp.search(q=query, limit=1, type=’album’) – поисковый запрос query выдает первый результат из раздела альбомы.
- В итоге функция возвращает ID альбома. А метод split делает из строки список, потому что метод current_user_saved_albums_add() , добавляющий в Спотифай альбом по ID, принимает в качестве аргумента именно список.
Перенесем альбомы через функцию transfer_albums() :
- sp, username = autorisation() – авторизация в Спотифай.
- query = ‘ ‘.join([artist_name, album_title]) – формируем поисковый запрос из названия альбома и имени исполнителя.
- get_album_id(query, sp) – ищем в Спотифай альбом по ID.
- sp.current_user_saved_albums_add(album_id) – добавляем альбом в свою медиатеку.
- except: pass – если альбом не найден (функция get_album_id вернет нам IndexError или KeyError ), то пропустить и начать сначала.
Переносим плейлисты
Плейлисты делятся на два вида:
- Плейлист «Мне понравилось» и созданные пользователем плейлисты.
- Лайкнутые плейлисты.
Мои плейлисты
- Перейти на странцу всех плелистов пользователя https://music.yandex.ru/users/yandex_username/playlists/ .
- Получить ID плейлистов из массива Mu .
- Перейти на страницу плейлиста по его ID.
- Получить со страницы плейлиста ID треков из массива Mu .
- Перейти на страницу каждого трека и получить их названия и имена исполнителей из тегов.
Вернемся к файлу get_music_data.py и добавим в него функцию get_my_playlists_id для получения ID альбомов на ЯМ:
Также как с альбомами: переходим на страницу всех плейлистов, извлекаем данные из массива Mu , находим ключ playlistIds с ID всех плейлистов.
Напишем функцию get_my_playlists для переноса своих плейлистов:
В этой части кода мы получаем ID всех наших плейлистов и записываем в словарь my_playlists , их ID и названия.
Теперь получим названия трека и имя исполнителя:
- track_id = re.findall(r’\d+(?=:)’, all_track_ids[j])[0] – all_track_ids имеет вид ID_трека:ID_плейлиста . Используем регулярное выражение, чтобы получить все числа до двоеточия – ID трека.
- driver.find_elements_by_xpath(“//span[@class=’d-artists’]//a[@class=’d-link deco-link’]”)[0].text – возвращает список, где первый элемент – имя первого исполнителя, если их несколько или единственного, если он записал трек соло.
В итоге словарь my_playlists_for_spotify выглядит так:
Теперь перенесем плейлисты в Спотифай. Откроем файл transfer.py и напишем функцию get_track_id() для поиска ID трека в Спотифай:
sp.search(q=query, limit=1, type=’track’) – получаем первый результат поискового запроса query .
Напишем функцию transfer_playlists , которая будет переносить как плейлисты пользователя, так и лайкнутые:
create_spotify_playlist – создает пустой плейлист в Спотифай с названием из ЯМ.
number_of_tracks – количество треков в плейлисте.
- Здесь мы ищем в Спотифай треки и записываем их ID и название плейлиста в словарь new_spotify_playlist .
- if all(query == ” for query in new_spotify_playlist.values()) – если все значения словаря пустые, значит треки отсутствуют в каталоге Спотифай, например, подкасты или локальные исполнители.
- sp.user_playlist_unfollow(username, new_spotify_playlist_id) – удаляет пустой плейлист из Спотифай.
Лайкнутые плейлисты
Лайкнутые плейлисты создали другие пользователи, но мы можем их перенести также как свои плейлсты. Откроем файл get_music_data и напишем функцию get_liked_playlists_data() , которая создает словарь с ID лайкнутых плейлистов, их названиями и именами пользователей, создавших плейлист.
Здесь мы переходим на страницу своих плейлистов, извлекаем содержимое из массива Mu и создаем словарь с ID плейлиста, его названием и именем пользователя создавшего плейлист.
Теперь напишем функцию get_liked_playlists() , которая переходит на страничку лайкнутых плейлистов и получает названия треков и исполнителей
В этом блоке кода мы:
- Переходим на страницу плейлиста.
- Получаем ID треков в формате ID_трека:ID_альбома .
- С помощью регулярного выражения получаем ID трека.
- Переходим на страницу трека.
- Получаем название трека и имя исполнителя.
- Записываем в словарь название плейлиста, его треки и имена исполнителей.
Лайкнутые плейлисты переносим через функцию transfer_playlsits() .
Запускаем миграцию музыки
В конце файла transfer.py напишем функцию main() , которая перенесет всю фонотеку в Спотифай.
Альбомы переносятся так:
Мы написали скрипт для переноса всей фонотеки из Яндекс.Музыки в Спотифай и научились: