import puppeteer from 'puppeteer'; async function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } async function main() { const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], }); const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); await page.setRequestInterception(true); page.on('request', (req) => { if (['image', 'font', 'media'].includes(req.resourceType())) { req.abort(); } else { req.continue(); } }); await page.goto('https://shop.bestdispensary.com/brands', { waitUntil: 'networkidle2', timeout: 60000 }); await sleep(3000); // Bypass age gate const ageGate = await page.$('[data-testid="age-gate-modal"]'); if (ageGate) { const btn = await page.$('[data-testid="age-gate-submit-button"]'); if (btn) await btn.click(); await sleep(2000); } // Use the selector hint: /html/body/main/section console.log('Looking at main > section structure...\n'); const sectionInfo = await page.evaluate(() => { const main = document.querySelector('main'); if (!main) return { error: 'No main element' }; const sections = main.querySelectorAll('section'); const results: any[] = []; sections.forEach((section, i) => { const children = section.children; const childInfo: string[] = []; for (let j = 0; j < Math.min(children.length, 10); j++) { const child = children[j]; childInfo.push(child.tagName + '.' + (child.className?.slice(0, 30) || '')); } results.push({ index: i, class: section.className?.slice(0, 50), childCount: children.length, sampleChildren: childInfo, }); }); return results; }); console.log('Sections in main:'); console.log(JSON.stringify(sectionInfo, null, 2)); // Look for brand cards within the section console.log('\nLooking for brand cards in main > section...'); const brandCards = await page.evaluate(() => { const section = document.querySelector('main > section'); if (!section) return []; // Get all child elements that might be brand cards const cards: { tag: string; text: string; href: string }[] = []; section.querySelectorAll('a').forEach((a: Element) => { const href = a.getAttribute('href') || ''; const text = a.textContent?.trim().slice(0, 50) || ''; cards.push({ tag: 'a', text, href }); }); return cards; }); console.log(`Found ${brandCards.length} links in section:`); brandCards.slice(0, 30).forEach(c => console.log(` ${c.text} -> ${c.href}`)); // Get the grid of brand cards console.log('\nLooking for grid container...'); const gridCards = await page.evaluate(() => { // Look for grid-like containers const grids = document.querySelectorAll('[class*="grid"], [class*="Grid"], main section > div'); const results: any[] = []; grids.forEach((grid, i) => { const links = grid.querySelectorAll('a[href*="/brand/"]'); if (links.length > 5) { const brands: string[] = []; links.forEach((a: Element) => { const text = a.textContent?.trim().split('\n')[0] || ''; if (text && !brands.includes(text)) brands.push(text); }); results.push({ class: grid.className?.slice(0, 40), brandCount: brands.length, brands: brands.slice(0, 50), }); } }); return results; }); console.log('Grid containers with brands:'); gridCards.forEach(g => { console.log(`\n[${g.brandCount} brands] class="${g.class}"`); g.brands.forEach((b: string, i: number) => console.log(` ${i+1}. ${b}`)); }); await browser.close(); } main().catch(console.error);