Last active
May 26, 2024 15:38
-
-
Save tirinox/e53943764f4e445e31b0a940c47560a9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# полный код | |
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