Spaces:
Sleeping
Sleeping
Download app.py from ENLYAS/web-scraper-pro: direct link, hf CLI and curl.
- Browser
- Download file 6.55 kB
-
https://huggingface.co/spaces/ENLYAS/web-scraper-pro/resolve/main/app.py
- Command line
-
hf download hf://spaces/ENLYAS/web-scraper-pro/app.py
-
curl -L -o app.py https://huggingface.co/spaces/ENLYAS/web-scraper-pro/resolve/main/app.py
6.55 kB
| import gradio as gr | |
| import requests | |
| from bs4 import BeautifulSoup | |
| import json | |
| import re | |
| from urllib.parse import urljoin, urlparse | |
| import pandas as pd | |
| from io import StringIO | |
| class WebScraper: | |
| def __init__(self): | |
| self.session = requests.Session() | |
| self.session.headers.update({ | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' | |
| }) | |
| def scrape_page(self, url, scrape_type='all'): | |
| try: | |
| response = self.session.get(url, timeout=15) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.text, 'html.parser') | |
| results = {'url': url, 'status': 'success', 'data': {}} | |
| if scrape_type in ['all', 'text']: | |
| text_content = soup.get_text(separator=' ', strip=True) | |
| results['data']['text'] = text_content[:10000] | |
| if scrape_type in ['all', 'links']: | |
| links = [] | |
| for link in soup.find_all('a', href=True): | |
| href = link['href'] | |
| full_url = urljoin(url, href) | |
| links.append({'text': link.get_text(strip=True), 'url': full_url}) | |
| results['data']['links'] = links[:50] | |
| if scrape_type in ['all', 'images']: | |
| images = [] | |
| for img in soup.find_all('img'): | |
| src = img.get('src') or img.get('data-src', '') | |
| if src: | |
| images.append({'src': urljoin(url, src), 'alt': img.get('alt', '')}) | |
| results['data']['images'] = images[:30] | |
| if scrape_type in ['all', 'tables']: | |
| tables = [] | |
| for table in soup.find_all('table'): | |
| rows = [] | |
| for tr in table.find_all('tr'): | |
| cells = [td.get_text(strip=True) for td in tr.find_all(['td', 'th'])] | |
| if cells: | |
| rows.append(cells) | |
| if rows: | |
| tables.append(rows) | |
| results['data']['tables'] = tables[:5] | |
| if scrape_type in ['all', 'headings']: | |
| headings = {} | |
| for level in range(1, 7): | |
| tags = soup.find_all(f'h{level}') | |
| headings[f'h{level}'] = [h.get_text(strip=True) for h in tags] | |
| results['data']['headings'] = headings | |
| if scrape_type in ['all', 'meta']: | |
| meta = {} | |
| for tag in soup.find_all('meta'): | |
| name = tag.get('name') or tag.get('property', '') | |
| content = tag.get('content', '') | |
| if name and content: | |
| meta[name] = content | |
| results['data']['meta'] = meta | |
| return json.dumps(results, indent=2, ensure_ascii=False) | |
| except Exception as e: | |
| return json.dumps({'url': url, 'status': 'error', 'error': str(e)}, indent=2) | |
| def scrape_multiple(self, urls_text, scrape_type='all'): | |
| urls = [u.strip() for u in urls_text.split('\n') if u.strip()] | |
| results = [] | |
| for url in urls[:10]: | |
| result = self.scrape_page(url, scrape_type) | |
| results.append(result) | |
| return '\n\n---\n\n'.join(results) | |
| def export_to_csv(self, url, scrape_type='tables'): | |
| try: | |
| response = self.session.get(url, timeout=15) | |
| soup = BeautifulSoup(response.text, 'html.parser') | |
| tables = soup.find_all('table') | |
| if not tables: | |
| return 'No tables found on this page.' | |
| csv_output = [] | |
| for i, table in enumerate(tables[:3]): | |
| csv_output.append(f'### Table {i+1}\n') | |
| df = pd.read_html(StringIO(str(table)))[0] | |
| csv_output.append(df.to_csv(index=False)) | |
| return '\n'.join(csv_output) | |
| except Exception as e: | |
| return f'Error: {str(e)}' | |
| def scrape_website(url, scrape_type, multiple_urls): | |
| scraper = WebScraper() | |
| if multiple_urls: | |
| return scraper.scrape_multiple(url, scrape_type) | |
| return scraper.scrape_page(url, scrape_type) | |
| def export_data(url, scrape_type): | |
| scraper = WebScraper() | |
| return scraper.export_to_csv(url, scrape_type) | |
| with gr.Blocks(theme=gr.themes.Soft(), title='Web Scraper Pro') as demo: | |
| gr.Markdown('# 🕷️ Web Scraper Pro\n\nExtract data from any website with ease. Supports text, links, images, tables, and more.') | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| url_input = gr.Textbox( | |
| label='Website URL(s)', | |
| placeholder='https://example.com\n\nFor multiple URLs, enter one per line', | |
| lines=3 | |
| ) | |
| with gr.Row(): | |
| scrape_type = gr.Dropdown( | |
| choices=['all', 'text', 'links', 'images', 'tables', 'headings', 'meta'], | |
| value='all', | |
| label='Scrape Type' | |
| ) | |
| multiple_urls = gr.Checkbox(label='Multiple URLs Mode', value=False) | |
| scrape_btn = gr.Button('🚀 Start Scraping', variant='primary', size='lg') | |
| export_btn = gr.Button('📥 Export Tables to CSV', variant='secondary') | |
| with gr.Column(scale=3): | |
| output = gr.Textbox( | |
| label='Scraped Results', | |
| lines=20, | |
| max_lines=50 | |
| ) | |
| gr.Markdown('### 📊 Quick Stats') | |
| with gr.Row(): | |
| stat_text = gr.Number(label='Characters Extracted', value=0) | |
| stat_links = gr.Number(label='Links Found', value=0) | |
| stat_images = gr.Number(label='Images Found', value=0) | |
| gr.Markdown('### 💡 Tips\n- Use **Multiple URLs Mode** to scrape several pages at once\n- Select specific **Scrape Type** for faster results\n- **Export Tables** downloads structured data as CSV') | |
| scrape_btn.click( | |
| fn=scrape_website, | |
| inputs=[url_input, scrape_type, multiple_urls], | |
| outputs=output | |
| ) | |
| export_btn.click( | |
| fn=export_data, | |
| inputs=[url_input, scrape_type], | |
| outputs=output | |
| ) | |
| if __name__ == '__main__': | |
| demo.launch(server_name='0.0.0.0', server_port=7860, share=True) |