{
  "version": "1.0.0",
  "exported_at": "2026-06-01T13:15:00.000Z",
  "project": {
    "name": "Falabella Retail Details Scraper",
    "description": "Scrapes Falabella product detail pages by URL, exporting product code, store code, brand, title, sale/current/original prices, URL, rating/review count when available, up to five product image URLs, size/type/gender when available, and cleaned specifications. Navigation uses a multi-URL input loop: add product detail URLs to navigate.urls; each URL produces one CSV row. Price extraction is scoped to the product purchase area to avoid unrelated recommendation/service prices.",
    "color": "bg-[#4589ff]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "set-window-size-1",
      "block_type": "process",
      "title": "Set Window Size",
      "description": "Set browser window dimensions",
      "position_x": 120,
      "position_y": 220,
      "config": {
        "width": 1920,
        "height": 1080,
        "color": "bg-[#4589ff]"
      }
    },
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 480,
      "position_y": 220,
      "config": {
        "urls": [
          "https://www.falabella.com.pe/falabella-pe/product/prod17640011/Mesa-De-Tv-Irlanda-65-/883013089"
        ],
        "color": "bg-[#4589ff]",
        "tags": [
          "replace-with-product-detail-urls",
          "multi-url-loop"
        ]
      }
    },
    {
      "block_id": "wait-for-page-load-1",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 840,
      "position_y": 220,
      "config": {
        "timeout": 45,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "duration": 4,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 1560,
      "position_y": 220,
      "config": {
        "selector": "body",
        "timeout": 30,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute JavaScript on page",
      "position_x": 1920,
      "position_y": 220,
      "config": {
        "jsCode": "(() => { const clean = v => (v == null ? '' : String(v)).replace(/\\s+/g, ' ').trim(); const decode = v => { const el = document.createElement('textarea'); el.innerHTML = clean(v); return el.value; }; const uniq = arr => arr.filter((v, i, a) => v && a.indexOf(v) === i); const bodyText = document.body ? document.body.innerText : ''; try { const btn = Array.from(document.querySelectorAll('button, [role=button], a')).find(e => /^(aceptar|acepto|accept|entendido|cerrar)$/i.test(clean(e.innerText || e.textContent))); if (btn) btn.click(); } catch (e) {} const url = location.href; const pathParts = url.split(/[?#]/)[0].split('/').filter(Boolean); const codigo = decodeURIComponent(pathParts[pathParts.length - 1] || ''); const jsonObjects = []; const addJson = t => { try { const s = clean(t); if (!s) return; if (s[0] === '{' || s[0] === '[') jsonObjects.push(JSON.parse(s)); } catch (e) {} }; Array.from(document.scripts).forEach(s => { if (s.type === 'application/ld+json' || s.id === '__NEXT_DATA__' || /application\\/json/i.test(s.type || '')) addJson(s.textContent); }); const walk = (o, fn, depth = 0) => { if (!o || depth > 16) return; if (Array.isArray(o)) { o.forEach(x => walk(x, fn, depth + 1)); return; } if (typeof o === 'object') { fn(o); Object.keys(o).forEach(k => walk(o[k], fn, depth + 1)); } }; const deepVal = keys => { const wanted = keys.map(k => String(k).toLowerCase()); let found = ''; for (const root of jsonObjects) { walk(root, obj => { if (found) return; for (const k of Object.keys(obj)) { if (wanted.includes(String(k).toLowerCase()) && obj[k] != null && typeof obj[k] !== 'object') { found = clean(obj[k]); return; } } }); if (found) break; } return found; }; const products = []; jsonObjects.forEach(root => walk(root, obj => { const type = obj && (obj['@type'] || obj.type); if (type && String(type).toLowerCase().includes('product')) products.push(obj); })); const product = products.find(p => clean(p.sku || p.productId || p.id).includes(codigo)) || products[0] || {}; const brandObj = product.brand; const marca = decode((brandObj && (brandObj.name || brandObj.brandName)) || deepVal(['brandName', 'brand', 'marca']) || ''); const offers = Array.isArray(product.offers) ? product.offers[0] : (product.offers || {}); const titulo = decode(product.name || deepVal(['productName', 'displayName', 'name']) || (document.querySelector('h1') && document.querySelector('h1').innerText) || (document.querySelector('meta[property=og:title]') && document.querySelector('meta[property=og:title]').content) || document.title).replace(/\\s*\\|\\s*Falabella.*$/i, ''); const codigo_tienda = clean(deepVal(['storeCode', 'sellerSkuId', 'sellerSku', 'skuSeller', 'sku', 'skuId', 'codigoTienda']) || codigo); const normPrice = p => { const m = clean(p).match(/S\\/\\s*([0-9][0-9.,]*)/i); if (!m) return ''; return 'S/ ' + m[1]; }; const priceNum = p => { const m = clean(p).match(/([0-9][0-9.,]*)/); return m ? parseFloat(m[1].replace(/,/g, '')) : 0; }; const priceList = txt => uniq((txt.match(/S\\/\\s*[0-9][0-9.,]*(?:\\s*m²)?/g) || []).map(normPrice).filter(Boolean)); const cartIndex = bodyText.search(/Agregar al Carro|Agregar a la bolsa|Comprar/i); let productText = ''; if (cartIndex > 0) productText = bodyText.slice(Math.max(0, cartIndex - 1600), Math.min(bodyText.length, cartIndex + 350)); else productText = bodyText.slice(0, 3500); productText = productText.replace(/Servicios adicionales[\\s\\S]*$/i, ''); let nearPrices = priceList(productText); let allPrices = priceList(bodyText); const offerPrice = offers && offers.price ? normPrice('S/ ' + clean(offers.price)) : ''; let precio_rebaja = offerPrice || nearPrices[0] || allPrices[0] || ''; const saleNum = priceNum(precio_rebaja); const saneHigher = p => priceNum(p) > saleNum + 0.01 && priceNum(p) <= saleNum * 4; let higherNearPrices = uniq(nearPrices).filter(saneHigher).sort((a, b) => priceNum(a) - priceNum(b)); let higherAllPrices = uniq(allPrices).filter(saneHigher).sort((a, b) => priceNum(a) - priceNum(b)); let higherPrices = higherNearPrices.length ? higherNearPrices : higherAllPrices; let precio_actual = higherPrices[0] || precio_rebaja; let precio_original = higherPrices[higherPrices.length - 1] || ''; if (precio_original === precio_rebaja) precio_original = ''; const rawImages = []; const addImg = src => { src = clean(src); if (src && !/teads|track|pixel|\\.svg|data:image|base64|assets\\/blt/i.test(src)) rawImages.push(src); }; if (Array.isArray(product.image)) product.image.forEach(addImg); else addImg(product.image); Array.from(document.images).forEach(img => addImg(img.currentSrc || img.src || img.getAttribute('data-src'))); Array.from(document.querySelectorAll('source')).forEach(s => addImg(s.srcset && s.srcset.split(' ')[0])); Array.from(document.querySelectorAll('meta')).forEach(m => { if (/og:image/i.test(clean(m.getAttribute('property')))) addImg(m.content); }); const codeParts = uniq([codigo, codigo_tienda].filter(Boolean)); const imageByIndex = {}; const imageScore = u => (/w=800,h=800/i.test(u) ? 4 : 0) + (/imagedelivery/i.test(u) ? 3 : 0) + (/\\/public/i.test(u) ? 2 : 0) + (/media\\.falabella/i.test(u) ? 1 : 0); uniq(rawImages).forEach(src => { if (!codeParts.some(c => src.includes(c))) return; if (!/falabella|sodimac|imagedelivery|media/i.test(src)) return; let u = src.replace(/w=100,h=100/gi, 'w=800,h=800'); const m = u.match(/_(\\d+)(?:\\/|_|\\.|$)/); const idx = m ? parseInt(m[1], 10) : 999; if (!imageByIndex[idx] || imageScore(u) > imageScore(imageByIndex[idx])) imageByIndex[idx] = u; }); const base = imageByIndex[1] || ''; if (base) { for (let i = 2; i <= 5; i++) { if (!imageByIndex[i] && /_1(?=\\/|_|\\.|$)/.test(base)) imageByIndex[i] = base.replace(/_1(?=\\/|_|\\.|$)/, '_' + i); } } const images = Object.keys(imageByIndex).map(Number).filter(n => n >= 1 && n <= 5).sort((a, b) => a - b).map(n => imageByIndex[n]).slice(0, 5); const agg = product.aggregateRating || {}; const ratingRegex = bodyText.match(/([0-5](?:[\\.,][0-9])?)\\s*(?:de\\s*5|estrellas|calificaci[oó]n|rating)/i); const reviewRegex = bodyText.match(/([0-9]+)\\s*(?:comentarios|opiniones|reseñas|reviews|calificaciones)/i); const rating = clean(agg.ratingValue || deepVal(['ratingValue', 'averageRating', 'rating']) || (ratingRegex && ratingRegex[1]) || ''); const comentario = clean(agg.reviewCount || agg.ratingCount || deepVal(['reviewCount', 'ratingCount', 'totalReviews', 'commentCount']) || (reviewRegex && reviewRegex[1]) || ''); const specCandidates = Array.from(document.querySelectorAll('section, div, table, dl, ul')).map(e => clean(e.innerText)).filter(t => t.length > 40 && t.length < 2200 && /(Tipo|Material|Modelo|Ancho|Alto|Requiere|Condici[oó]n|Especificaciones|Garant[ií]a)/i.test(t)); const labelScore = t => ['Tipo', 'Material', 'Modelo', 'Ancho', 'Alto', 'Profundidad', 'Garantía', 'Requiere', 'Condicion', 'Condición'].reduce((n, l) => n + (t.toLowerCase().includes(l.toLowerCase()) ? 1 : 0), 0); specCandidates.sort((a, b) => (labelScore(b) - labelScore(a)) || (a.length - b.length)); let especificacion = specCandidates[0] || ''; if (!especificacion) { const start = bodyText.search(/Especificaciones principales|Tipo de rack|Material|Modelo/i); const end = bodyText.search(/Código:|Cód\\. tienda|Entrega en|Agregar al Carro/i); especificacion = start >= 0 ? bodyText.slice(start, end > start ? end : start + 1800) : ''; } especificacion = clean(especificacion.replace(/Color:\\s*[^\\n]+?Agregar al Carro/gi, ' ').replace(/\\bVer más especificaciones\\b/gi, ' ').replace(/Código:\\s*\\d+.*$/i, ' ')); const findField = names => { for (const name of names) { const re = new RegExp(name + '\\\\s*:?\\\\s*([^\\\\n:]{1,90})', 'i'); const m = especificacion.match(re) || bodyText.match(re); if (m) return clean(m[1]).replace(/\\s+(Material|Modelo|Ancho|Alto|Profundidad|Dificultad|Requiere|Garant[ií]a|Tipo de ensamblado).*$/i, ''); } return ''; }; const tamano = findField(['Tamaño', 'Talla', 'Size', 'Capacidad para TV', 'Número de puestos']); const tipo = findField(['Tipo de rack', 'Tipo']); const genero = findField(['Género', 'Genero', 'Gender']); window.__uscraperFalabellaProduct = { codigo, codigo_tienda, marca, titulo, precio_rebaja, precio_actual, precio_original, producto_url: url, rating, comentario, imagen1: images[0] || '', imagen2: images[1] || '', imagen3: images[2] || '', imagen4: images[3] || '', imagen5: images[4] || '', tamano, tipo, genero, especificacion }; })();",
        "waitForCompletion": true,
        "timeout": 20,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2280,
      "position_y": 220,
      "config": {
        "rowSelector": "body",
        "fileName": "falabella-retail-detalles-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "codigo",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.codigo) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "codigo_tienda",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.codigo_tienda) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "marca",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.marca) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "titulo",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.titulo) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "precio_rebaja",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.precio_rebaja) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "precio_actual",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.precio_actual) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "precio_original",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.precio_original) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "producto_url",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.producto_url) || location.href",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.rating) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "comentario",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.comentario) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "imagen1",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.imagen1) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "imagen2",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.imagen2) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "imagen3",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.imagen3) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "imagen4",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.imagen4) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "imagen5",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.imagen5) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "tamano",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.tamano) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "tipo",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.tipo) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "genero",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.genero) || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "especificacion",
            "selector": "(window.__uscraperFalabellaProduct && window.__uscraperFalabellaProduct.especificacion) || ''",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 2640,
      "position_y": 220,
      "config": {
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "end-1",
      "block_type": "output",
      "title": "End",
      "description": "Terminate execution flow",
      "position_x": 3000,
      "position_y": 220,
      "config": {
        "color": "bg-[#8d8d8d]"
      }
    }
  ],
  "connections": [
    {
      "from_block_id": "set-window-size-1",
      "from_connector_id": "right",
      "to_block_id": "navigate-1",
      "to_connector_id": "left"
    },
    {
      "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": "wait-for-element-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-1",
      "from_connector_id": "right",
      "to_block_id": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-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"
    },
    {
      "from_block_id": "loop-continue-1",
      "from_connector_id": "right",
      "to_block_id": "end-1",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-entry",
      "element_type": "group",
      "title": "Entry & Setup",
      "color": "#4589ff",
      "position_x": 48,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "set-window-size-1"
        ]
      }
    },
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 408,
      "position_y": 116,
      "width": 1400,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "wait-for-element-1"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1848,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2208,
      "position_y": 116,
      "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": 2568,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-control",
      "element_type": "group",
      "title": "Control Flow",
      "color": "#8d8d8d",
      "position_x": 2928,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "end-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Falabella product detail pages by URL, exporting product code, store code, brand, title, sale/current/original prices, URL, rating/review count when available, up to five product image URLs, size/type/gender when available, and cleaned specifications. Navigation uses a multi-URL input loop: add product detail URLs to navigate.urls; each URL produces one CSV row. Price extraction is scoped to the product purchase area to avoid unrelated recommendation/service prices.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-navigate-1",
      "element_type": "note",
      "title": "Note: Navigate",
      "content": "Multi-URL loop over 1 pages. Pair with loop-continue at the end of each iteration.",
      "color": "#ee5396",
      "position_x": 680,
      "position_y": 200,
      "width": 328,
      "height": 107,
      "z_index": 22,
      "data": {
        "block_id": "navigate-1"
      }
    },
    {
      "id": "note-block-inject-javascript-1",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(() => { const clean = v => (v == null ? '' : String(v)).replace(/\\s+/g, ' ').trim(); const decode =...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 200,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-1"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (codigo, codigo_tienda, marca, titulo, precio_rebaja). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2480,
      "position_y": 200,
      "width": 340,
      "height": 131,
      "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": 2840,
      "position_y": 200,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}