← 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();