fix: KöPi - exakte marktguru Selektoren, saubere Anzeige

This commit is contained in:
2026-07-09 00:57:46 +02:00
parent d2b8706b26
commit 0eec03d5c7
2 changed files with 40 additions and 65 deletions

View File

@@ -50,58 +50,25 @@ async function scrapeMarktguru() {
await new Promise(r => setTimeout(r, 4000));
const offers = await page.evaluate(() => {
const results = [];
// Angebots-Karten selektieren
const cards = document.querySelectorAll('.offer-item, [class*="offer-item"], .search-offer, [class*="searchOffer"]');
// Fallback: alle Container die Preis + Händler enthalten
const containers = cards.length > 0 ? cards :
document.querySelectorAll('[class*="offer"]:not([class*="more"]):not([class*="list"]):not([class*="section"])');
containers.forEach(card => {
const text = card.innerText || card.textContent || '';
if (!text.includes('König') && !text.includes('Pilsen')) return;
const img = card.querySelector('img');
const lines = text.split('\n').map(l => l.trim()).filter(Boolean);
// Felder aus Text extrahieren
let name='', brand='', price='', retailer='', validity='', dateRange='', description='', oldPrice='';
lines.forEach((line, i) => {
if (line.match(/^€\s*\d/) && !price) price = line;
if (line.match(/^\d+[,\.]\d+\s*€/) && !price) price = line;
if (line.includes('Händler:')) retailer = lines[i+1] || line.replace('Händler:','').trim();
if (line.includes('Marke:')) brand = lines[i+1] || line.replace('Marke:','').trim();
if (line.includes('Gültig:') || line.includes('gültig:')) dateRange = lines[i+1] || line.replace(/G.ltig:/i,'').trim();
if (line.includes('Noch') && line.includes('Tag')) validity = line;
if (line.includes('/ l') || line.includes('/l') || line.includes('Kasten') || line.includes('Flasche')) description = line;
if (line.includes('Brandneu')) validity = 'Neu';
});
// Name ist meist die erste Zeile
name = lines[0] || '';
// Direkte DOM-Selektion als Alternative
const priceEl = card.querySelector('[class*="price"],[class*="Price"]');
const retailEl = card.querySelector('[class*="retailer"],[class*="Retailer"],[class*="store"],[class*="Store"]');
const nameEl = card.querySelector('[class*="title"],[class*="name"],h3,h2');
const brandEl = card.querySelector('[class*="brand"],[class*="Brand"]');
const descEl = card.querySelector('[class*="desc"],[class*="info"],[class*="detail"]');
if (priceEl) price = priceEl.textContent.trim();
if (retailEl) retailer = retailEl.textContent.trim();
if (nameEl) name = nameEl.textContent.trim();
if (brandEl) brand = brandEl.textContent.trim();
if (descEl) description = descEl.textContent.trim();
results.push({
name, brand, price, oldPrice, retailer, validity, dateRange, description,
image: img?.src || null,
});
// Exakte Selektoren basierend auf marktguru HTML-Struktur
const cards = document.querySelectorAll('li.offer-list-item');
return Array.from(cards).map(card => {
const name = card.querySelector('h3')?.textContent?.trim() || '';
const brand = card.querySelector('dd.brand a')?.textContent?.trim() || '';
const price = card.querySelector('span.price')?.textContent?.trim() || '';
const oldPrice = card.querySelector('.price-bubble .old-price, .crossed')?.textContent?.trim() || '';
const retailer = card.querySelector('dd.retailer-name a')?.textContent?.trim() || '';
const dateRange= card.querySelector('dd.valid')?.textContent?.trim() || '';
const daysLeft = card.querySelector('dd.time-left span')?.textContent?.trim() || '';
const daysText = card.querySelector('dd.time-left')?.textContent?.trim() || '';
const validity = daysLeft ? `Noch ${daysLeft} Tag${daysLeft==='1'?'':'e'}` :
card.querySelector('dt.time-left')?.textContent?.includes('Brandneu') ? 'Neu' : '';
const descEl = card.querySelector('.info div, .info');
const description = descEl?.textContent?.trim() || '';
const img = card.querySelector('img.offer-list-item-img');
const badge = card.querySelector('.badge, .discount-badge, [class*="badge"]')?.textContent?.trim() || '';
return { name, brand, price, oldPrice, retailer, dateRange, validity, description, badge, image: img?.src || null };
});
return results;
});
// Filtern auf Ziel-Händler + nur König Pilsener