Skip to content

Instantly share code, notes, and snippets.

@snnwolf
Last active August 29, 2015 14:10
Show Gist options
  • Save snnwolf/bb6a059e60a7a6545164 to your computer and use it in GitHub Desktop.
Save snnwolf/bb6a059e60a7a6545164 to your computer and use it in GitHub Desktop.
Скрипт для скачивания музыки из vk.com. 2 варианта: 1) через нити и очереди; 2) через нити и семафоры. Пожалуй с очередями правильнее!!!
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Скрипт для скачивания музыки с сайта vkontakte.ru (vk.com)
Запуск:
python vkcom_audio_download.py
Принцип работы:
Скрипт проверяет сохраненный access_token. Если его нет или срок истек,
то открывается страница в браузере с запросом на доступ к аккаунту.
После подтверждения идет редирект на https://oauth.vk.com/blank.htm#... .
Нужно скопировать весь url, на который вас редиректнуло и вставить его
в консоль скрипта.
Далее будут скачиваться все ваши аудиозаписи. Если аудиозапись уже есть на
диске - то скачивания не происходит.
Будут запрошены ваши данные приложением с app_id = 3358129
Можно создать свое Standalone-приложение с доступом к аудио здесь:
http://vk.com/editapp?act=create
И заменить APP_ID на ваше.
"""
import webbrowser
import pickle
import json
import urllib
import urllib2
import HTMLParser
import re
import os
import urlparse
from pprint import pprint
import threading
import Queue
from datetime import datetime, timedelta
import time
import logging
logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] (%(threadName)-10s) %(message)s')
# id of vk.com application, that has access to audio
APP_ID = '4650301'
# if None, then save mp3 in current folder
MUSIC_FOLDER = None
# file, where auth data is saved
AUTH_FILE = '.auth_data'
# chars to exclude from filename
FORBIDDEN_CHARS = '/\\\?%*:|"<>!'
# кол-во потоков
THREAD_COUNT = 4
def get_saved_auth_params():
access_token = None
user_id = None
try:
with open(AUTH_FILE, 'rb') as pkl_file:
token = pickle.load(pkl_file)
expires = pickle.load(pkl_file)
uid = pickle.load(pkl_file)
if datetime.now() < expires:
access_token = token
user_id = uid
except IOError:
pass
return access_token, user_id
def save_auth_params(access_token, expires_in, user_id):
expires = datetime.now() + timedelta(seconds=int(expires_in))
with open(AUTH_FILE, 'wb') as output:
pickle.dump(access_token, output)
pickle.dump(expires, output)
pickle.dump(user_id, output)
def get_auth_params():
auth_url = ("https://oauth.vk.com/authorize?client_id={app_id}"
"&scope=audio&redirect_uri=http://oauth.vk.com/blank.html"
"&display=page&response_type=token".format(app_id=APP_ID))
webbrowser.open_new_tab(auth_url)
redirected_url = raw_input("Paste here url you were redirected:\n")
aup = urlparse.parse_qs(redirected_url)
aup['access_token'] = aup.pop(
'https://oauth.vk.com/blank.html#access_token')
save_auth_params(aup['access_token'][0], aup['expires_in'][0],
aup['user_id'][0])
return aup['access_token'][0], aup['user_id'][0]
def get_tracks_metadata(access_token, user_id):
url = ("https://api.vkontakte.ru/method/audio.get.json?"
"uid={uid}&access_token={atoken}".format(
uid=user_id, atoken=access_token))
audio_get_page = urllib2.urlopen(url).read()
return json.loads(audio_get_page)['response']
def get_track_full_name(t_data):
html_parser = HTMLParser.HTMLParser()
full_name = u"{0}_{1}".format(
html_parser.unescape(t_data['artist'][:100]).strip(),
html_parser.unescape(t_data['title'][:100]).strip(),
)
full_name = re.sub('[' + FORBIDDEN_CHARS + ']', "", full_name)
full_name = re.sub(' +', ' ', full_name)
return full_name + ".mp3"
# def Thread(f):
# """"
# Декорат для скачивания
# Для ограничения можно использовать семафоры
# """
# def _inside(*a, **k):
# thr = threading.Thread(target = f, args = a, kwargs = k)
# thr.start()
# return _inside
# @Thread
def download_track(t_url, t_name):
# with semaphore:
t_path = os.path.join(MUSIC_FOLDER or "", t_name)
if not os.path.exists(t_path):
logging.info(u"Downloading {0}".format(t_name))
urllib.urlretrieve(t_url, t_path)
logging.info(u'Finish {0}'.format(t_name))
class Consumer(threading.Thread):
def __init__(self, task_queue):
threading.Thread.__init__(self)
self.task_queue = task_queue
def run(self):
while True:
next_task = self.task_queue.get()
if next_task is None:
# Poison pill means we should exit
logging.info('Exiting')
break
# logger.info('%s: %s' % (proc_name, next_task)
t_url, t_name = next_task
download_track(t_url, t_name)
return
def main():
access_token, user_id = get_saved_auth_params()
if not access_token or not user_id:
access_token, user_id = get_auth_params()
tracks = get_tracks_metadata(access_token, user_id)
if MUSIC_FOLDER and not os.path.exists(MUSIC_FOLDER):
os.makedirs(MUSIC_FOLDER)
semaphore = threading.Semaphore(4)
tasks = Queue.Queue()
jobs = [Consumer(tasks) for i in xrange(THREAD_COUNT)]
for w in jobs:
w.daemon = True
w.start()
for t in tracks:
t_name = get_track_full_name(t)
# download_track(t['url'], t_name, semaphore)
tasks.put((t['url'], t_name))
for i in xrange(THREAD_COUNT):
tasks.put(None)
# http://stackoverflow.com/questions/11815947/cannot-kill-python-script-with-ctrl-c
try:
while threading.active_count() > 1:
print 'threads:', threading.active_count(), [n.name for n in threading.enumerate()]
time.sleep(5)
except KeyboardInterrupt:
print ''
logging.info("Adieu")
if __name__ == '__main__':
main()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Скрипт для скачивания музыки с сайта vkontakte.ru (vk.com)
Запуск:
python vkcom_audio_download.py
Принцип работы:
Скрипт проверяет сохраненный access_token. Если его нет или срок истек,
то открывается страница в браузере с запросом на доступ к аккаунту.
После подтверждения идет редирект на https://oauth.vk.com/blank.htm#... .
Нужно скопировать весь url, на который вас редиректнуло и вставить его
в консоль скрипта.
Далее будут скачиваться все ваши аудиозаписи. Если аудиозапись уже есть на
диске - то скачивания не происходит.
Будут запрошены ваши данные приложением с app_id = 3358129
Можно создать свое Standalone-приложение с доступом к аудио здесь:
http://vk.com/editapp?act=create
И заменить APP_ID на ваше.
"""
import webbrowser
import pickle
import json
import urllib
import urllib2
import HTMLParser
import re
import os
import urlparse
from pprint import pprint
import threading
import Queue
from datetime import datetime, timedelta
import time
import logging
logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] (%(threadName)-10s) %(message)s')
# id of vk.com application, that has access to audio
APP_ID = '4650301'
# if None, then save mp3 in current folder
MUSIC_FOLDER = None
# file, where auth data is saved
AUTH_FILE = '.auth_data'
# chars to exclude from filename
FORBIDDEN_CHARS = '/\\\?%*:|"<>!'
# кол-во потоков
THREAD_COUNT = 4
def get_saved_auth_params():
access_token = None
user_id = None
try:
with open(AUTH_FILE, 'rb') as pkl_file:
token = pickle.load(pkl_file)
expires = pickle.load(pkl_file)
uid = pickle.load(pkl_file)
if datetime.now() < expires:
access_token = token
user_id = uid
except IOError:
pass
return access_token, user_id
def save_auth_params(access_token, expires_in, user_id):
expires = datetime.now() + timedelta(seconds=int(expires_in))
with open(AUTH_FILE, 'wb') as output:
pickle.dump(access_token, output)
pickle.dump(expires, output)
pickle.dump(user_id, output)
def get_auth_params():
auth_url = ("https://oauth.vk.com/authorize?client_id={app_id}"
"&scope=audio&redirect_uri=http://oauth.vk.com/blank.html"
"&display=page&response_type=token".format(app_id=APP_ID))
webbrowser.open_new_tab(auth_url)
redirected_url = raw_input("Paste here url you were redirected:\n")
aup = urlparse.parse_qs(redirected_url)
aup['access_token'] = aup.pop(
'https://oauth.vk.com/blank.html#access_token')
save_auth_params(aup['access_token'][0], aup['expires_in'][0],
aup['user_id'][0])
return aup['access_token'][0], aup['user_id'][0]
def get_tracks_metadata(access_token, user_id):
url = ("https://api.vkontakte.ru/method/audio.get.json?"
"uid={uid}&access_token={atoken}".format(
uid=user_id, atoken=access_token))
audio_get_page = urllib2.urlopen(url).read()
return json.loads(audio_get_page)['response']
def get_track_full_name(t_data):
html_parser = HTMLParser.HTMLParser()
full_name = u"{0}_{1}".format(
html_parser.unescape(t_data['artist'][:100]).strip(),
html_parser.unescape(t_data['title'][:100]).strip(),
)
full_name = re.sub('[' + FORBIDDEN_CHARS + ']', "", full_name)
full_name = re.sub(' +', ' ', full_name)
return full_name + ".mp3"
def Thread(f):
""""
Декоратор для скачивания.
Для ограничения можно использовать семафоры.
Все процессы демонизируются. Поэтому в основной программе нужно добавить
while threading.active_count() > 1:
time.sleep(1)
"""
def _inside(*a, **k):
thr = threading.Thread(target = f, args = a, kwargs = k)
thr.daemon = True
thr.start()
return _inside
@Thread
def download_track(t_url, t_name, semaphore):
with semaphore:
t_path = os.path.join(MUSIC_FOLDER or "", t_name)
if not os.path.exists(t_path):
logging.info(u"Downloading {0}".format(t_name))
urllib.urlretrieve(t_url, t_path)
logging.info(u'Finish {0}'.format(t_name))
def main():
access_token, user_id = get_saved_auth_params()
if not access_token or not user_id:
access_token, user_id = get_auth_params()
tracks = get_tracks_metadata(access_token, user_id)
if MUSIC_FOLDER and not os.path.exists(MUSIC_FOLDER):
os.makedirs(MUSIC_FOLDER)
semaphore = threading.Semaphore(4)
for t in tracks:
t_name = get_track_full_name(t)
download_track(t['url'], t_name, semaphore)
# http://stackoverflow.com/questions/11815947/cannot-kill-python-script-with-ctrl-c
try:
while threading.active_count() > 1:
print 'threads:', threading.active_count() #, [n.name for n in threading.enumerate()]
time.sleep(1)
except KeyboardInterrupt:
print ''
print("Adieu")
else:
print('All files downloaded')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment