← back to Hollywood Import

innov-price-crawl.mjs

45 lines

// Innovations authed price crawl for our 2 DB-only patterns (Anjuna, Faux Glass Bead).
// Read-only on the vendor + local stage only (NO Shopify/canonical push — gated).
// Uses the saved innov-auth.json session (no re-login). Sequential + throttled.
import { chromium } from 'playwright';
import fs from 'node:fs';

const BASE = 'https://www.innovationsusa.com';
const TERMS = ['anjuna', 'faux glass bead', 'glass bead', 'textured vinyl'];
const sleep = (ms) => new Promise(r => setTimeout(r, ms));

const browser = await chromium.launch({ channel: 'chrome', headless: true });
const ctx = await browser.newContext({ storageState: './innov-auth.json', viewport: { width: 1400, height: 1000 } });
const page = await ctx.newPage();

const seen = new Set();
const out = { ranAt: new Date().toISOString(), perTerm: [], items: [] };

for (const q of TERMS) {
  const url = `${BASE}/search/${encodeURIComponent(q)}`;
  const resp = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 }).catch(() => null);
  await sleep(2500);
  const links = await page.evaluate(() =>
    [...document.querySelectorAll('a[href*="/item/"]')].map(a => a.getAttribute('href'))
      .filter((v, i, a) => a.indexOf(v) === i).slice(0, 12));
  out.perTerm.push({ term: q, status: resp ? resp.status() : null, found: links.length, links });
  for (const href of links) {
    const u = href.startsWith('http') ? href : BASE + href;
    if (seen.has(u)) continue; seen.add(u);
    await page.goto(u, { waitUntil: 'domcontentloaded', timeout: 30000 }).catch(() => {});
    await sleep(1800);
    const r = await page.evaluate(() => {
      const t = document.body.innerText;
      const h1 = (document.querySelector('h1,h2')?.innerText || '').trim();
      const prices = [...t.matchAll(/\$\s?\d[\d,]*\.\d{2}\s*(\/\s*(yard|yd|roll|sq|panel|each))?/gi)].map(m => m[0].trim()).slice(0, 6);
      return { title: h1, prices, hasPrice: /\$\d/.test(t) };
    });
    out.items.push({ url: u, title: r.title, prices: r.prices });
    console.log(`  ${u.replace(BASE, '')} → ${r.title} → ${JSON.stringify(r.prices)}`);
  }
}

fs.writeFileSync(new URL('innov-prices-staged.json', import.meta.url), JSON.stringify(out, null, 2));
console.log(`\nTERMS:${TERMS.length}  item-pages:${out.items.length}  priced:${out.items.filter(i => i.prices.length).length}`);
await browser.close();