Spaces:
Sleeping
Sleeping
Download app.py from jayanth-2005/10: direct link, hf CLI and curl.
- Browser
- Download file 4.84 kB
-
https://huggingface.co/spaces/jayanth-2005/10/resolve/main/app.py
- Command line
-
hf download hf://spaces/jayanth-2005/10/app.py
-
curl -L -o app.py https://huggingface.co/spaces/jayanth-2005/10/resolve/main/app.py
4.84 kB
| import requests | |
| from bs4 import BeautifulSoup | |
| import re | |
| from urllib.parse import urljoin | |
| import gradio as gr | |
| # --------------------------------- | |
| # Validate proper email | |
| # --------------------------------- | |
| def is_valid_email(email): | |
| return re.match(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", email) | |
| # --------------------------------- | |
| # Clean text (remove garbage) | |
| # --------------------------------- | |
| def is_clean_text(text): | |
| if not text: | |
| return False | |
| if len(text) > 100: | |
| return False | |
| if any(char in text for char in ["�", "\x00"]): | |
| return False | |
| if any(word in text.lower() for word in [ | |
| "obj", "endobj", "stream", "pdf" | |
| ]): | |
| return False | |
| return True | |
| # --------------------------------- | |
| # Validate real name | |
| # --------------------------------- | |
| def is_valid_name(text): | |
| text_lower = text.lower() | |
| if any(word in text_lower for word in [ | |
| "iit", "university", "college", | |
| "department", "school", | |
| "faculty", "staff", "research", | |
| "principal", "administrator" | |
| ]): | |
| return False | |
| if "@" in text: | |
| return False | |
| words = text.split() | |
| return 2 <= len(words) <= 5 | |
| # --------------------------------- | |
| # Email → Name fallback | |
| # --------------------------------- | |
| def name_from_email(email): | |
| username = email.split("@")[0] | |
| parts = re.split(r"[._]", username) | |
| if len(parts) == 1: | |
| parts = re.findall('[A-Za-z][^A-Z]*', username) | |
| return " ".join([p.capitalize() for p in parts if p]) | |
| # --------------------------------- | |
| # Find closest name to email | |
| # --------------------------------- | |
| def find_name_near_email(text_node): | |
| parent = text_node.parent | |
| # Check previous siblings (closest first) | |
| for sibling in parent.previous_siblings: | |
| if hasattr(sibling, "get_text"): | |
| text = sibling.get_text(strip=True) | |
| if is_valid_name(text) and is_clean_text(text): | |
| return text | |
| # Check inside same parent | |
| text = parent.get_text("\n", strip=True) | |
| lines = text.split("\n") | |
| for line in lines: | |
| line = line.strip() | |
| if is_valid_name(line) and is_clean_text(line): | |
| return line | |
| return None | |
| # --------------------------------- | |
| # Main scraper | |
| # --------------------------------- | |
| def get_professor_details(college_url): | |
| try: | |
| headers = {"User-Agent": "Mozilla/5.0"} | |
| response = requests.get(college_url, headers=headers, timeout=10) | |
| soup = BeautifulSoup(response.text, "html.parser") | |
| # Find faculty-related links | |
| keywords = ["faculty", "people", "staff", "directory"] | |
| faculty_links = [] | |
| for link in soup.find_all("a", href=True): | |
| href = link["href"].lower() | |
| if any(word in href for word in keywords): | |
| faculty_links.append(urljoin(college_url, link["href"])) | |
| pages_to_scan = faculty_links if faculty_links else [college_url] | |
| results = [] | |
| seen = set() | |
| for page in pages_to_scan: | |
| try: | |
| res = requests.get(page, headers=headers, timeout=10) | |
| page_soup = BeautifulSoup(res.text, "html.parser") | |
| # Find all text nodes containing emails | |
| for text_node in page_soup.find_all(string=re.compile(r"@")): | |
| emails = re.findall(r"[\w\.-]+@[\w\.-]+", text_node) | |
| for email in emails: | |
| if not is_valid_email(email): | |
| continue | |
| if email in seen: | |
| continue | |
| seen.add(email) | |
| # Try to find real name near email | |
| name = find_name_near_email(text_node) | |
| # Fallback | |
| if not name: | |
| name = name_from_email(email) | |
| results.append({ | |
| "name": name, | |
| "email": email | |
| }) | |
| except: | |
| continue | |
| if not results: | |
| return "No data found." | |
| # Format output | |
| output = "" | |
| for r in results: | |
| output += f"Name: {r['name']}\nEmail: {r['email']}\n\n" | |
| return output | |
| except Exception as e: | |
| return f"Error: {str(e)}" | |
| # --------------------------------- | |
| # Gradio UI | |
| # --------------------------------- | |
| iface = gr.Interface( | |
| fn=get_professor_details, | |
| inputs=gr.Textbox(label="Enter College Website URL"), | |
| outputs=gr.Textbox(label="Professor Details"), | |
| title="🎓 College Professor Scraper (Final Version)", | |
| description="Extracts professor names and emails using hybrid intelligent scraping" | |
| ) | |
| iface.launch() |