diff --git a/beatport_unified_scraper.py b/beatport_unified_scraper.py index eced8d24..3983a891 100644 --- a/beatport_unified_scraper.py +++ b/beatport_unified_scraper.py @@ -7,6 +7,8 @@ Focused on extracting clean artist and track names for virtual playlists import requests from bs4 import BeautifulSoup import json +import logging +import os import time import re from urllib.parse import urljoin @@ -14,6 +16,39 @@ from typing import Dict, List, Optional import concurrent.futures from threading import Lock +from utils.logging_config import get_logger + + +logger = get_logger("beatport_scraper") +_BEATPORT_LOGGING_ENABLED = os.environ.get("SOULSYNC_BEATPORT_SCRAPER_LOGS", "").lower() in ("1", "true", "yes", "on") +if _BEATPORT_LOGGING_ENABLED: + logger.setLevel(logging.DEBUG) +else: + logger.setLevel(logging.CRITICAL + 1) + +def _beatport_log(message: str): + """Route scraper output through logging when explicitly enabled.""" + if not _BEATPORT_LOGGING_ENABLED: + return + + text = str(message) + stripped = text.strip() + + if not stripped: + return + + lowered = stripped.lower() + level = logging.DEBUG + + if lowered.startswith("error") or " exception" in lowered or lowered.startswith("failed") or " failed" in lowered: + level = logging.ERROR + elif lowered.startswith("could not") or lowered.startswith("couldn't"): + level = logging.WARNING + elif lowered.startswith("no ") and "found" not in lowered: + level = logging.WARNING + + logger.log(level, text) + class BeatportUnifiedScraper: def __init__(self): self.base_url = "https://beatport.com" @@ -127,7 +162,7 @@ class BeatportUnifiedScraper: response.raise_for_status() return BeautifulSoup(response.content, 'html.parser') except requests.RequestException as e: - print(f"Error fetching {url}: {e}") + _beatport_log(f"Error fetching {url}: {e}") return None def clean_artist_track_data(self, raw_artist: str, raw_title: str) -> Dict[str, str]: @@ -171,12 +206,12 @@ class BeatportUnifiedScraper: def discover_genres_from_homepage(self) -> List[Dict]: """Dynamically discover all genres from Beatport homepage dropdown""" - print("Discovering genres from Beatport homepage...") + _beatport_log("Discovering genres from Beatport homepage...") try: soup = self.get_page(self.base_url) if not soup: - print("Could not fetch homepage") + _beatport_log("Could not fetch homepage") return self.fallback_genres genres = [] @@ -185,14 +220,14 @@ class BeatportUnifiedScraper: genres_dropdown = soup.find('div', {'id': 'genres-dropdown-menu'}) if genres_dropdown: - print("Found genres-dropdown-menu") + _beatport_log("Found genres-dropdown-menu") # Look for the two main div containers as described genre_containers = genres_dropdown.find_all('div', recursive=False) - print(f"Found {len(genre_containers)} top-level containers in dropdown") + _beatport_log(f"Found {len(genre_containers)} top-level containers in dropdown") for container_idx, container in enumerate(genre_containers): - print(f"Processing container {container_idx + 1}") + _beatport_log(f"Processing container {container_idx + 1}") # Look specifically for .dropdown_menu classes dropdown_menus = container.find_all(class_='dropdown_menu') @@ -202,17 +237,17 @@ class BeatportUnifiedScraper: dropdown_menus = container.find_all(class_=re.compile(r'dropdown.*menu', re.I)) if not dropdown_menus: - print(f"No .dropdown_menu found in container {container_idx + 1}") + _beatport_log(f"No .dropdown_menu found in container {container_idx + 1}") continue for menu_idx, menu in enumerate(dropdown_menus): - print(f"Processing dropdown_menu {menu_idx + 1} in container {container_idx + 1}") + _beatport_log(f"Processing dropdown_menu {menu_idx + 1} in container {container_idx + 1}") # Look for