Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Visitor Analytics Scraper</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary-color: #4361ee; | |
| --secondary-color: #3f37c9; | |
| --accent-color: #4895ef; | |
| --dark-color: #1a1a2e; | |
| --light-color: #f8f9fa; | |
| --danger-color: #ef233c; | |
| --success-color: #2ecc71; | |
| --warning-color: #ff9f1c; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background-color: #f5f7fb; | |
| color: var(--dark-color); | |
| line-height: 1.6; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 2rem; | |
| } | |
| header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 2rem; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| color: var(--primary-color); | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| } | |
| .logo i { | |
| font-size: 2rem; | |
| } | |
| .search-container { | |
| display: flex; | |
| gap: 1rem; | |
| margin-bottom: 2rem; | |
| } | |
| .search-input { | |
| flex: 1; | |
| padding: 0.8rem 1rem; | |
| border: 1px solid #ddd; | |
| border-radius: 8px; | |
| font-size: 1rem; | |
| box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); | |
| transition: all 0.3s ease; | |
| } | |
| .search-input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 2px 10px rgba(67, 97, 238, 0.2); | |
| } | |
| .search-btn { | |
| background-color: var(--primary-color); | |
| color: white; | |
| border: none; | |
| border-radius: 8px; | |
| padding: 0 2rem; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .search-btn:hover { | |
| background-color: var(--secondary-color); | |
| } | |
| .dashboard { | |
| display: grid; | |
| grid-template-columns: 1fr 2fr; | |
| gap: 2rem; | |
| } | |
| .stats-card { | |
| background-color: white; | |
| border-radius: 12px; | |
| padding: 1.5rem; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); | |
| } | |
| .stats-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 1.5rem; | |
| } | |
| .stats-title { | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| } | |
| .refresh-btn { | |
| background-color: var(--light-color); | |
| border: none; | |
| border-radius: 50%; | |
| width: 36px; | |
| height: 36px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .refresh-btn:hover { | |
| background-color: #e9ecef; | |
| } | |
| .stat-item { | |
| margin-bottom: 1rem; | |
| } | |
| .stat-label { | |
| display: block; | |
| font-size: 0.9rem; | |
| color: #6c757d; | |
| margin-bottom: 0.2rem; | |
| } | |
| .stat-value { | |
| font-size: 1.5rem; | |
| font-weight: 600; | |
| color: var(--dark-color); | |
| } | |
| .visitors-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| background-color: white; | |
| border-radius: 12px; | |
| overflow: hidden; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); | |
| } | |
| .visitors-table th, .visitors-table td { | |
| padding: 1rem; | |
| text-align: left; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .visitors-table th { | |
| background-color: #f8f9fa; | |
| font-weight: 600; | |
| color: #495057; | |
| } | |
| .visitors-table tr:last-child td { | |
| border-bottom: none; | |
| } | |
| .visitor-avatar { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 50%; | |
| object-fit: cover; | |
| margin-right: 0.5rem; | |
| vertical-align: middle; | |
| } | |
| .visitor-info { | |
| display: flex; | |
| align-items: center; | |
| } | |
| .visitor-name { | |
| font-weight: 500; | |
| } | |
| .visitor-email { | |
| font-size: 0.8rem; | |
| color: #6c757d; | |
| } | |
| .flag-icon { | |
| width: 20px; | |
| margin-right: 0.5rem; | |
| vertical-align: middle; | |
| } | |
| .status { | |
| display: inline-block; | |
| padding: 0.3rem 0.6rem; | |
| border-radius: 20px; | |
| font-size: 0.8rem; | |
| font-weight: 500; | |
| } | |
| .status-new { | |
| background-color: rgba(72, 149, 239, 0.1); | |
| color: var(--accent-color); | |
| } | |
| .status-returning { | |
| background-color: rgba(46, 204, 113, 0.1); | |
| color: var(--success-color); | |
| } | |
| .pagination { | |
| display: flex; | |
| justify-content: center; | |
| margin-top: 1.5rem; | |
| gap: 0.5rem; | |
| } | |
| .pagination-btn { | |
| background-color: white; | |
| border: 1px solid #ddd; | |
| border-radius: 6px; | |
| padding: 0.5rem 1rem; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .pagination-btn:hover { | |
| background-color: #f1f3f5; | |
| } | |
| .pagination-btn.active { | |
| background-color: var(--primary-color); | |
| color: white; | |
| border-color: var(--primary-color); | |
| } | |
| .tabs { | |
| display: flex; | |
| margin-bottom: 2rem; | |
| border-bottom: 1px solid #ddd; | |
| } | |
| .tab { | |
| padding: 0.8rem 1.5rem; | |
| cursor: pointer; | |
| font-weight: 500; | |
| color: #6c757d; | |
| position: relative; | |
| transition: all 0.3s ease; | |
| } | |
| .tab:hover { | |
| color: var(--primary-color); | |
| } | |
| .tab.active { | |
| color: var(--primary-color); | |
| } | |
| .tab.active::after { | |
| content: ''; | |
| position: absolute; | |
| bottom: -1px; | |
| left: 0; | |
| right: 0; | |
| height: 3px; | |
| background-color: var(--primary-color); | |
| border-radius: 3px 3px 0 0; | |
| } | |
| .chart-container { | |
| background-color: white; | |
| border-radius: 12px; | |
| padding: 1.5rem; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); | |
| margin-bottom: 2rem; | |
| } | |
| @media (max-width: 992px) { | |
| .dashboard { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .loader { | |
| display: none; | |
| border: 4px solid #f3f3f3; | |
| border-top: 4px solid var(--primary-color); | |
| border-radius: 50%; | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| margin: 2rem auto; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .notification { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| background-color: var(--success-color); | |
| color: white; | |
| padding: 1rem; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); | |
| display: none; | |
| z-index: 1000; | |
| animation: slideIn 0.3s ease-out; | |
| } | |
| @keyframes slideIn { | |
| from { transform: translateX(100%); opacity: 0; } | |
| to { transform: translateX(0); opacity: 1; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <div class="logo"> | |
| <i class="fas fa-users"></i> | |
| <span>VisitorScraper Pro</span> | |
| </div> | |
| <div> | |
| <button class="search-btn" id="exportBtn"> | |
| <i class="fas fa-file-export"></i> Export Data | |
| </button> | |
| </div> | |
| </header> | |
| <div class="search-container"> | |
| <input type="text" class="search-input" id="websiteUrl" placeholder="Enter website URL (e.g., https://example.com)" value="example.com"> | |
| <button class="search-btn" id="scrapeBtn"> | |
| <i class="fas fa-search"></i> Scrape Visitors | |
| </button> | |
| </div> | |
| <div class="loader" id="loader"></div> | |
| <div class="tabs"> | |
| <div class="tab active">Dashboard</div> | |
| <div class="tab">Analyze</div> | |
| <div class="tab">Settings</div> | |
| </div> | |
| <div class="dashboard" id="dashboard"> | |
| <div> | |
| <div class="stats-card"> | |
| <div class="stats-header"> | |
| <h3 class="stats-title">Visitor Statistics</h3> | |
| <button class="refresh-btn" id="refreshStats"> | |
| <i class="fas fa-sync-alt"></i> | |
| </button> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Total Visitors</span> | |
| <span class="stat-value" id="totalVisitors">0</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Unique Visitors</span> | |
| <span class="stat-value" id="uniqueVisitors">0</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Returning Visitors</span> | |
| <span class="stat-value" id="returningVisitors">0</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Avg. Visit Duration</span> | |
| <span class="stat-value" id="avgDuration">0m 0s</span> | |
| </div> | |
| </div> | |
| <div class="stats-card" style="margin-top: 1.5rem;"> | |
| <div class="stats-header"> | |
| <h3 class="stats-title">Traffic Sources</h3> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Direct</span> | |
| <span class="stat-value" id="directTraffic">0%</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Organic Search</span> | |
| <span class="stat-value" id="organicTraffic">0%</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Social Media</span> | |
| <span class="stat-value" id="socialTraffic">0%</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Referral</span> | |
| <span class="stat-value" id="referralTraffic">0%</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="chart-container"> | |
| <canvas id="visitorChart" height="200"></canvas> | |
| </div> | |
| <div class="stats-card"> | |
| <div class="stats-header"> | |
| <h3 class="stats-title">Recent Visitors</h3> | |
| <div class="dropdown"> | |
| <button class="refresh-btn"> | |
| <i class="fas fa-ellipsis-v"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div style="overflow-x: auto;"> | |
| <table class="visitors-table"> | |
| <thead> | |
| <tr> | |
| <th>Visitor</th> | |
| <th>Location</th> | |
| <th>Device</th> | |
| <th>Time Spent</th> | |
| <th>Status</th> | |
| </tr> | |
| </thead> | |
| <tbody id="visitorsTableBody"> | |
| <!-- Visitors will be dynamically inserted here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="pagination"> | |
| <button class="pagination-btn active">1</button> | |
| <button class="pagination-btn">2</button> | |
| <button class="pagination-btn">3</button> | |
| <button class="pagination-btn"> | |
| <i class="fas fa-chevron-right"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="notification" id="notification"> | |
| <i class="fas fa-check-circle"></i> Data scraped successfully! | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Mock data for demonstration | |
| const mockVisitors = [ | |
| { | |
| id: 1, | |
| name: "John Doe", | |
| email: "john@example.com", | |
| location: "United States", | |
| device: "Desktop", | |
| timeSpent: "4m 32s", | |
| status: "returning", | |
| ip: "192.168.1.1", | |
| avatar: "https://randomuser.me/api/portraits/men/32.jpg" | |
| }, | |
| { | |
| id: 2, | |
| name: "Jane Smith", | |
| email: "jane@example.com", | |
| location: "Germany", | |
| device: "Mobile", | |
| timeSpent: "2m 15s", | |
| status: "new", | |
| ip: "192.168.1.2", | |
| avatar: "https://randomuser.me/api/portraits/women/44.jpg" | |
| }, | |
| { | |
| id: 3, | |
| name: "Robert Johnson", | |
| email: "robert@example.com", | |
| location: "United Kingdom", | |
| device: "Tablet", | |
| timeSpent: "8m 47s", | |
| status: "returning", | |
| ip: "192.168.1.3", | |
| avatar: "https://randomuser.me/api/portraits/men/67.jpg" | |
| }, | |
| { | |
| id: 4, | |
| name: "Emily Davis", | |
| email: "emily@example.com", | |
| location: "France", | |
| device: "Desktop", | |
| timeSpent: "5m 21s", | |
| status: "new", | |
| ip: "192.168.1.4", | |
| avatar: "https://randomuser.me/api/portraits/women/33.jpg" | |
| }, | |
| { | |
| id: 5, | |
| name: "Michael Brown", | |
| email: "michael@example.com", | |
| location: "Canada", | |
| device: "Mobile", | |
| timeSpent: "3m 54s", | |
| status: "returning", | |
| ip: "192.168.1.5", | |
| avatar: "https://randomuser.me/api/portraits/men/22.jpg" | |
| } | |
| ]; | |
| // Elements | |
| const scrapeBtn = document.getElementById('scrapeBtn'); | |
| const exportBtn = document.getElementById('exportBtn'); | |
| const refreshStats = document.getElementById('refreshStats'); | |
| const loader = document.getElementById('loader'); | |
| const dashboard = document.getElementById('dashboard'); | |
| const notification = document.getElementById('notification'); | |
| const visitorsTableBody = document.getElementById('visitorsTableBody'); | |
| const tabs = document.querySelectorAll('.tab'); | |
| const paginationBtns = document.querySelectorAll('.pagination-btn'); | |
| // Statistics elements | |
| const totalVisitors = document.getElementById('totalVisitors'); | |
| const uniqueVisitors = document.getElementById('uniqueVisitors'); | |
| const returningVisitors = document.getElementById('returningVisitors'); | |
| const avgDuration = document.getElementById('avgDuration'); | |
| const directTraffic = document.getElementById('directTraffic'); | |
| const organicTraffic = document.getElementById('organicTraffic'); | |
| const socialTraffic = document.getElementById('socialTraffic'); | |
| const referralTraffic = document.getElementById('referralTraffic'); | |
| // Chart initialization | |
| const ctx = document.getElementById('visitorChart').getContext('2d'); | |
| let visitorChart = new Chart(ctx, { | |
| type: 'line', | |
| data: { | |
| labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'], | |
| datasets: [{ | |
| label: 'Visitors', | |
| data: [120, 190, 170, 220, 280, 250, 310], | |
| backgroundColor: 'rgba(67, 97, 238, 0.2)', | |
| borderColor: 'rgba(67, 97, 238, 1)', | |
| borderWidth: 2, | |
| tension: 0.4, | |
| fill: true | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| plugins: { | |
| legend: { | |
| display: false | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true, | |
| grid: { | |
| display: true, | |
| color: 'rgba(0, 0, 0, 0.05)' | |
| } | |
| }, | |
| x: { | |
| grid: { | |
| display: false | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Tab functionality | |
| tabs.forEach(tab => { | |
| tab.addEventListener('click', function() { | |
| tabs.forEach(t => t.classList.remove('active')); | |
| this.classList.add('active'); | |
| }); | |
| }); | |
| // Pagination functionality | |
| paginationBtns.forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| if (this.textContent.trim() !== '') { | |
| paginationBtns.forEach(b => b.classList.remove('active')); | |
| this.classList.add('active'); | |
| } | |
| }); | |
| }); | |
| // Display mock visitors | |
| function displayVisitors(visitors) { | |
| visitorsTableBody.innerHTML = ''; | |
| visitors.forEach(visitor => { | |
| const statusClass = visitor.status === 'new' ? 'status-new' : 'status-returning'; | |
| const statusText = visitor.status === 'new' ? 'New' : 'Returning'; | |
| const row = document.createElement('tr'); | |
| row.innerHTML = ` | |
| <td> | |
| <div class="visitor-info"> | |
| <img src="${visitor.avatar}" alt="${visitor.name}" class="visitor-avatar"> | |
| <div> | |
| <div class="visitor-name">${visitor.name}</div> | |
| <div class="visitor-email">${visitor.email}</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td> | |
| <img src="https://flagcdn.com/w20/${getCountryCode(visitor.location).toLowerCase()}.png" class="flag-icon"> | |
| ${visitor.location} | |
| </td> | |
| <td>${visitor.device}</td> | |
| <td>${visitor.timeSpent}</td> | |
| <td><span class="status ${statusClass}">${statusText}</span></td> | |
| `; | |
| visitorsTableBody.appendChild(row); | |
| }); | |
| } | |
| // Helper function to get country code (simplified) | |
| function getCountryCode(country) { | |
| const countryMap = { | |
| 'United States': 'US', | |
| 'Germany': 'DE', | |
| 'United Kingdom': 'GB', | |
| 'France': 'FR', | |
| 'Canada': 'CA' | |
| }; | |
| return countryMap[country] || 'US'; | |
| } | |
| // Update statistics | |
| function updateStats() { | |
| totalVisitors.textContent = mockVisitors.length; | |
| uniqueVisitors.textContent = mockVisitors.filter(v => v.status === 'new').length; | |
| returningVisitors.textContent = mockVisitors.filter(v => v.status === 'returning').length; | |
| // Calculate average time spent | |
| const times = mockVisitors.map(v => { | |
| const parts = v.timeSpent.split(/[ms]/).filter(Boolean).map(Number); | |
| return parts[0] * 60 + (parts[1] || 0); | |
| }); | |
| const avgSeconds = Math.round(times.reduce((a, b) => a + b, 0) / times.length); | |
| const minutes = Math.floor(avgSeconds / 60); | |
| const seconds = avgSeconds % 60; | |
| avgDuration.textContent = `${minutes}m ${seconds}s`; | |
| // Traffic sources | |
| directTraffic.textContent = '40%'; | |
| organicTraffic.textContent = '35%'; | |
| socialTraffic.textContent = '15%'; | |
| referralTraffic.textContent = '10%'; | |
| } | |
| // Scrape button click handler | |
| scrapeBtn.addEventListener('click', function() { | |
| const websiteUrl = document.getElementById('websiteUrl').value.trim(); | |
| if (!websiteUrl) { | |
| alert('Please enter a website URL'); | |
| return; | |
| } | |
| // Show loader, hide dashboard | |
| loader.style.display = 'block'; | |
| dashboard.style.opacity = '0.5'; | |
| dashboard.style.pointerEvents = 'none'; | |
| // Simulate scraping process | |
| setTimeout(function() { | |
| // Hide loader, show dashboard | |
| loader.style.display = 'none'; | |
| dashboard.style.opacity = '1'; | |
| dashboard.style.pointerEvents = 'auto'; | |
| // Update data | |
| displayVisitors(mockVisitors); | |
| updateStats(); | |
| // Update chart | |
| visitorChart.data.datasets[0].data = [150, 210, 190, 240, 300, 270, 330]; | |
| visitorChart.update(); | |
| // Show notification | |
| notification.style.display = 'flex'; | |
| setTimeout(() => { | |
| notification.style.display = 'none'; | |
| }, 3000); | |
| }, 2000); | |
| }); | |
| // Export button click handler | |
| exportBtn.addEventListener('click', function() { | |
| alert('Visitor data exported to CSV (simulated)'); | |
| }); | |
| // Refresh stats button click handler | |
| refreshStats.addEventListener('click', function() { | |
| this.querySelector('i').classList.add('fa-spin'); | |
| setTimeout(() => { | |
| this.querySelector('i').classList.remove('fa-spin'); | |
| updateStats(); | |
| }, 1000); | |
| }); | |
| // Initial load | |
| displayVisitors(mockVisitors); | |
| updateStats(); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
| </html> |