From cca24ea39037412a9535e7316ee4e304ad6778cb Mon Sep 17 00:00:00 2001 From: Ivan Semkin Date: Fri, 3 Nov 2017 15:24:58 +0300 Subject: [PATCH 1/6] Add support for downloading Music Albums --- examples/get_album_audio.py | 54 +++++++++++++++++++++++++++++++++++++ vk_api/audio.py | 21 +++++++++++---- 2 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 examples/get_album_audio.py diff --git a/examples/get_album_audio.py b/examples/get_album_audio.py new file mode 100644 index 00000000..42a6072a --- /dev/null +++ b/examples/get_album_audio.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +import collections + +import vk_api +from vk_api.audio import VkAudio + + +def main(): + """ Пример составления топа исполнителей для альбома вк """ + + login, password = 'login', 'password' + vk_session = vk_api.VkApi(login, password) + + try: + vk_session.auth() + except vk_api.AuthError as error_msg: + print(error_msg) + return + + vkaudio = VkAudio(vk_session) + + artists = collections.Counter() + + offset = 0 + + while True: + audios = vkaudio.get(album_id='-89975290_74038117', offset=offset) + + if not audios: + break + + for audio in audios: + artists[audio['artist']] += 1 + + offset += len(audios) + + # Составляем рейтинг первых 15 + print('\nTop 15:') + for artist, tracks in artists.most_common(15): + print('{} - {} tracks'.format(artist, tracks)) + + # Ищем треки самого популярного + most_common_artist = artists.most_common(1)[0][0] + + print('\nSearch for', most_common_artist) + + tracks = vkaudio.search(q=most_common_artist)[:10] + + for n, track in enumerate(tracks, 1): + print('{}. {} {}'.format(n, track['title'], track['url'])) + + +if __name__ == '__main__': + main() diff --git a/vk_api/audio.py b/vk_api/audio.py index 0c19e86b..bc1e3a59 100644 --- a/vk_api/audio.py +++ b/vk_api/audio.py @@ -16,15 +16,27 @@ class VkAudio: def __init__(self, vk): self._vk = vk - def get(self, owner_id, offset=0): + def get(self, owner_id=None, album_id=None, offset=0): """ Получить список аудиозаписей пользователя :param owner_id: ID владельца (отрицательные значения для групп) + :param album_id: ID альбома (отрицательные значения для групп) :param offset: смещение """ + if owner_id is None and album_id is None: + raise TypeError("get() missing 1 required argument: 'album_id' or 'owner_id'") + elif owner_id is not None and album_id is not None: + raise TypeError("get() too many arguments") + + id = owner_id + url = "https://m.vk.com/audios{}" + if album_id is not None: + id = album_id + url = "https://m.vk.com/audio?act=audio_playlist{}" + response = self._vk.http.get( - 'https://m.vk.com/audios{}'.format(owner_id), + url.format(id), params={ 'offset': offset }, @@ -34,7 +46,7 @@ def get(self, owner_id, offset=0): if not response.text: raise AccessDenied( 'You don\'t have permissions to browse {}\'s audio'.format( - owner_id + id ) ) @@ -92,8 +104,7 @@ def scrap_data(html): soup = BeautifulSoup(html, 'html.parser') tracks = [] - - for audio in soup.find_all('div', {'class': 'audio_item ai_has_btn'}): + for audio in soup.find_all('div', {'class': 'audio_item'}): ai_artist = audio.select('.ai_artist') artist = ai_artist[0].text link = audio.select('.ai_body')[0].input['value'] From fbd35b589c8bfdf93dd5d1feef6b8430ba4167f6 Mon Sep 17 00:00:00 2001 From: Ivan Semkin Date: Fri, 10 Nov 2017 08:30:34 +0300 Subject: [PATCH 2/6] Fix formatting issues --- vk_api/audio.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/vk_api/audio.py b/vk_api/audio.py index bc1e3a59..00ebe60f 100644 --- a/vk_api/audio.py +++ b/vk_api/audio.py @@ -25,15 +25,17 @@ def get(self, owner_id=None, album_id=None, offset=0): """ if owner_id is None and album_id is None: - raise TypeError("get() missing 1 required argument: 'album_id' or 'owner_id'") + raise TypeError( + 'get() missing 1 required argument: album_id or owner_id' + ) elif owner_id is not None and album_id is not None: - raise TypeError("get() too many arguments") + raise TypeError('get() too many arguments') id = owner_id - url = "https://m.vk.com/audios{}" + url = 'https://m.vk.com/audios{}' if album_id is not None: id = album_id - url = "https://m.vk.com/audio?act=audio_playlist{}" + url = 'https://m.vk.com/audio?act=audio_playlist{}' response = self._vk.http.get( url.format(id), From 58d127598904dd47daaa90f05074c45e5c7b4fe9 Mon Sep 17 00:00:00 2001 From: Ivan Semkin Date: Sat, 11 Nov 2017 01:11:25 +0300 Subject: [PATCH 3/6] Add albums parsing --- examples/get_album_audio.py | 19 +++++++++---------- vk_api/audio.py | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/examples/get_album_audio.py b/examples/get_album_audio.py index 42a6072a..2d2d2763 100644 --- a/examples/get_album_audio.py +++ b/examples/get_album_audio.py @@ -24,27 +24,26 @@ def main(): offset = 0 while True: - audios = vkaudio.get(album_id='-89975290_74038117', offset=offset) + albums = vkaudio.get(owner_id='194957739', get_albums=True, offset=offset) - if not audios: + if not albums: break - for audio in audios: - artists[audio['artist']] += 1 + for album in albums: + artists[album['artist']] += 1 - offset += len(audios) + offset += len(albums) # Составляем рейтинг первых 15 print('\nTop 15:') for artist, tracks in artists.most_common(15): print('{} - {} tracks'.format(artist, tracks)) - # Ищем треки самого популярного - most_common_artist = artists.most_common(1)[0][0] + # Ищем треки последнего альбома + album = vkaudio.get(owner_id='194957739', get_albums=True)[0] + print('\nSearch for', album['title']) - print('\nSearch for', most_common_artist) - - tracks = vkaudio.search(q=most_common_artist)[:10] + tracks = vkaudio.get(album_id=album['id'][25:]) for n, track in enumerate(tracks, 1): print('{}. {} {}'.format(n, track['title'], track['url'])) diff --git a/vk_api/audio.py b/vk_api/audio.py index 00ebe60f..728a20fb 100644 --- a/vk_api/audio.py +++ b/vk_api/audio.py @@ -6,7 +6,7 @@ from .audio_url_decoder import decode_audio_url from .exceptions import AccessDenied -RE_AUDIO = re.compile(r'audio\d+_\d+_audios\d+') +RE_AUDIO = re.compile(r'audio[-\d]+_\d+_audios\d+') class VkAudio: @@ -30,12 +30,16 @@ def get(self, owner_id=None, album_id=None, offset=0): ) elif owner_id is not None and album_id is not None: raise TypeError('get() too many arguments') + if album_id is not None and get_albums is True: + raise TypeError('get() too many arguments') id = owner_id url = 'https://m.vk.com/audios{}' if album_id is not None: id = album_id url = 'https://m.vk.com/audio?act=audio_playlist{}' + if get_albums is True: + url = 'https://m.vk.com/audio?act=audio_playlists{}' response = self._vk.http.get( url.format(id), @@ -52,6 +56,8 @@ def get(self, owner_id=None, album_id=None, offset=0): ) ) + if get_albums: + return scrap_albums(response.text) return scrap_data(response.text) def search_user(self, owner_id, q=''): @@ -123,3 +129,22 @@ def scrap_data(html): }) return tracks + + +def scrap_albums(html): + """ Парсинг списка альбомов из html странцы """ + + soup = BeautifulSoup(html, 'html.parser') + albums = [] + for album in soup.find_all('div', {'class': 'audioPlaylistsPage__item'}): + link = album.select('.audioPlaylistsPage__itemLink')[0]['href'] + + albums.append({ + 'artist': album.select('.audioPlaylistsPage__author')[0].text, + 'title': album.select('.audioPlaylistsPage__title')[0].text, + 'plays': album.select('.audioPlaylistsPage__stats')[0].text, + 'id': album['class'][1], + 'url': 'https://m.vk.com/audio?act=audio_playlist{}'.format(link) + }) + + return albums From 7e198b9aee1252306de6b6066640fbc39525e9a4 Mon Sep 17 00:00:00 2001 From: Ivan Semkin Date: Sun, 12 Nov 2017 04:08:07 +0300 Subject: [PATCH 4/6] Split albums / songs searching into separate methods --- examples/get_album_audio.py | 2 +- vk_api/audio.py | 38 +++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/examples/get_album_audio.py b/examples/get_album_audio.py index 2d2d2763..4488fed7 100644 --- a/examples/get_album_audio.py +++ b/examples/get_album_audio.py @@ -24,7 +24,7 @@ def main(): offset = 0 while True: - albums = vkaudio.get(owner_id='194957739', get_albums=True, offset=offset) + albums = vkaudio.get_albums(owner_id='194957739', offset=offset) if not albums: break diff --git a/vk_api/audio.py b/vk_api/audio.py index 728a20fb..a519400b 100644 --- a/vk_api/audio.py +++ b/vk_api/audio.py @@ -30,19 +30,15 @@ def get(self, owner_id=None, album_id=None, offset=0): ) elif owner_id is not None and album_id is not None: raise TypeError('get() too many arguments') - if album_id is not None and get_albums is True: - raise TypeError('get() too many arguments') - id = owner_id + user_id = owner_id url = 'https://m.vk.com/audios{}' if album_id is not None: - id = album_id + user_id = album_id url = 'https://m.vk.com/audio?act=audio_playlist{}' - if get_albums is True: - url = 'https://m.vk.com/audio?act=audio_playlists{}' response = self._vk.http.get( - url.format(id), + url.format(user_id), params={ 'offset': offset }, @@ -52,14 +48,36 @@ def get(self, owner_id=None, album_id=None, offset=0): if not response.text: raise AccessDenied( 'You don\'t have permissions to browse {}\'s audio'.format( - id + user_id ) ) - if get_albums: - return scrap_albums(response.text) return scrap_data(response.text) + def get_albums(self, owner_id, offset=0): + """ Получить список альбомов пользователя + + :param owner_id: ID владельца (отрицательные значения для групп) + :param offset: смещение + """ + + response = self._vk.http.get( + 'https://m.vk.com/audio?act=audio_playlists{}'.format(owner_id), + params={ + 'offset': offset + }, + allow_redirects=False + ) + + if not response.text: + raise AccessDenied( + 'You don\'t have permissions to browse {}\'s albums'.format( + owner_id + ) + ) + + return scrap_albums(response.text) + def search_user(self, owner_id, q=''): """ Искать по аудиозаписям пользователя From 3c8782b956cc5b92e1ec85d0acc92820043ad493 Mon Sep 17 00:00:00 2001 From: Ivan Semkin Date: Sun, 12 Nov 2017 15:21:59 +0300 Subject: [PATCH 5/6] Improve albums example --- examples/get_album_audio.py | 26 +++++++++++--------------- vk_api/audio.py | 13 +++++-------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/examples/get_album_audio.py b/examples/get_album_audio.py index 4488fed7..d32c36a2 100644 --- a/examples/get_album_audio.py +++ b/examples/get_album_audio.py @@ -19,31 +19,27 @@ def main(): vkaudio = VkAudio(vk_session) - artists = collections.Counter() - + albums = [] offset = 0 while True: - albums = vkaudio.get_albums(owner_id='194957739', offset=offset) + temp_albums = vkaudio.get_albums(owner_id='194957739', offset=offset) - if not albums: + if not temp_albums: break - for album in albums: - artists[album['artist']] += 1 + for album in temp_albums: + albums.append(album) - offset += len(albums) + offset += len(temp_albums) - # Составляем рейтинг первых 15 - print('\nTop 15:') - for artist, tracks in artists.most_common(15): - print('{} - {} tracks'.format(artist, tracks)) + print('\nLast 5:') + for album in albums[:5]: + print(album['title']) # Ищем треки последнего альбома - album = vkaudio.get(owner_id='194957739', get_albums=True)[0] - print('\nSearch for', album['title']) - - tracks = vkaudio.get(album_id=album['id'][25:]) + print('\nSearch for', albums[0]['title']) + tracks = vkaudio.get(album_id=albums[0]['id'][25:]) for n, track in enumerate(tracks, 1): print('{}. {} {}'.format(n, track['title'], track['url'])) diff --git a/vk_api/audio.py b/vk_api/audio.py index a519400b..d840df2f 100644 --- a/vk_api/audio.py +++ b/vk_api/audio.py @@ -31,14 +31,13 @@ def get(self, owner_id=None, album_id=None, offset=0): elif owner_id is not None and album_id is not None: raise TypeError('get() too many arguments') - user_id = owner_id - url = 'https://m.vk.com/audios{}' if album_id is not None: - user_id = album_id - url = 'https://m.vk.com/audio?act=audio_playlist{}' + url = 'https://m.vk.com/audio?act=audio_playlist{}'.format(album_id) + else: + url = 'https://m.vk.com/audios{}'.format(owner_id) response = self._vk.http.get( - url.format(user_id), + url, params={ 'offset': offset }, @@ -47,9 +46,7 @@ def get(self, owner_id=None, album_id=None, offset=0): if not response.text: raise AccessDenied( - 'You don\'t have permissions to browse {}\'s audio'.format( - user_id - ) + 'You don\'t have permissions to browse user\'s audio' ) return scrap_data(response.text) From af9500bc76c3258916cc0dc5a149faf82c7d197c Mon Sep 17 00:00:00 2001 From: Ivan Semkin Date: Mon, 13 Nov 2017 02:08:49 +0300 Subject: [PATCH 6/6] Final improvements --- examples/get_album_audio.py | 8 +++----- vk_api/audio.py | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/get_album_audio.py b/examples/get_album_audio.py index d32c36a2..4dd3302a 100644 --- a/examples/get_album_audio.py +++ b/examples/get_album_audio.py @@ -6,7 +6,7 @@ def main(): - """ Пример составления топа исполнителей для альбома вк """ + """ Пример отображения 5 последних альбомов пользователя """ login, password = 'login', 'password' vk_session = vk_api.VkApi(login, password) @@ -28,9 +28,7 @@ def main(): if not temp_albums: break - for album in temp_albums: - albums.append(album) - + albums += temp_albums offset += len(temp_albums) print('\nLast 5:') @@ -39,7 +37,7 @@ def main(): # Ищем треки последнего альбома print('\nSearch for', albums[0]['title']) - tracks = vkaudio.get(album_id=albums[0]['id'][25:]) + tracks = vkaudio.get(album_id=albums[0]['id']) for n, track in enumerate(tracks, 1): print('{}. {} {}'.format(n, track['title'], track['url'])) diff --git a/vk_api/audio.py b/vk_api/audio.py index d840df2f..e3ed2481 100644 --- a/vk_api/audio.py +++ b/vk_api/audio.py @@ -158,7 +158,7 @@ def scrap_albums(html): 'artist': album.select('.audioPlaylistsPage__author')[0].text, 'title': album.select('.audioPlaylistsPage__title')[0].text, 'plays': album.select('.audioPlaylistsPage__stats')[0].text, - 'id': album['class'][1], + 'id': album['class'][1][25:], 'url': 'https://m.vk.com/audio?act=audio_playlist{}'.format(link) })