Spaces:
Runtime error
Runtime error
Download src/streamlit_app.py from jayanth-2005/Extractor: direct link, hf CLI and curl.
- Browser
- Download file 4.26 kB
-
https://huggingface.co/spaces/jayanth-2005/Extractor/resolve/main/src/streamlit_app.py
- Command line
-
hf download hf://spaces/jayanth-2005/Extractor/src/streamlit_app.py
-
curl -L -o streamlit_app.py https://huggingface.co/spaces/jayanth-2005/Extractor/resolve/main/src/streamlit_app.py
4.26 kB
| import streamlit as st | |
| import requests | |
| from bs4 import BeautifulSoup | |
| import pandas as pd | |
| import re | |
| from urllib.parse import urljoin | |
| HEADERS = {"User-Agent": "Mozilla/5.0"} | |
| # ------------------------------- | |
| # FETCH PAGE | |
| # ------------------------------- | |
| def fetch_page(url): | |
| try: | |
| response = requests.get(url, headers=HEADERS, timeout=10) | |
| return BeautifulSoup(response.text, "html.parser") | |
| except: | |
| return None | |
| # ------------------------------- | |
| # EXTRACT FROM BLOCKS (MAIN LOGIC) | |
| # ------------------------------- | |
| def extract_from_blocks(soup): | |
| blocks = soup.find_all(["p", "div", "li"]) | |
| data = [] | |
| for block in blocks: | |
| text = block.get_text(" ", strip=True) | |
| # Email detection | |
| email_match = re.search( | |
| r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}", text | |
| ) | |
| if email_match: | |
| email = email_match.group() | |
| # Name guess | |
| words = text.split() | |
| name = " ".join(words[:3]) if len(words) >= 3 else "Unknown" | |
| # Phone | |
| phone_match = re.search(r"\+?\d[\d\s\-]{8,15}", text) | |
| phone = phone_match.group() if phone_match else "Not Available" | |
| data.append([name, email, phone]) | |
| return data | |
| # ------------------------------- | |
| # TRY TO FIND PROFILE LINKS | |
| # ------------------------------- | |
| def get_profile_links(soup, base_url): | |
| links = set() | |
| for a in soup.find_all("a", href=True): | |
| href = a["href"] | |
| full = urljoin(base_url, href) | |
| keywords = ["faculty", "profile", "staff", "person", "people"] | |
| if any(k in full.lower() for k in keywords): | |
| links.add(full) | |
| return list(links) | |
| # ------------------------------- | |
| # EXTRACT FROM PROFILE PAGE | |
| # ------------------------------- | |
| def extract_from_profile(url): | |
| soup = fetch_page(url) | |
| if not soup: | |
| return None | |
| text = soup.get_text(" ", strip=True) | |
| # Name | |
| name = "Not Available" | |
| for tag in ["h1", "h2", "h3"]: | |
| t = soup.find(tag) | |
| if t: | |
| val = t.get_text(strip=True) | |
| if 2 < len(val) < 80: | |
| name = val | |
| break | |
| email_match = re.search( | |
| r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}", text | |
| ) | |
| email = email_match.group() if email_match else "Not Available" | |
| # Phone | |
| phone_match = re.search(r"\+?\d[\d\s\-]{8,15}", text) | |
| phone = phone_match.group() if phone_match else "Not Available" | |
| return [name, email, phone] | |
| # ------------------------------- | |
| # MAIN SCRAPER FUNCTION | |
| # ------------------------------- | |
| def scrape(url): | |
| soup = fetch_page(url) | |
| if not soup: | |
| return None, "β Failed to load page" | |
| # Method 1: Direct extraction | |
| data = extract_from_blocks(soup) | |
| # Method 2: Profile-based extraction (fallback) | |
| if not data: | |
| links = get_profile_links(soup, url) | |
| for link in links[:20]: # limit for speed | |
| result = extract_from_profile(link) | |
| if result: | |
| data.append(result) | |
| if not data: | |
| return None, "β No data found (site may block scraping or use JavaScript)" | |
| df = pd.DataFrame(data, columns=["Name", "Email", "Phone"]) | |
| df = df.drop_duplicates() | |
| return df, f"β Found {len(df)} records" | |
| # ------------------------------- | |
| # STREAMLIT UI | |
| # ------------------------------- | |
| st.set_page_config(page_title="Faculty Scraper", layout="wide") | |
| st.title("π Universal Faculty Scraper") | |
| st.markdown("Paste a college faculty page URL and extract emails, names, and phone numbers.") | |
| url = st.text_input("π Enter Faculty Page URL") | |
| if st.button("π Scrape"): | |
| if not url: | |
| st.warning("Please enter a URL") | |
| else: | |
| with st.spinner("Scraping in progress..."): | |
| df, msg = scrape(url) | |
| if df is not None: | |
| st.success(msg) | |
| st.dataframe(df, use_container_width=True) | |
| csv = df.to_csv(index=False).encode("utf-8") | |
| st.download_button( | |
| label="π₯ Download CSV", | |
| data=csv, | |
| file_name="faculty_data.csv", | |
| mime="text/csv", | |
| ) | |
| else: | |
| st.error(msg) |