// Usage: node render-yandex-list.cjs // Рендер страницы категории Яндекс.Карт локальным Playwright (Firecrawl её не берёт, §12.2). // Скроллит КОНТЕЙНЕР СПИСКА результатов (подгрузка ленивая) и печатает JSON: // { orgs: [{ name, id, href }] } — имя + id + ссылка на карточку организации. // Сайт в списке Яндекса НЕ отдаётся (только на карточке) — здесь не собираем (шаг 1 = имя+карточка). // require('playwright') резолвится из node_modules корня репо (скрипт лежит под app/scripts). const { chromium } = require('playwright'); (async () => { const url = process.argv[2]; let parsed; try { parsed = new URL(url); } catch (e) { console.error('bad url'); process.exit(2); } if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') { console.error('bad scheme'); process.exit(2); } const browser = await chromium.launch({ headless: true }); try { const page = await browser.newPage({ locale: 'ru-RU' }); await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 }); await page.waitForTimeout(4000); // Ленивая лента результатов — скроллим её контейнер, пока подгружается. for (let i = 0; i < 14; i++) { await page.evaluate(() => { const el = document.querySelector('.scroll__container, .search-list-view__list, [class*="search-list"]'); if (el) el.scrollBy(0, 2000); }); await page.waitForTimeout(800); } const orgs = await page.$$eval('a[href*="/maps/org/"]', (els) => { const seen = new Set(); const out = []; for (const e of els) { const href = e.getAttribute('href') || ''; const m = href.match(/\/maps\/org\/[a-z0-9_-]+\/(\d+)/i); if (!m || seen.has(m[1])) continue; seen.add(m[1]); const name = (e.getAttribute('aria-label') || e.textContent || '').trim(); if (name) out.push({ name, id: m[1], href: href.split('?')[0] }); } return out; }); process.stdout.write(JSON.stringify({ orgs })); } finally { await browser.close(); } })().catch((e) => { console.error(String(e)); process.exit(1); });