← back to Hollywood Import

momentum-recon4.mjs

52 lines

// Recon #4: dump exact DOM contract. (A) one /products grid CARD outerHTML (does it carry
// price + item number in bulk?). (B) Regale detail price-block outerHTML + item number,
// waiting for Livewire price hydration. Read-only. Reuses saved auth.
import { chromium } from 'playwright';
import fs from 'node:fs';
const STATE = new URL('momentum-auth.json', import.meta.url).pathname;
const BASE = 'https://momentumco.com';
const out = {};

const browser = await chromium.launch({ channel: 'chrome', headless: true });
const ctx = await browser.newContext({ storageState: STATE, viewport: { width: 1400, height: 1200 } });
const page = await ctx.newPage();

// (A) grid card
await page.goto(BASE + '/products?forceSync=1', { waitUntil: 'domcontentloaded', timeout: 60000 }).catch(()=>{});
await page.waitForTimeout(6000);
await page.mouse.wheel(0, 3000); await page.waitForTimeout(3000);
out.gridCard = await page.evaluate(() => {
  const a = document.querySelector('a[href*="/products/"]');
  if (!a) return null;
  // climb to the card container
  let card = a; for (let i=0;i<5 && card.parentElement;i++){ card = card.parentElement; if ((card.innerText||'').match(/\$\d/)) break; }
  return { href: a.getAttribute('href'), cardHasPrice: /\$\d/.test(card.innerText||''),
    cardText: (card.innerText||'').replace(/\s+/g,' ').slice(0,400),
    cardHTML: card.outerHTML.slice(0, 2500) };
});

// (B) detail with price hydration wait
await page.goto(BASE + '/products/09153923', { waitUntil: 'domcontentloaded', timeout: 60000 }).catch(()=>{});
await page.waitForFunction(() => /\$\s?\d[\d,]*\.\d{2}/.test(document.body.innerText), { timeout: 20000 }).catch(()=>{});
await page.waitForTimeout(2000);
out.detail = await page.evaluate(() => {
  // find smallest element containing the per-unit price label
  let block = null;
  for (const el of document.querySelectorAll('div,section,table,ul')) {
    const t = el.innerText || '';
    if (/Price\s*:?\s*\$\d/i.test(t) && t.length < 700) { block = el; break; }
  }
  const body = document.body.innerText;
  return {
    title: document.title,
    itemNumberLine: (body.match(/.{0,30}(item|sku|product)\s*#?.{0,30}/i)||[])[0] || null,
    codes: [...new Set((body.match(/\b[A-Z]{2,5}-\d{2,6}\b/g)||[]))].slice(0,12),
    priceBlockText: block ? block.innerText.replace(/\n+/g,' | ') : null,
    priceBlockHTML: block ? block.outerHTML.slice(0, 2500) : null,
  };
});

fs.writeFileSync(new URL('recon4-out.json', import.meta.url), JSON.stringify(out, null, 2));
console.log(JSON.stringify(out, null, 2).slice(0, 4000));
await browser.close();