A modern, real-time web scraping dashboard for extracting data from Google Maps and YouTube. Features a beautiful React frontend with live progress updates, analytics charts, and export functionality.
- π Real-Time Dashboard - Watch data arrive live as it's scraped via WebSocket
- π Analytics Charts - Visual insights with Recharts
- π Dark/Light Mode - Easy theme toggle with persistence
- π€ Export Options - Excel, CSV, and JSON export
- π Multiple Concurrent Sessions - Run multiple scrapers simultaneously
| Scraper | Modes | Data Points |
|---|---|---|
| πΊοΈ Google Maps | Search | Name, address, phone, website, rating, reviews, social links |
| π₯ YouTube | Search, Trending, Suggestions, Deep Metadata | Title, views, likes, duration, uploader, tags, categories, description |
- π¨ Premium Design - Glass morphism, gradients, smooth animations
- π± Fully Responsive - Works on desktop, tablet, and mobile
- βΏ Accessible - ARIA labels, keyboard navigation support
- π Real-Time Notifications - Toast notifications for all events
- β‘ Fast Performance - Optimized React rendering, virtual scrolling ready
web-scraper/
βββ backend/ # Node.js + Express + Socket.io
β βββ server.js # Main server with graceful shutdown
β βββ scrapers/ # Async generator scrapers
β β βββ google.js # Google Maps scraper
β β βββ youtube.js # YouTube scraper (4 modes)
β βββ controllers/ # API handlers
β β βββ googleController.js
β β βββ youtubeController.js
β βββ routes/ # API endpoints
β β βββ scrapers.js
β βββ utils/ # Utilities
β βββ sessionManager.js # Session state management
β βββ browserManager.js # Puppeteer browser tracking
β βββ logger.js # Winston logging
β βββ errorHandler.js # Error classification
β
βββ frontend/ # React + Vite + Tailwind
β βββ src/
β βββ components/ # React components
β β βββ ScraperSelector.jsx
β β βββ GoogleForm.jsx
β β βββ YouTubeForm.jsx
β β βββ ProgressBar.jsx
β β βββ ResultsTable.jsx
β β βββ Charts.jsx
β β βββ ExportButtons.jsx
β β βββ ActiveSessions.jsx
β β βββ ThemeToggle.jsx
β βββ context/ # Global state
β β βββ ScraperContext.jsx
β βββ styles/ # Tailwind CSS + custom animations
β
βββ scrapers/ # Legacy CLI scrapers
βββ output/ # Exported data
- Node.js v18+ (with ES modules support)
- npm v9+
- yt-dlp (for YouTube metadata extraction)
Install yt-dlp:
# macOS
brew install yt-dlp
# Linux
sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
sudo chmod a+rx /usr/local/bin/yt-dlp
# Windows
choco install yt-dlp# Clone the repository
git clone <repo-url>
cd web-scraper
# Install backend dependencies
cd backend
npm install
# Install frontend dependencies
cd ../frontend
npm installBackend (backend/.env):
NODE_ENV=development
PORT=3000
FRONTEND_URL=http://localhost:5173Frontend (frontend/.env):
VITE_API_URL=http://localhost:3000Terminal 1 - Backend:
cd backend
npm startServer runs on http://localhost:3000
Terminal 2 - Frontend:
cd frontend
npm run devDashboard opens on http://localhost:5173
Press Ctrl+C in the terminal. The server will:
- Cancel all running scraping sessions
- Close all Puppeteer browser instances
- Close Socket.io connections
- Exit gracefully within 10 seconds
- Open
http://localhost:5173 - Select a scraper (Google Maps or YouTube)
- Configure options:
- Google Maps: Search term, headless mode, max results
- YouTube: Mode, search term/country, content filter
- Start scraping and watch real-time results
- View analytics charts automatically update
- Export to Excel/CSV/JSON when complete
Configuration:
- Search Term (required) - e.g., "Restaurants in New York"
- Headless Mode - Run browser without UI (default: true)
- Max Results - Limit number of results (optional)
Data Extracted:
{
name: "Business Name",
address: "123 Main St",
phone: "+1 234 567 8900",
website: "https://example.com",
rating: "4.5",
reviews: "123",
fb: "facebook.com/page",
insta: "instagram.com/page",
linkedln: "linkedin.com/company",
url: "maps.google.com/..."
}Modes:
-
Search - Search videos by keyword
- Input: Search term
- Results: Video list with views, duration, channel
-
Trending - Get trending videos by country
- Input: Country code, content filter (all/videos/shorts)
- Results: Trending videos with metadata
-
Suggestions - Get autocomplete suggestions
- Input: Query term
- Results: Suggestion list
-
Deep Metadata - Get full video metadata
- Input: Video URL
- Results: Complete metadata including tags, categories, description
Data Extracted:
{
title: "Video Title",
url: "https://youtube.com/watch?v=...",
views: 1234567,
likes: 45678,
duration: 627, // seconds
upload_date: "20240115",
tags: ["tag1", "tag2"],
categories: ["Entertainment"],
description: "Video description...",
uploader: "Channel Name",
thumbnail: "https://..."
}POST /api/scrape/google
Body: { searchTerm, headless?, maxResults? }
POST /api/scrape/youtube
Body: { mode, searchTerm?, countryCode?, filterType?, headless? }
GET /api/scrape/active # List all active sessions
GET /api/scrape/status/:id # Get session status
DELETE /api/scrape/:id # Cancel a session
GET /api/scrape/:sessionId/export?format=excel|csv|json
Client β Server:
socket.emit('scrape:start', { scraperType, config })
socket.emit('scrape:cancel', { sessionId })
socket.emit('session:join', { sessionId })Server β Client:
socket.on('session:started', { sessionId, scraperType, startTime })
socket.on('scrape:progress', { sessionId, progress })
socket.on('scrape:data', { sessionId, data })
socket.on('scrape:batch', { sessionId, data })
socket.on('session:complete', { sessionId, totalItems, duration })
socket.on('session:error', { sessionId, error })
socket.on('session:cancelled', { sessionId })
socket.on('sessions:active', { sessions })| Technology | Purpose |
|---|---|
| Express.js | Web framework |
| Socket.io | Real-time WebSocket communication |
| Puppeteer | Headless browser automation |
| yt-search | YouTube search API |
| yt-dlp | YouTube metadata extraction |
| Winston | Logging |
| UUID | Session ID generation |
| ExcelJS | Excel export |
| Technology | Purpose |
|---|---|
| React 18 | UI framework |
| Vite | Build tool and dev server |
| Tailwind CSS | Styling |
| Recharts | Data visualization |
| Socket.io-client | WebSocket client |
| axios | HTTP requests |
| react-hot-toast | Notifications |
Puppeteer launch options (in scrapers):
{
headless: true, // Run without UI
args: [
'--no-sandbox', // Required for Linux
'--disable-setuid-sandbox', // Security
'--disable-dev-shm-usage' // Memory optimization
]
}- Max items per session: 10,000
- Session retention: 24 hours
- Auto-cleanup: Every hour
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
development | Environment mode |
PORT |
3000 | Backend server port |
FRONTEND_URL |
http://localhost:5173 | CORS origin |
VITE_API_URL |
http://localhost:3000 | Backend API URL |
# Check if port 3000 is in use
lsof -i :3000
# Kill the process or change PORT in .env# Install required dependencies
# Ubuntu/Debian
sudo apt-get install -y \
chromium-browser \
fonts-liberation \
fonts-noto-color-emoji \
fonts-ipafont-gothic \
fonts-wqy-zenhei \
fonts-thai-tlwg \
fonts-kacst \
fonts-freefont-ttf
# macOS
# No additional dependencies needed# Verify yt-dlp installation
yt-dlp --version
# Update yt-dlp
yt-dlp --update- The graceful shutdown waits up to 10 seconds for browsers to close
- Force quit: Press
Ctrl+Ctwice orCtrl+\
- Check
VITE_API_URLin frontend.env - Check
FRONTEND_URLin backend.env - Ensure backend is running on correct port
This project is intended for educational and research purposes only.
Ensure you comply with the Terms of Service of:
- Respect rate limits - Add delays between requests
- Don't overload servers - Use reasonable concurrent sessions
- Attribution - Credit data sources appropriately
- Legal compliance - Follow local laws and regulations
Bilal Ahmed
- Email: reply2bilal.ahmed@gmail.com
- GitHub: @bilalahmed
- yt-search - YouTube search library
- Puppeteer - Headless Chrome automation
- Vite - Next-gen frontend tooling
- Tailwind CSS - Utility-first CSS framework