feat: KöPi - 11er Kasten mit kasten_front.png

This commit is contained in:
2026-07-09 15:47:36 +02:00
parent b53f58956a
commit 5a14fec92d
7 changed files with 32 additions and 37 deletions

View File

@@ -99,41 +99,37 @@ async function scrapeMarktguru() {
const description = descEl?.textContent?.trim() || ''; const description = descEl?.textContent?.trim() || '';
const img = card.querySelector('img.offer-list-item-img'); const img = card.querySelector('img.offer-list-item-img');
const badge = card.querySelector('.badge, .discount-badge')?.textContent?.trim() || ''; const badge = card.querySelector('.badge, .discount-badge')?.textContent?.trim() || '';
const imgSrc = img?.src || null; const imgSrc = img?.src?.replace('/medium.webp', '/large.webp') || img?.src || null;
return { name, brand, price, oldPrice, retailer, dateRange, validity, description, badge, address: '', image: imgSrc }; return { name, brand, price, oldPrice, retailer, dateRange, validity, description, badge, address: '', image: imgSrc };
}); });
}); });
// Bilder via Node https mit exakten Browser-Headers laden // Lokale Bilder auswählen basierend auf Beschreibung
const nodeHttps = require('https'); for (const offer of offers) {
for (let i = 0; i < offers.length; i++) { const desc = (offer.description || '').toLowerCase();
const url = offers[i].image; if (desc.includes('steini')) {
if (!url || !url.startsWith('https://')) continue; // Steini-Kasten
offers[i].image = await new Promise(resolve => { offer.imageLocal = '/koepi/kasten_steini.png';
const req = nodeHttps.get(url, { } else if (desc.includes('0,33') && (desc.includes('24') || desc.includes('24 x'))) {
headers: { // 24x0,33l Kasten
'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', offer.imageLocal = '/koepi/kasten_033.png';
'Accept': 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', } else if (desc.includes('11') && desc.includes('0,5')) {
'Accept-Language': 'de-DE,de;q=0.9', // 11x0,5l Kasten (von vorne)
'Referer': 'https://www.marktguru.de/', offer.imageLocal = '/koepi/kasten_front.png';
'Origin': 'https://www.marktguru.de', } else if (desc.includes('0,5') && (desc.includes('20') || desc.includes('20 x'))) {
'sec-fetch-dest': 'image', // 20x0,5l Langhalsflasche
'sec-fetch-mode': 'no-cors', offer.imageLocal = '/koepi/kasten_lang.png';
'sec-fetch-site': 'cross-site', } else if (desc.includes('flasche') || desc.includes('6 x') || desc.includes('6x')) {
// 6er Träger
offer.imageLocal = '/koepi/traeger.png';
} else if (desc.includes('0,5')) {
offer.imageLocal = '/koepi/kasten_050.png';
} else if (desc.includes('0,33')) {
offer.imageLocal = '/koepi/kasten_033.png';
} else {
offer.imageLocal = '/koepi/kasten_050.png'; // default
} }
}, res => { offer.image = null; // CDN nicht mehr nötig
if (res.statusCode !== 200) return resolve(null);
const chunks = [];
res.on('data', c => chunks.push(c));
res.on('end', () => {
const b64 = Buffer.concat(chunks).toString('base64');
const mime = res.headers['content-type'] || 'image/webp';
resolve(`data:${mime};base64,${b64}`);
});
});
req.on('error', () => resolve(null));
req.setTimeout(8000, () => { req.destroy(); resolve(null); });
});
} }
// Filtern auf Ziel-Händler + nur König Pilsener // Filtern auf Ziel-Händler + nur König Pilsener

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File

@@ -34,12 +34,11 @@ function OfferCard({ offer }) {
border:'1px solid rgba(255,255,255,0.1)', border:'1px solid rgba(255,255,255,0.1)',
display:'flex', flexDirection:'column', gap:8, display:'flex', flexDirection:'column', gap:8,
}}> }}>
{/* Bild oben, volle Breite */} {/* Bild oben */}
{offer.image && ( {offer.imageLocal && (
<div style={{ margin:'-12px -14px 8px -14px', borderRadius:'8px 8px 0 0', overflow:'hidden', background:'#1a1a1a', display:'flex', alignItems:'center', justifyContent:'center', maxHeight:220 }}> <div style={{ margin:'-12px -14px 8px -14px', borderRadius:'8px 8px 0 0', background:'transparent', height:180, display:'flex', alignItems:'center', justifyContent:'center' }}>
<img src={offer.image} alt="König Pilsener" <img src={offer.imageLocal} alt="König Pilsener"
style={{ maxWidth:'100%', maxHeight:220, width:'auto', height:'auto', display:'block', objectFit:'contain' }} style={{ maxWidth:'100%', maxHeight:'180px', width:'auto', height:'auto', display:'block', objectFit:'contain' }}
onError={e => { e.target.parentElement.style.display='none'; }}
/> />
</div> </div>
)} )}