Spaces:
Runtime error
Runtime error
File size: 3,619 Bytes
aca6a88 831a22a aca6a88 831a22a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | import streamlit as st
import pandas as pd
import re
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
st.set_page_config(page_title="Faculty Scraper", layout="wide")
st.title("π Universal Faculty Scraper (Clean + Smart)")
EMAIL_REGEX = r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
# -------- DRIVER --------
def get_driver():
options = Options()
options.binary_location = "/usr/bin/chromium"
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(options=options)
return driver
# -------- NAME CLEANING --------
def name_from_email(email):
name_part = email.split("@")[0]
# Replace separators
name_part = re.sub(r"[._]", " ", name_part)
# Split camel case
name_part = re.sub(r'([a-z])([A-Z])', r'\1 \2', name_part)
# Remove numbers
name_part = re.sub(r'\d+', '', name_part)
words = name_part.split()
return " ".join([w.capitalize() for w in words if len(w) > 1])
# -------- PHONE CLEANING --------
def clean_phone(text):
phones = re.findall(r"\+?\d[\d\s\-]{8,15}", text)
for p in phones:
p_clean = p.replace(" ", "")
# Reject year-like values
if re.search(r"\d{4}-\d{2}", p_clean):
continue
digits = re.sub(r"\D", "", p_clean)
# Accept only realistic phone lengths
if 10 <= len(digits) <= 13:
return p_clean
return "Not Available"
# -------- MAIN SCRAPER --------
def scrape_faculty(url):
driver = get_driver()
driver.get(url)
time.sleep(5)
soup = BeautifulSoup(driver.page_source, "html.parser")
driver.quit()
data = []
blocks = soup.find_all(["tr", "div", "li", "section"])
for block in blocks:
text = block.get_text(" ", strip=True)
if len(text) < 20:
continue
# -------- EMAIL --------
email_match = re.search(EMAIL_REGEX, text)
if not email_match:
mail = block.find("a", href=re.compile("mailto:", re.I))
if mail:
email = mail.get("href").replace("mailto:", "").strip()
else:
continue
else:
email = email_match.group()
# -------- NAME --------
name = None
# Try headings
h = block.find(["h1", "h2", "h3", "h4", "strong", "b"])
if h:
name = h.get_text(strip=True)
# Fallback
if not name or len(name) < 3:
name = name_from_email(email)
# -------- PHONE --------
phone = clean_phone(text)
data.append([name, email, phone])
df = pd.DataFrame(data, columns=["Name", "Email", "Phone"])
# -------- REMOVE DUPLICATES --------
df = df.drop_duplicates(subset=["Email"])
return df
# -------- UI --------
url = st.text_input("π Enter Faculty Page URL")
if st.button("π Scrape Data"):
if not url:
st.warning("Please enter a URL")
else:
with st.spinner("Scraping intelligently..."):
df = scrape_faculty(url)
if not df.empty:
st.success("β
Data Extracted Successfully")
st.dataframe(df, use_container_width=True)
csv = df.to_csv(index=False).encode("utf-8")
st.download_button(
"π₯ Download CSV",
csv,
"faculty_data.csv",
"text/csv"
)
else:
st.error("β No data found") |