import asyncio import json from collections import defaultdict from itertools import chain from typing import List, Optional, Tuple, TypedDict import aiohttp from bs4 import BeautifulSoup """ This file scrapes disney songs + lyrics from "https://www.disneyclips.com/lyrics/" """ # Base URL for scraping Disney lyrics URL = "https://www.disneyclips.com/lyrics/" # Function to get song names and URLs from a given movie URL async def get_lyrics_names_and_urls_from_movie_url( movie_name: str, url: str, session: aiohttp.ClientSession ) -> List[Tuple[str, str]]: async with session.get(url) as response: html = await response.text() soup = BeautifulSoup(html, "html.parser") table = soup.find("table", {"class": "songs"}) names_and_urls = [] if table: links = table.find_all("a") names_and_urls = [] for link in links: names_and_urls.append( (movie_name, link.text, f"{URL}/{link.get('href')}") ) return names_and_urls # Function to extract lyrics from a given lyric URL async def get_lyric_from_lyric_url( movie_name: str, lyric_name: str, url: str, session: aiohttp.ClientSession ) -> str: async with session.get(url) as response: html = await response.text() soup = BeautifulSoup(html, "html.parser") div = soup.find("div", {"id": "cnt"}).find("div", {"class": "main"}) paragraphs = div.find_all("p") text = "" # first
has the lyric p = paragraphs[0] for br in p.find_all("br"): br.replace_with(". ") for span in p.find_all("span"): span.decompose() text += p.text return (movie_name, lyric_name, text) # Function to get movie names and URLs async def get_movie_names_and_urls( session: aiohttp.ClientSession, ) -> List[Tuple[str, str]]: async with session.get(URL) as response: html = await response.text() soup = BeautifulSoup(html, "html.parser") links = ( soup.find("div", {"id": "cnt"}).find("div", {"class": "main"}).find_all("a") ) movie_names_and_urls = [ (link.text, f"{URL}/{link.get('href')}") for link in links ] return movie_names_and_urls # Main function to scrape Disney lyrics async def scrape_disney_lyrics(): async with aiohttp.ClientSession() as session: data = await get_movie_names_and_urls(session) data = await asyncio.gather( *[ asyncio.create_task( get_lyrics_names_and_urls_from_movie_url(*el, session) ) for el in data ] ) data = await asyncio.gather( *[ asyncio.create_task(get_lyric_from_lyric_url(*data, session)) for data in chain(*data) ] ) result = defaultdict(list) for movie_name, lyric_name, lyric_text in data: result[movie_name].append({"name": lyric_name, "text": lyric_text}) with open("data/lyrics.json", "w") as f: json.dump(result, f) # Run the scraping function loop = asyncio.get_event_loop() loop.run_until_complete(scrape_disney_lyrics())