{
  "version": "1.0.0",
  "exported_at": "2026-06-02T23:00:00.000Z",
  "project": {
    "name": "Liverpool Details Scraper",
    "description": "Scrapes Liverpool México product detail pages and exports Product, Product URL, Product Image URL, Product Code, Reviews, Price, Original Price, Color, Brand, and Rating. Navigation strategy: multi-input detail URL loop using navigate.urls[] plus loop-continue, so every supplied PDP URL is visited and appended to one CSV. Replace or extend the sample URLs with your own Liverpool PDP URLs. Some old PDP URLs may return 404, load only placeholder assets, or trigger CAPTCHA; those rows may have blank fields rather than unrelated carousel data.",
    "color": "bg-[#e10098]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 120,
      "position_y": 200,
      "config": {
        "urls": [
          "https://www.liverpool.com.mx/tienda/pdp/colch%C3%B3n-spring-air-volt-confort-medio/1122913109?skuid=1117626977",
          "https://www.liverpool.com.mx/tienda/pdp/mortero-wood-planks-mx-calli/1142438638?skuid=1142438638",
          "https://www.liverpool.com.mx/tienda/pdp/mortero-&-pistilo-chef'n/1063879785?skuid=1063879785",
          "https://www.liverpool.com.mx/tienda/pdp/antena-digital-de-televisi%C3%B3n-lab.g/1134922466?skuid=1134922466",
          "https://www.liverpool.com.mx/tienda/pdp/antena-para-tv-hd-aksi-116112/1105651712?skuid=1105651712",
          "https://www.liverpool.com.mx/tienda/pdp/proyector-port%C3%A1til-hype-m24/9949222708?skuid=1129009451",
          "https://www.liverpool.com.mx/tienda/pdp/proyector-xgimi-mogo-pro+/1143041634?skuid=1143041634"
        ],
        "color": "bg-[#e10098]"
      }
    },
    {
      "block_id": "wait-for-page-load-1",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 480,
      "position_y": 200,
      "config": {
        "timeout": 45
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 840,
      "position_y": 200,
      "config": {
        "duration": 4
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1200,
      "position_y": 200,
      "config": {
        "rowSelector": "body",
        "fileName": "liverpool-detalles-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "columns": [
          {
            "name": "Producto",
            "selector": "(() => { const h1 = ROW.querySelector('h1.a-product__information--title')?.textContent || ROW.querySelector('h1')?.textContent || ''; const meta = document.querySelector('meta[property=\"og:title\"], meta[name=\"twitter:title\"]')?.content || ''; const value = h1 || (meta && meta !== 'Liverpool México' ? meta : ''); return value.trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Producto_URL",
            "selector": "(() => location.href)()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Imagen_URL",
            "selector": "(() => { const params = new URLSearchParams(location.search); const sku = params.get('skuid') || ''; const pathCode = (location.pathname.match(/\\/(\\d+)(?:$|[/?#])/) || [])[1] || ''; const codes = [sku, pathCode].filter(Boolean); const title = (ROW.querySelector('h1.a-product__information--title')?.textContent || ROW.querySelector('h1')?.textContent || '').trim(); const raw = []; const add = v => { if (!v) return; String(v).split(/\\s*,\\s*/).forEach(part => { const u = part.trim().split(/\\s+/)[0]; if (/^https?:\\/\\//i.test(u)) raw.push(u); }); }; ROW.querySelectorAll('#image-real, img.m-img-pdp, img.pdpthumb, .o-gallery__pdp--desktop img, .viewerImg img, img[alt]').forEach(img => { add(img.getAttribute('src')); add(img.currentSrc); add(img.getAttribute('data-src')); add(img.getAttribute('data-lazy')); add(img.getAttribute('data-original')); add(img.getAttribute('srcset')); add(img.getAttribute('data-srcset')); }); document.querySelectorAll('meta[property=\"og:image\"], meta[name=\"twitter:image\"], link[rel=\"image_src\"]').forEach(el => add(el.getAttribute('content') || el.getAttribute('href'))); const html = document.documentElement.innerHTML; const re = /https?:\\\\?\\/\\\\?\\/ss\\d+\\.[^\\s\"'<>\\\\]+?\\/(?:xl|lg|z|sm)\\/[^\\s\"'<>\\\\]+?\\.(?:jpg|jpeg|png|webp)/gi; let m; while ((m = re.exec(html)) !== null) add(m[0].replace(/\\\\\\//g, '/')); const clean = Array.from(new Set(raw.map(u => u.replace(/&amp;/g, '&').replace('/lg/', '/xl/').replace('/z/', '/xl/')))); const valid = clean.filter(u => /^https?:\\/\\/ss\\d+\\./i.test(u) && /\\.(jpg|jpeg|png|webp)(\\?|$)/i.test(u) && !/assetspwa|logo|loader|loading|placeholder|sprite/i.test(u)); const withCode = valid.find(u => codes.some(c => c && u.includes(c))); if (withCode) return withCode; return title ? (valid[0] || '') : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Código_de_producto",
            "selector": "(() => { const direct = ROW.querySelector('.product-header-subcontainer-information--code span')?.textContent?.trim(); if (direct) return direct; const text = ROW.textContent || ''; const fromText = text.match(/Código de Producto:\\s*(\\d+)/i); if (fromText) return fromText[1]; const fromPath = location.pathname.match(/\\/(\\d+)(?:$|[/?#])/); return fromPath ? fromPath[1] : (new URLSearchParams(location.search).get('skuid') || ''); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Opiniones",
            "selector": "(() => { const reviewText = ROW.querySelector('.TTreadReviews, .RRMoreR')?.textContent || ROW.textContent || ''; const match = reviewText.match(/(\\d+)\\s*opiniones?/i); return match ? match[1] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Precio",
            "selector": "(() => { const fmt = el => { if (!el) return ''; let s = (el.innerText || el.textContent || '').replace(/\\s+/g, ' ').trim(); if (/^\\$[\\d,]+\\d{2}$/.test(s)) s = s.replace(/(\\d{2})$/, ' $1'); return s; }; const discount = fmt(ROW.querySelector('.a-product__paragraphDiscountPrice')); const regular = fmt(ROW.querySelector('.a-product__paragraphRegularPrice')); return discount || regular; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Precio_original",
            "selector": "(() => { const fmt = el => { if (!el) return ''; let s = (el.innerText || el.textContent || '').replace(/\\s+/g, ' ').trim(); if (/^\\$[\\d,]+\\d{2}$/.test(s)) s = s.replace(/(\\d{2})$/, ' $1'); return s; }; const discount = fmt(ROW.querySelector('.a-product__paragraphDiscountPrice')); const regular = fmt(ROW.querySelector('.a-product__paragraphRegularPrice')); return discount && regular ? regular : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Color",
            "selector": "(() => { const value = ROW.querySelector('.attributeAccordionContainer.colors .attributeAccordionTextValue, .attributeAccordionTextValue')?.textContent || ''; const heading = Array.from(ROW.querySelectorAll('h3')).map(h => h.textContent || '').find(t => /^Color:/i.test(t)); return (value || (heading ? heading.replace(/^Color:\\s*/i, '') : '')).trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Marca",
            "selector": "(() => { return (ROW.querySelector('.brandTitleOffBrand')?.textContent || '').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Calificación",
            "selector": "(() => { const el = ROW.querySelector('[class*=\"TTrating-\"]'); const cls = el ? Array.from(el.classList).join(' ') : ''; const match = cls.match(/TTrating-(\\d+)-(\\d+)/); return match ? `${match[1]},${match[2]} / 5,0` : ''; })()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 1560,
      "position_y": 200,
      "config": {}
    }
  ],
  "connections": [
    {
      "from_block_id": "navigate-1",
      "from_connector_id": "right",
      "to_block_id": "wait-for-page-load-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-page-load-1",
      "from_connector_id": "right",
      "to_block_id": "sleep-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-1",
      "from_connector_id": "right",
      "to_block_id": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-1",
      "from_connector_id": "right",
      "to_block_id": "loop-continue-1",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 48,
      "position_y": 96,
      "width": 1040,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 1128,
      "position_y": 96,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1488,
      "position_y": 96,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Liverpool México product detail pages and exports Product, Product URL, Product Image URL, Product Code, Reviews, Price, Original Price, Color, Brand, and Rating. Navigation strategy: multi-input detail URL loop using navigate.urls[] plus loop-continue, so every supplied PDP URL is visited and appended to one CSV. Replace or extend the sample URLs with your own Liverpool PDP URLs. Some old PDP URLs may return 404, load only placeholder assets, or trigger CAPTCHA; those rows may have blank fields rather than unrelated carousel data.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (Producto, Producto_URL, Imagen_URL, Código_de_producto, Opiniones). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 1400,
      "position_y": 180,
      "width": 340,
      "height": 135,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    },
    {
      "id": "note-block-loop-continue-1",
      "element_type": "note",
      "title": "Note: Loop Continue",
      "content": "Loop Continue advances a multi-URL or multi-text loop. Place at the end of the loop body with a clear back-edge to the loop start.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 180,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}