feat: complete N8N scrapers for 6 sources and seed script
- Create comprehensive N8N workflow for all 6 parapharmacy sources - Create webhook-triggered manual scraping workflow - Add seed script with 20 sample products - Update n8n/README.md with complete documentation - Update docs/parapharmacy.md with seeding instructions - Add seed script to package.json Sources configured: - Promofarma - Pharmarket - DocMorris - 1001Farma - Primor - MiFarma
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_URL = process.env.PARAPHARMACY_API_URL || 'http://localhost:3002';
|
||||
|
||||
// Common parapharmacy search queries
|
||||
const QUERIES = [
|
||||
'crema hidratante',
|
||||
'protector solar',
|
||||
'champú',
|
||||
'gel ducha',
|
||||
'vitaminas',
|
||||
'paracetamol',
|
||||
'ibuprofeno',
|
||||
'omeprazol',
|
||||
'spray nasal',
|
||||
'gotas para los ojos',
|
||||
'crema manos',
|
||||
'bálsamo labial',
|
||||
'antiséptico',
|
||||
'vendas',
|
||||
'termómetro'
|
||||
];
|
||||
|
||||
// Simulated products for testing (replace with real scraping)
|
||||
const MOCK_PRODUCTS = [
|
||||
{ name: 'Bioderma Atoderm Crema Hidratante 500ml', brand: 'Bioderma', category: 'Dermocosmética', price: 18.95 },
|
||||
{ name: 'La Roche-Posay Anthelios Airlicium FPS50+', brand: 'La Roche-Posay', category: 'Solar', price: 19.95 },
|
||||
{ name: 'Mustela Gel de Ducha 500ml', brand: 'Mustela', category: 'Bebé', price: 12.50 },
|
||||
{ name: 'Centrum Multivitaminicos 30 comprimidos', brand: 'Centrum', category: 'Vitaminas', price: 15.80 },
|
||||
{ name: 'Dolocordalpan 1g Paracetamol 20 sobres', brand: 'Dolocordalpan', category: 'Analgésicos', price: 4.95 },
|
||||
{ name: 'Nurofen Flash 400mg 20 cápsulas', brand: 'Nurofen', category: 'Antiinflamatorios', price: 6.75 },
|
||||
{ name: 'Omeprazol Cinfa 20mg 28 cápsulas', brand: 'Cinfa', category: 'Gastrointestinal', price: 8.50 },
|
||||
{ name: 'Vichy Mineral 89 Sérum Hidratante 30ml', brand: 'Vichy', category: 'Dermocosmética', price: 25.90 },
|
||||
{ name: 'Avène Agua Termal 300ml', brand: 'Avène', category: 'Dermocosmética', price: 9.95 },
|
||||
{ name: 'CeraVe Crema Hidratante 340g', brand: 'CeraVe', category: 'Dermocosmética', price: 14.95 },
|
||||
{ name: 'Ibuprofeno Alter 600mg 20 comprimidos', brand: 'Alter', category: 'Antiinflamatorios', price: 5.20 },
|
||||
{ name: 'Salonpas Parches Analgésicos 5 unidades', brand: 'Salonpas', category: 'Analgésicos', price: 7.80 },
|
||||
{ name: 'Fisiomer Spray Nasal 135ml', brand: 'Fisiomer', category: 'Respiratorio', price: 11.50 },
|
||||
{ name: 'Thealoz Duo Colirio 10ml', brand: 'Thea', category: 'Oftalmología', price: 12.95 },
|
||||
{ name: 'Neutrogena Crema Manos Noruega 50ml', brand: 'Neutrogena', category: 'Dermocosmética', price: 4.50 },
|
||||
{ name: 'Capricare 1 Leche en polvo 400g', brand: 'Capricare', category: 'Fórmulas lácteas', price: 14.95 },
|
||||
{ name: 'Nutribén 2 Leche 800g', brand: 'Nutribén', category: 'Fórmulas lácteas', price: 16.50 },
|
||||
{ name: 'Bebelin Vitamina C 1g 20 comprimidos', brand: 'Bebelín', category: 'Vitaminas', price: 6.95 },
|
||||
{ name: 'Lacer Pasta Dientes Sensibilidad 75ml', brand: 'Lacer', category: 'Oral', price: 5.80 },
|
||||
{ name: 'Fotosan Crema Solar FPS50 200ml', brand: 'Fotosan', category: 'Solar', price: 22.50 }
|
||||
];
|
||||
|
||||
async function checkAPIHealth() {
|
||||
try {
|
||||
const response = await axios.get(`${API_URL}/api/health`);
|
||||
return response.data.status === 'ok';
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function seedProducts() {
|
||||
console.log('🌱 Starting parapharmacy database seed...\n');
|
||||
|
||||
// Check if API is running
|
||||
const apiHealthy = await checkAPIHealth();
|
||||
if (!apiHealthy) {
|
||||
console.error('❌ Parapharmacy API is not running. Start it with: npm run dev');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✅ Parapharmacy API is running\n');
|
||||
|
||||
// Seed products
|
||||
let created = 0;
|
||||
let updated = 0;
|
||||
let errors = 0;
|
||||
|
||||
for (const product of MOCK_PRODUCTS) {
|
||||
try {
|
||||
const productData = {
|
||||
...product,
|
||||
source: 'seed',
|
||||
source_product_id: `seed_${product.name.toLowerCase().replace(/[^a-z0-9]/g, '_')}`,
|
||||
source_url: `https://www.promofarma.com/es/search?q=${encodeURIComponent(product.name)}`,
|
||||
image_url: null,
|
||||
currency: 'EUR',
|
||||
available: true,
|
||||
scraped_at: new Date().toISOString()
|
||||
};
|
||||
|
||||
await axios.post(`${API_URL}/api/products`, productData);
|
||||
created++;
|
||||
console.log(` ✅ Created: ${product.name}`);
|
||||
} catch (error) {
|
||||
if (error.response?.status === 409) {
|
||||
updated++;
|
||||
console.log(` ⏭️ Already exists: ${product.name}`);
|
||||
} else {
|
||||
errors++;
|
||||
console.error(` ❌ Error: ${product.name} - ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n📊 Seed Summary:');
|
||||
console.log(` Created: ${created}`);
|
||||
console.log(` Already exists: ${updated}`);
|
||||
console.log(` Errors: ${errors}`);
|
||||
console.log(` Total: ${MOCK_PRODUCTS.length}`);
|
||||
}
|
||||
|
||||
// Run seed
|
||||
seedProducts().catch(error => {
|
||||
console.error('❌ Seed failed:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user