← back to Dw Marketing Reels

harvest-ol-family.cjs

83 lines

'use strict';
// Harvest real product image URLs for the blocked O&L-family vendors (osborneandlittle.com,
// designersguild.com) via ONE Browserbase cloud session (residential IP bypasses the local block).
// For each target: goto known product_url OR run the site's own search by mfr_sku, then read
// og:image + product-gallery <img> srcs. Prints JSON. Does NOT download (curl-download the URLs
// afterward from this box — the CDN image hosts are reachable even when the html host isn't).
const os = require('os'), fs = require('fs');
require('dotenv').config({ path: os.homedir() + '/.claude/skills/browserbase/.env' });
const Browserbase = require('@browserbasehq/sdk').default;
const { chromium } = require('playwright-core');
const sleep = ms => new Promise(r => setTimeout(r, ms));

// targets: {sku, pattern, url? , searchUrl?}
const OL = 'https://www.osborneandlittle.com';
const targets = [
  { sku:'W7814-01', pattern:'Colonnato',       url:`${OL}/colonnato-w7814.html` },
  { sku:'W7682-01', pattern:'Coralline',       url:`${OL}/coralline-w7682.html` },
  { sku:'W7024-03', pattern:'Japanese Garden', url:`${OL}/japanese-garden-w7024-w7024.html` },
  { sku:'W6541-02', pattern:'Peacock',         url:`${OL}/peacock-w6541.html` },
  { sku:'W5223-03', pattern:'Tamba',           url:`${OL}/tamba-w5223.html` },
  { sku:'W7334-1',  pattern:'Trailing Orchid', search:`${OL}/catalogsearch/result/?q=W7334` },
  { sku:'EUR-70328',pattern:'Audley',          search:`${OL}/catalogsearch/result/?q=Audley` },
  { sku:'EUR-70402',pattern:'Canestra',        search:`${OL}/catalogsearch/result/?q=Canestra` },
  { sku:'EUR-70351',pattern:'Chameleon',       search:`${OL}/catalogsearch/result/?q=Chameleon` },
  { sku:'PDG1062-01',pattern:'Surimono',       search:`https://www.designersguild.com/uk/search?q=Surimono`, vendor:'DG' },
  { sku:'NCW4270-03',pattern:'Coromandel',     search:`${OL}/catalogsearch/result/?q=NCW4270`, vendor:'NC' },
  { sku:'NCW4270-05',pattern:'Coromandel',     search:`${OL}/catalogsearch/result/?q=NCW4270`, vendor:'NC' },
];

async function readImgs(page){
  return await page.evaluate(() => {
    const out = { og:null, gallery:[], title:document.title };
    const og = document.querySelector('meta[property="og:image"]');
    if (og) out.og = og.content;
    // magento gallery
    document.querySelectorAll('img').forEach(im => {
      const s = im.src || im.getAttribute('data-src') || '';
      if (/media\/catalog\/product|\/product\//i.test(s) && !/AVATAR|logo|placeholder/i.test(s)) out.gallery.push(s);
    });
    // magento JSON gallery in script
    const m = document.body.innerHTML.match(/"data":\s*\[\s*\{[^\]]*?"img":"([^"]+)"/);
    if (m) out.galleryJson = m[1].replace(/\\\//g,'/');
    return out;
  });
}

(async () => {
  const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY });
  const session = await bb.sessions.create({ projectId: process.env.BROWSERBASE_PROJECT_ID, browserSettings: { solveCaptchas: true } });
  console.error('session', session.id, 'debug:', session.debuggerUrl || '');
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0].pages()[0] || await browser.contexts()[0].newPage();
  page.setDefaultTimeout(45000);
  const results = [];
  for (const t of targets){
    const r = { sku:t.sku, pattern:t.pattern, vendor:t.vendor||'OL' };
    try {
      if (t.url){
        await page.goto(t.url, { waitUntil:'domcontentloaded' }).catch(()=>{});
        await sleep(2500);
        if (/404|not found|page not found/i.test(await page.title())) { r.note='url-404, trying pattern search'; }
      }
      if (!t.url || (r.note && t.search)) {
        if (t.search){ await page.goto(t.search, { waitUntil:'domcontentloaded' }).catch(()=>{}); await sleep(2500);
          // click first product result
          const link = await page.$('a.product-item-link, .product-item a[href*=".html"], a.product-item-photo, .product-item-info a');
          if (link){ const href = await link.getAttribute('href'); r.resolvedUrl=href; await page.goto(href,{waitUntil:'domcontentloaded'}).catch(()=>{}); await sleep(2500); }
          else r.note = (r.note?r.note+'; ':'') + 'no search result';
        }
      }
      r.finalUrl = page.url();
      const imgs = await readImgs(page);
      r.pageTitle = imgs.title; r.og = imgs.og; r.gallery = [...new Set(imgs.gallery)].slice(0,6); r.galleryJson = imgs.galleryJson;
    } catch(e){ r.error = e.message; }
    console.error(`[${r.sku}] ${r.finalUrl||''} og=${r.og?'Y':'N'} gal=${(r.gallery||[]).length}`);
    results.push(r);
  }
  await browser.close().catch(()=>{});
  const fp = os.homedir()+'/Projects/dw-marketing-reels/harvest-ol-results.json';
  fs.writeFileSync(fp, JSON.stringify(results,null,2));
  console.log(fp);
})().catch(e=>{ console.error('FATAL', e.message); process.exit(1); });