scraper / index.html
Swobby's picture
Add 3 files
0c3b461 verified
Raw History Blame Contribute Delete
26.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebScrape Pro | Extract Website Data</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#6366F1',
secondary: '#8B5CF6',
dark: '#1F2937',
}
}
}
}
</script>
<style>
.gradient-bg {
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 100%);
}
.scrape-card {
transition: all 0.3s ease;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
}
.scrape-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
.url-input:focus {
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.3);
}
.loader {
border-top-color: #6366F1;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.preview-container {
transition: height 0.3s ease;
overflow: hidden;
}
.result-item {
transition: transform 0.2s;
}
.result-item:hover {
transform: scale(1.02);
}
.notification {
animation: slideIn 0.5s, fadeOut 0.5s 4.5s;
}
@keyframes slideIn {
from { right: -100px; opacity: 0; }
to { right: 20px; opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
</style>
</head>
<body class="bg-gray-50 min-h-screen flex flex-col">
<!-- Navigation -->
<nav class="gradient-bg text-white py-4 px-6 shadow-md">
<div class="container mx-auto flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-code text-2xl"></i>
<h1 class="text-2xl font-bold">WebScrape Pro</h1>
</div>
<div class="flex space-x-4">
<a href="#" class="hover:text-gray-200 transition"><i class="fas fa-home mr-1"></i> Home</a>
<a href="#" class="hover:text-gray-200 transition"><i class="fas fa-book mr-1"></i> Docs</a>
<a href="#" class="hover:text-gray-200 transition"><i class="fas fa-cog mr-1"></i> Settings</a>
</div>
</div>
</nav>
<!-- Hero Section -->
<section class="gradient-bg text-white py-16">
<div class="container mx-auto px-6 text-center">
<h1 class="text-4xl md:text-5xl font-bold mb-4">Extract Data from Any Website</h1>
<p class="text-xl max-w-2xl mx-auto mb-8 opacity-90">
Simple, elegant data extraction tool. Extract text, links, images and more from websites instantly.
</p>
<div class="flex justify-center space-x-4">
<button class="bg-white text-primary font-bold py-3 px-6 rounded-full shadow-lg hover:bg-gray-100 transition transform hover:scale-105">
Get Started <i class="fas fa-arrow-right ml-2"></i>
</button>
<button class="border-2 border-white text-white font-bold py-3 px-6 rounded-full hover:bg-white hover:bg-opacity-10 transition">
<i class="fas fa-play-circle mr-2"></i> Watch Demo
</button>
</div>
</div>
</section>
<!-- Main Content -->
<main class="flex-grow container mx-auto px-4 py-10 max-w-6xl">
<!-- Scraper Tool -->
<div class="scrape-card bg-white rounded-2xl p-6 mb-10">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Input Section -->
<div class="lg:col-span-2">
<h2 class="text-2xl font-bold text-dark mb-4">Website Data Extractor</h2>
<p class="text-gray-600 mb-6">
Enter any website URL to extract data. Select what you want to scrape and get results in seconds.
</p>
<div class="mb-6">
<label class="block text-gray-700 font-medium mb-2">Website URL</label>
<div class="flex">
<input
type="text"
id="url-input"
placeholder="https://example.com"
class="url-input flex-grow p-4 border border-gray-300 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-primary"
>
<button
id="scrape-btn"
class="gradient-bg text-white px-6 rounded-r-lg font-semibold hover:opacity-90 transition"
>
Extract <i class="fas fa-bolt ml-2"></i>
</button>
</div>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<button class="bg-gray-100 py-3 px-4 rounded-lg font-medium hover:bg-gray-200 transition flex items-center justify-center">
<i class="fas fa-font text-primary mr-2"></i> Text
</button>
<button class="bg-gray-100 py-3 px-4 rounded-lg font-medium hover:bg-gray-200 transition flex items-center justify-center">
<i class="fas fa-link text-purple-500 mr-2"></i> Links
</button>
<button class="bg-gray-100 py-3 px-4 rounded-lg font-medium hover:bg-gray-200 transition flex items-center justify-center">
<i class="fas fa-image text-blue-500 mr-2"></i> Images
</button>
<button class="bg-gray-100 py-3 px-4 rounded-lg font-medium hover:bg-gray-200 transition flex items-center justify-center">
<i class="fas fa-table text-green-500 mr-2"></i> Tables
</button>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="flex justify-between items-center mb-2">
<label class="block text-gray-700 font-medium">Options</label>
<button class="text-sm text-primary font-medium">Advanced</button>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="flex items-center">
<input type="checkbox" id="follow-links" class="mr-2">
<label for="follow-links">Follow links</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="include-images" class="mr-2">
<label for="include-images">Include images</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="include-meta" class="mr-2" checked>
<label for="include-meta">Include metadata</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="respect-robots" class="mr-2" checked>
<label for="respect-robots">Respect robots.txt</label>
</div>
</div>
</div>
</div>
<!-- Preview Section -->
<div class="bg-gray-50 rounded-xl p-6">
<h3 class="text-lg font-bold text-gray-800 mb-4">Live Preview</h3>
<div class="preview-container bg-white border border-gray-200 rounded-lg h-72 overflow-hidden mb-4">
<iframe id="preview-frame" class="w-full h-full hidden" frameborder="0"></iframe>
<div id="preview-placeholder" class="flex justify-center items-center h-full">
<div class="text-center p-6">
<div class="bg-gray-200 border-2 border-dashed rounded-xl w-16 h-16 mx-auto mb-4"></div>
<p class="text-gray-500">Enter a URL and click "Extract" to see a preview of the scraped data</p>
</div>
</div>
</div>
<div class="mt-4">
<h4 class="font-medium text-gray-700 mb-2">Scraping Tips</h4>
<ul class="text-sm text-gray-600 space-y-1">
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Use complete URLs starting with https://</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>For best results, choose specific elements to extract</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Respect website terms of service</span>
</li>
<li class="flex items-start">
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>Some sites may block previews due to CORS policies</span>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- Results Section -->
<div id="results-section" class="hidden">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold text-dark">Extracted Text Content</h2>
<div class="flex space-x-3">
<button id="copy-btn" class="bg-gray-100 py-2 px-4 rounded-lg font-medium hover:bg-gray-200 transition">
<i class="fas fa-copy mr-2"></i> Copy All
</button>
</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border border-gray-100">
<div id="text-content" class="h-96 overflow-y-auto text-gray-700 whitespace-pre-line"></div>
</div>
</div>
<!-- Features Section -->
<div class="py-10">
<h2 class="text-3xl font-bold text-center text-dark mb-16">Why Choose WebScrape Pro?</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="text-center p-6 bg-white rounded-xl shadow-sm hover:shadow-md transition">
<div class="w-16 h-16 gradient-bg rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-bolt text-white text-2xl"></i>
</div>
<h3 class="text-xl font-bold mb-3">Lightning Fast</h3>
<p class="text-gray-600">Extract data in milliseconds with our optimized scraping engine.</p>
</div>
<div class="text-center p-6 bg-white rounded-xl shadow-sm hover:shadow-md transition">
<div class="w-16 h-16 gradient-bg rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-shield-alt text-white text-2xl"></i>
</div>
<h3 class="text-xl font-bold mb-3">Secure & Private</h3>
<p class="text-gray-600">All data is processed locally on your device for maximum privacy.</p>
</div>
<div class="text-center p-6 bg-white rounded-xl shadow-sm hover:shadow-md transition">
<div class="w-16 h-16 gradient-bg rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-sync text-white text-2xl"></i>
</div>
<h3 class="text-xl font-bold mb-3">Schedule Scrapes</h3>
<p class="text-gray-600">Automatically extract data on a recurring schedule.</p>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="bg-dark text-white py-10">
<div class="container mx-auto px-4 max-w-6xl">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<div>
<h3 class="text-xl font-bold mb-4 flex items-center">
<i class="fas fa-code mr-2"></i> WebScrape Pro
</h3>
<p class="text-gray-400">The most elegant website data extraction tool on the market.</p>
</div>
<div>
<h4 class="text-lg font-semibold mb-4">Resources</h4>
<ul class="space-y-2">
<li><a href="#" class="text-gray-400 hover:text-white transition">Documentation</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">API Reference</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Tutorials</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Blog</a></li>
</ul>
</div>
<div>
<h4 class="text-lg font-semibold mb-4">Legal</h4>
<ul class="space-y-2">
<li><a href="#" class="text-gray-400 hover:text-white transition">Privacy Policy</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Terms of Service</a></li>
<li><a href="#" class="text-gray-400 hover:text-white transition">Compliance</a></li>
</ul>
</div>
<div>
<h4 class="text-lg font-semibold mb-4">Subscribe</h4>
<p class="text-gray-400 mb-2">Get the latest updates</p>
<div class="flex">
<input type="email" placeholder="Your email" class="bg-gray-700 px-4 py-2 rounded-l-lg w-full focus:outline-none">
<button class="gradient-bg text-white px-4 rounded-r-lg">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
</div>
<div class="border-t border-gray-800 mt-10 pt-6 text-center text-gray-500">
<p>&copy; 2023 WebScrape Pro. All rights reserved.</p>
</div>
</div>
</footer>
<!-- Notification -->
<div id="notification" class="notification fixed top-24 right-6 bg-green-500 text-white p-4 rounded-lg shadow-lg z-50 hidden">
<div class="flex items-center">
<i class="fas fa-check-circle mr-2"></i>
<span>Data extracted successfully!</span>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const scrapeBtn = document.getElementById('scrape-btn');
const urlInput = document.getElementById('url-input');
const resultsSection = document.getElementById('results-section');
const notification = document.getElementById('notification');
scrapeBtn.addEventListener('click', function() {
if (urlInput.value.trim() === '') {
urlInput.focus();
return;
}
// Show loading state
scrapeBtn.innerHTML = 'Processing... <i class="fas fa-spinner fa-spin ml-2"></i>';
scrapeBtn.disabled = true;
const url = urlInput.value.trim();
// Show preview
const previewFrame = document.getElementById('preview-frame');
const placeholder = document.getElementById('preview-placeholder');
try {
previewFrame.src = url;
previewFrame.classList.remove('hidden');
placeholder.classList.add('hidden');
} catch (e) {
console.log("Preview not available due to CORS restrictions");
}
// Track visited URLs to avoid duplicates
const visitedUrls = new Set();
// Function to scrape a page and follow links recursively
const scrapePage = async (pageUrl, depth = 0, maxDepth = 1) => {
// Skip if we've already visited this URL
if (visitedUrls.has(pageUrl)) return;
visitedUrls.add(pageUrl);
try {
// First validate the URL
if (!pageUrl.startsWith('http://') && !pageUrl.startsWith('https://')) {
pageUrl = 'https://' + pageUrl;
}
// Use a serverless function approach
const response = await fetch(`https://api.allorigins.win/get?url=${encodeURIComponent(pageUrl)}`);
if (!response.ok) throw new Error('Failed to fetch page');
const data = await response.json();
const html = data.contents;
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Remove unwanted elements
doc.querySelectorAll('script, style, iframe, img, svg, video, audio').forEach(el => el.remove());
// Get clean text content
let text = doc.body.textContent
.replace(/\s+/g, ' ')
.trim()
.replace(/\n/g, ', ')
.replace(/\s*,\s*/g, ', ');
// Add to results with page URL header
const textContent = document.getElementById('text-content');
textContent.textContent += `\n\n=== Page: ${pageUrl} ===\n\n${text}\n`;
// Follow links if checkbox is checked and we haven't reached max depth
if (document.getElementById('follow-links').checked && depth < maxDepth) {
const links = Array.from(doc.querySelectorAll('a[href]'))
.map(a => {
try {
// Handle relative URLs by creating absolute URLs
const href = a.getAttribute('href');
if (href.startsWith('http')) {
return href;
}
// Handle relative paths
const baseUrl = new URL(pageUrl);
if (href.startsWith('/')) {
return `${baseUrl.protocol}//${baseUrl.host}${href}`;
} else {
// Handle relative paths without leading slash
const pathParts = baseUrl.pathname.split('/');
pathParts.pop(); // Remove last part (current page)
return `${baseUrl.protocol}//${baseUrl.host}${pathParts.join('/')}/${href}`;
}
} catch {
return null;
}
})
.filter(href =>
href &&
!href.includes('#') &&
!href.startsWith('mailto:') &&
!href.startsWith('tel:') &&
new URL(href).origin === new URL(pageUrl).origin
)
.slice(0, 10); // Limit to 10 links to follow
// Filter out already visited links
const uniqueLinks = links.filter(link => !visitedUrls.has(link));
for (const link of uniqueLinks) {
await scrapePage(link, depth + 1, maxDepth);
}
}
} catch (e) {
console.error(`Error scraping ${pageUrl}:`, e);
return null;
}
};
// Clear previous results
document.getElementById('text-content').textContent = '';
// Start scraping with initial depth 0
scrapePage(url, 0, document.getElementById('follow-links').checked ? 3 : 0) // Only go deeper if follow links is checked
.then((text) => {
// Show notification
notification.classList.remove('hidden');
// Show results section
resultsSection.classList.remove('hidden');
resultsSection.scrollIntoView({ behavior: 'smooth' });
// Reset button
scrapeBtn.innerHTML = 'Extract <i class="fas fa-bolt ml-2"></i>';
scrapeBtn.disabled = false;
// Hide notification after some time
setTimeout(() => {
notification.classList.add('hidden');
}, 5000);
})
.catch(error => {
console.error('Scraping failed:', error);
scrapeBtn.innerHTML = 'Extract <i class="fas fa-bolt ml-2"></i>';
scrapeBtn.disabled = false;
});
});
// Copy button functionality
document.getElementById('copy-btn').addEventListener('click', function() {
const textContent = document.getElementById('text-content').textContent;
navigator.clipboard.writeText(textContent).then(() => {
const notification = document.getElementById('notification');
notification.querySelector('span').textContent = 'Text copied to clipboard!';
notification.classList.remove('hidden');
setTimeout(() => notification.classList.add('hidden'), 3000);
});
});
// Example: Add URL input suggestions
const exampleUrls = [
'https://en.wikipedia.org/wiki/Web_scraping',
'https://example.com',
'https://developer.mozilla.org/en-US/'
];
urlInput.addEventListener('focus', function() {
if (!this.dataset.list) {
const datalist = document.createElement('datalist');
datalist.id = 'url-suggestions';
exampleUrls.forEach(url => {
const option = document.createElement('option');
option.value = url;
datalist.appendChild(option);
});
document.body.appendChild(datalist);
this.setAttribute('list', 'url-suggestions');
}
});
});
</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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Swobby/scraper" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>