import requests import pandas as pd from bs4 import BeautifulSoup from typing import List, Tuple from . import persist # =============================== # SCREENER MAP (OWNER) # =============================== SCREENER_MAP = { "from_high": "https://www.screener.in/screens/3355081/from-high/", "sales_wise": "https://www.screener.in/screens/880780/sales_wise/", "fii_buying": "https://www.screener.in/screens/343087/fii-buying/", "debt_reduction": "https://www.screener.in/screens/126864/debt-reduction/", "magic_formula": "https://www.screener.in/screens/59/magic-formula/", } # =============================== # Public API # =============================== def fetch_screener(screen_name: str) -> str: """ Returns a fully styled HTML table for a given screener name. Uses disk persistence (HTML primary, CSV secondary). """ url = SCREENER_MAP.get(screen_name) if not url: return _error_html(f"Invalid screener: {screen_name}") cache_name = f"SCREENER_{screen_name.upper()}" # 1️⃣ Cache hit if persist.exists(cache_name, "html"): return persist.load(cache_name, "html") # 2️⃣ Fetch live headers, rows = _fetch_table(url) if not headers or not rows: return _error_html("No data available") # 3️⃣ Build outputs html = _build_html(headers, rows) csv_df = pd.DataFrame(rows, columns=headers) # 4️⃣ Persist persist.save(cache_name, html, "html") persist.save(cache_name, csv_df, "csv") return html # =============================== # Internal helpers # =============================== def _fetch_table(url: str) -> Tuple[List[str], List[List[str]]]: r = requests.get( url, headers={"User-Agent": "Mozilla/5.0"}, timeout=15 ) r.raise_for_status() soup = BeautifulSoup(r.text, "html.parser") table = soup.find("table") if not table: return [], [] thead = table.find("thead") header_row = thead.find("tr") if thead else table.find("tr") headers = [th.get_text(strip=True) for th in header_row.find_all("th")] rows = [] for tr in table.find_all("tr")[1:]: cells = tr.find_all("td") if cells: rows.append([td.get_text(strip=True) for td in cells]) return headers, rows def _build_html(headers: List[str], rows: List[List[str]]) -> str: style = """ """ html = [style, "
| {h} | ") html.append("
|---|
| {cell} | ") html.append("