Skip to content

Instantly share code, notes, and snippets.

@tirinox
Last active May 26, 2024 15:38
Show Gist options
  • Save tirinox/e53943764f4e445e31b0a940c47560a9 to your computer and use it in GitHub Desktop.
Save tirinox/e53943764f4e445e31b0a940c47560a9 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
# полный код
from multiprocessing import Pool
import requests
from urllib.parse import urlparse
from bs4 import BeautifulSoup
from functools import wraps
import time
import os
# генератор страниц, с которых мы будем качать музыку
def page_generator():
for i in range(1, 16):
yield f'http://music.lib.ru/janr/index_janr_23-{i}.shtml'
# куда будем сохранять музыку локально
DOWNLOAD_TO = os.path.expanduser('~/Downloads/music_lib_ru_test')
# декоратор, который делает несколько попыток выполнить функцию
def retry(tries=4, delay=3):
def deco_retry(f):
@wraps(f)
def f_retry(*args, **kwargs):
for _ in range(tries):
try:
return f(*args, **kwargs)
except:
time.sleep(delay)
return f(*args, **kwargs)
return f_retry
return deco_retry
def is_music(href: str):
href = href.lower()
for ext in ['.mp3', '.wma', '.ogg']:
if href.endswith(ext):
return True
return False
def all_links(html):
soup = BeautifulSoup(html, 'html.parser')
all_a = soup.find_all('a')
yield from map(lambda el: el.get('href'), all_a)
@retry(5)
def do_page(page_url):
print(f'Downloading list: {page_url}')
html = requests.get(page_url).text
links = all_links(html)
music_links = filter(is_music, links)
return list(music_links)
def flatten(l):
return [item for sublist in l for item in sublist]
@retry(5)
def download_music_piece(url, i, total, download_to):
"""
url - ссылка
i - номер песни (для отображения прогресса)
total - всего песен
download_to - каталог, куда сохранить
"""
print(f'[{i:6} / {total:6}] {url}')
# парсим URL, чтобы достать оригинальное имя файла
original_path = urlparse(url).path
original_path = original_path[1:] # убираем передний слэш / (это важно!)
# чисто имя файла
filename = os.path.basename(original_path)
# будущий локальный каталог файла
dirname = os.path.join(download_to, os.path.dirname(original_path))
# полное локальное имя файла
full_local_path = os.path.join(dirname, filename)
# проверка, не скачали ли мы уже этот файл ранее (если да, пропускаем)
if not os.path.isfile(full_local_path):
# создадим каталог для него, если еще нет
os.makedirs(dirname, exist_ok=True)
# открываем локлаьный файл для записи бинарно
with open(full_local_path, 'wb') as f:
# делаем запрос на скачивание
r = requests.get(url)
if r.status_code == 200:
# если ответ ОК (200), то все кусочки пишем в файл
for c in r:
f.write(c)
if __name__ == '__main__':
os.makedirs(DOWNLOAD_TO, exist_ok=True)
pool = Pool(4)
mp3_urls = flatten(pool.map(do_page, page_generator()))
total = len(mp3_urls)
mp3_urls = [(url, i, total, DOWNLOAD_TO) for i, url in enumerate(mp3_urls, start=1)]
pool.starmap(download_music_piece, mp3_urls)
print('All done!')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment