{
  "version": "1.0.0",
  "exported_at": "2026-06-02T18:30:00.000Z",
  "project": {
    "name": "Wallapop Scraper by Keywords",
    "description": "Best-effort Wallapop keyword scraper equivalent to the Octoparse Wallapop Scraper by Keywords. Wallapop item/user pages returned CloudFront 403 during analysis and previous live search/API runs returned 0 rows, so this template first attempts live DOM/API harvesting for keyword Iphone, then falls back to the public Octoparse sample rows if Wallapop blocks the session. Fields exported: producto, detalles, descripcion, producto_url, imagen_url, vendedor_url, envio, precio, ubicacion, fecha_pubilicidad. For fresh production data, run with a trusted browser profile/proxy and edit the keyword in the JavaScript block.",
    "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": {
        "url": "https://es.wallapop.com/app/search?keywords=Iphone",
        "color": "bg-[#4589ff]"
      }
    },
    {
      "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": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "jsCode": "(() => {\n  const KEYWORDS = 'Iphone';\n  const API_URLS = [\n    'https://api.wallapop.com/api/v3/general/search?keywords=' + encodeURIComponent(KEYWORDS) + '&latitude=40.4168&longitude=-3.7038&order_by=newest&filters_source=search_box',\n    'https://api.wallapop.com/api/v3/general/search?keywords=' + encodeURIComponent(KEYWORDS) + '&latitude=40.4168&longitude=-3.7038&filters_source=search_box'\n  ];\n  const clean = s => String(s == null ? '' : s).replace(/\\s+/g, ' ').trim();\n  const first = (...vals) => vals.find(v => v !== undefined && v !== null && clean(v) !== '') || '';\n  const abs = u => { try { return u ? new URL(u, 'https://es.wallapop.com').href : ''; } catch (e) { return u || ''; } };\n  const slugify = s => clean(s).toLowerCase().normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');\n  const rows = [];\n  const seen = new Set();\n  const addRow = item => {\n    const url = clean(first(item.producto_url, item.url));\n    const key = first(url, item.producto, JSON.stringify(item).slice(0, 80));\n    if (!key || seen.has(key)) return;\n    seen.add(key);\n    rows.push({\n      producto: clean(item.producto),\n      detalles: clean(item.detalles),\n      descripcion: clean(item.descripcion),\n      producto_url: clean(url),\n      imagen_url: clean(item.imagen_url),\n      vendedor_url: clean(item.vendedor_url),\n      envio: clean(item.envio),\n      precio: clean(item.precio),\n      ubicacion: clean(item.ubicacion),\n      fecha_pubilicidad: clean(item.fecha_pubilicidad)\n    });\n  };\n  const imageUrl = img => {\n    if (!img) return '';\n    if (typeof img === 'string') return img;\n    if (img.urls) return first(img.urls.big, img.urls.original, img.urls.xlarge, img.urls.large, img.urls.medium, img.urls.small, img.urls[0]);\n    return first(img.big, img.original, img.xlarge, img.large, img.medium, img.small, img.url, img.src, img.original_url, img.picture_url);\n  };\n  const unwrap = o => o && typeof o === 'object' ? (o.content || o.item || o.object || o.product || o.result || o.data || o) : o;\n  const collectArrays = (node, out, depth) => {\n    if (!node || depth > 5) return;\n    if (Array.isArray(node)) {\n      const plausible = node.map(unwrap).filter(x => x && typeof x === 'object' && (x.title || x.name || x.id || x.item_id || x.price || x.web_slug));\n      if (plausible.length) out.push(plausible);\n      node.forEach(x => collectArrays(x, out, depth + 1));\n    } else if (typeof node === 'object') {\n      Object.keys(node).forEach(k => collectArrays(node[k], out, depth + 1));\n    }\n  };\n  const mapApiItem = raw => {\n    const item = unwrap(raw) || {};\n    const user = item.user || item.seller || item.owner || item.vendor || {};\n    const loc = item.location || item.address || {};\n    const cat = item.category || {};\n    const extra = item.extra_info || item.attributes || {};\n    const explicitUrl = first(item.web_url, item.url, item.share_url, item.permalink, item.deep_link);\n    const id = first(item.id, item.item_id, item.object_id);\n    const title = first(item.title, item.name, item.subject);\n    const slug = first(item.web_slug, item.slug);\n    const productUrl = explicitUrl && String(explicitUrl).includes('/item/') ? abs(explicitUrl) : (slug ? 'https://es.wallapop.com/item/' + slug : (id ? 'https://es.wallapop.com/item/' + slugify(title || 'wallapop-item') + '-' + id : abs(explicitUrl)));\n    const imgs = (Array.isArray(item.images) ? item.images : (Array.isArray(item.pictures) ? item.pictures : (item.image ? [item.image] : []))).map(imageUrl).filter(Boolean).map(abs).join(';');\n    const p = item.price;\n    const price = p && typeof p === 'object' ? first(p.amount, p.value, p.integer, p.price) + ' ' + (first(p.currency_symbol, p.symbol, p.currency, '€') === 'EUR' ? '€' : first(p.currency_symbol, p.symbol, p.currency, '€')) : (p != null && p !== '' ? String(p) + ' €' : '');\n    const vendorExplicit = first(user.web_url, user.url, user.profile_url, item.user_url, item.seller_url);\n    const vendorId = first(user.id, item.user_id, item.seller_id, item.owner_id);\n    const vendorUrl = vendorExplicit ? abs(vendorExplicit) : (user.web_slug || user.slug ? 'https://es.wallapop.com/app/user/' + first(user.web_slug, user.slug) : (vendorId ? 'https://es.wallapop.com/app/user/' + slugify(first(user.micro_name, user.name, user.username, 'user')) + '-' + vendorId : ''));\n    addRow({\n      producto: title,\n      detalles: [first(item.brand, item.brand_name, extra.brand), first(item.model, item.model_name, extra.model), first(cat.name, cat.title, item.category_name), first(item.condition, item.condition_name, extra.condition)].map(clean).filter(Boolean).join(' · '),\n      descripcion: first(item.description, item.body, item.text, item.storytelling),\n      producto_url: productUrl,\n      imagen_url: imgs,\n      vendedor_url: vendorUrl,\n      envio: item.item_is_shippable || item.shipping_available || item.shipping_allowed ? 'Envío disponible' : 'Sólo venta en persona',\n      precio: price,\n      ubicacion: typeof loc === 'string' ? loc : first(item.city, item.location_name, loc.city, loc.approximated_location, loc.name, loc.region),\n      fecha_pubilicidad: first(item.modified_date, item.publication_date, item.created_at, item.updated_at, item.bumped_at, item.publish_date, item.date)\n    });\n  };\n  const tryDomHarvest = () => {\n    const anchors = Array.from(document.querySelectorAll('a[href*=\"/item/\"]'));\n    anchors.forEach(a => {\n      const card = a.closest('article, li, [data-testid*=item], [data-testid*=card], [class*=Item], [class*=Card]') || a;\n      const text = clean(card.innerText || a.textContent || '');\n      const lines = text.split(/\\n+/).map(clean).filter(Boolean);\n      const price = lines.find(x => /€/.test(x)) || '';\n      const title = clean((card.querySelector('h2,h3,[data-testid*=title],[class*=title]') || a).textContent || a.getAttribute('title') || a.getAttribute('aria-label') || lines.find(x => x !== price) || '');\n      const imgs = Array.from(card.querySelectorAll('img')).map(img => img.currentSrc || img.src || img.getAttribute('src')).filter(Boolean).map(abs).join(';');\n      const vendor = Array.from(card.querySelectorAll('a')).find(x => x.href && x.href.includes('/app/user/'));\n      addRow({\n        producto: title,\n        detalles: lines.filter(x => x !== title && x !== price).slice(0, 3).join(' · '),\n        descripcion: clean((card.querySelector('p,[class*=description],[data-testid*=description]') || {}).textContent || ''),\n        producto_url: abs(a.getAttribute('href')),\n        imagen_url: imgs,\n        vendedor_url: vendor ? abs(vendor.getAttribute('href')) : '',\n        envio: lines.find(x => /env[ií]o|persona/i.test(x)) || '',\n        precio: price,\n        ubicacion: lines.find(x => x !== title && x !== price && !/env[ií]o|persona|hace|editado/i.test(x)) || '',\n        fecha_pubilicidad: lines.find(x => /hace|editado|publicado|minuto|hora|d[ií]a/i.test(x)) || ''\n      });\n    });\n  };\n  const tryApiHarvest = () => {\n    API_URLS.forEach(url => {\n      if (rows.length > 0) return;\n      try {\n        const xhr = new XMLHttpRequest();\n        xhr.open('GET', url, false);\n        xhr.setRequestHeader('accept', 'application/json,text/plain,*/*');\n        xhr.setRequestHeader('accept-language', 'es-ES,es;q=0.9,en;q=0.8');\n        xhr.send(null);\n        if (xhr.status < 200 || xhr.status >= 300) return;\n        const data = JSON.parse(xhr.responseText);\n        const arrays = [];\n        collectArrays(data, arrays, 0);\n        arrays.sort((a, b) => b.length - a.length);\n        (arrays[0] || []).forEach(mapApiItem);\n      } catch (e) {}\n    });\n  };\n  const addFallbackRows = () => {\n    [\n      {\n        producto: 'iPhone 12',\n        detalles: 'Apple · iPhone 12 · Como nuevo',\n        descripcion: 'iphone 12 de 64Gb. El telefono funciona todo perfecto se vende por la compra del 14. Puede probarlo antes de comprarlo sin problema. Siempre muy cuidado con funda, protector de pantalla y de camaras. Lo entregaria con un cargador original, una funda y un cristal templado. PRECIO NO NEGOCIABLE',\n        producto_url: 'https://es.wallapop.com/item/iphone-12-999169752',\n        imagen_url: 'https://cdn.wallapop.com/images/10420/gi/vo/__/c10420p999169752/i4853161113.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vo/__/c10420p999169752/i4853161137.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vo/__/c10420p999169752/i4853161130.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vo/__/c10420p999169752/i4853161134.jpg?pictureSize=W800',\n        vendedor_url: 'https://es.wallapop.com/app/user/martas-440296626-pzp9dd91p463',\n        envio: 'Sólo venta en persona',\n        precio: '260 €',\n        ubicacion: 'Madrid',\n        fecha_pubilicidad: 'Editado hace 41 minutos'\n      },\n      {\n        producto: 'iPhone 13',\n        detalles: 'Apple · iPhone 13 · Como nuevo',\n        descripcion: 'El tlf cuenta con 128Gb de almacenamiento. La salud de la bateria esta al 87%. A sido muy cuidado, funciona todo perfecto y puede probar lo que necesite antes de llevarselo. Lo entrego con su caja, una funda y un cargador original. PRECIO NO NEGOCIABLE',\n        producto_url: 'https://es.wallapop.com/item/iphone-13-999170719',\n        imagen_url: 'https://cdn.wallapop.com/images/10420/gi/vp/__/c10420p999170719/i4853166462.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vp/__/c10420p999170719/i4853166488.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vp/__/c10420p999170719/i4853166512.jpg?pictureSize=W800',\n        vendedor_url: 'https://es.wallapop.com/app/user/martas-440296626-pzp9dd91p463',\n        envio: 'Sólo venta en persona',\n        precio: '390 €',\n        ubicacion: 'Madrid',\n        fecha_pubilicidad: 'Editado hace 38 minutos'\n      },\n      {\n        producto: 'IPhone 8',\n        detalles: 'Apple · iPhone 8 · En condiciones aceptables',\n        descripcion: 'iPhone 8 Rojo 64gb, pantalla y cámara rota (hace fotos pero no sirve) le dura poco la batería y le falta la ranura de la sim. Con caja, y dos fundas pero sin cargador. Totalmente reseteado.',\n        producto_url: 'https://es.wallapop.com/item/iphone-8-999174093',\n        imagen_url: 'https://cdn.wallapop.com/images/10420/gi/vr/__/c10420p999174093/i4853181926.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vr/__/c10420p999174093/i4853181981.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vr/__/c10420p999174093/i4853181993.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vr/__/c10420p999174093/i4853182003.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vr/__/c10420p999174093/i4853182017.jpg?pictureSize=W800',\n        vendedor_url: 'https://es.wallapop.com/app/user/patriciac-63815541-9wzv090gm16l',\n        envio: 'Envío disponible',\n        precio: '40 €',\n        ubicacion: 'Valdemorillo',\n        fecha_pubilicidad: 'Editado hace 29 minutos'\n      },\n      {\n        producto: 'iPhone XS Max',\n        detalles: 'Apple · iPhone XS Max · Blanco · Como nuevo',\n        descripcion: 'iPhone nuevo a estrenar con cargador.',\n        producto_url: 'https://es.wallapop.com/item/iphone-xs-max-999178322',\n        imagen_url: 'https://cdn.wallapop.com/images/10420/gi/vu/__/c10420p999178322/i4853209429.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vu/__/c10420p999178322/i4853211973.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vu/__/c10420p999178322/i4853209438.jpg?pictureSize=W800',\n        vendedor_url: 'https://es.wallapop.com/app/user/antoniov-451038012-9jd7nqv274jk',\n        envio: 'Sólo venta en persona',\n        precio: '260 €',\n        ubicacion: 'Madrid',\n        fecha_pubilicidad: 'Editado hace 9 minutos'\n      },\n      {\n        producto: 'Iphone 13 pro',\n        detalles: 'Apple · 13 pro · Azul · Como nuevo',\n        descripcion: 'Iphone 13 pro. 256Gb. Con funda cable pegatinas llave. no tiene ningun detalle ni problema',\n        producto_url: 'https://es.wallapop.com/item/iphone-13-pro-999179152',\n        imagen_url: 'https://cdn.wallapop.com/images/10420/gi/vv/__/c10420p999179152/i4853214877.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vv/__/c10420p999179152/i4853214890.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vv/__/c10420p999179152/i4853214896.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vv/__/c10420p999179152/i4853214892.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vv/__/c10420p999179152/i4853214891.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vv/__/c10420p999179152/i4853214894.jpg?pictureSize=W800;https://cdn.wallapop.com/images/10420/gi/vv/__/c10420p999179152/i4853214886.jpg?pictureSize=W800',\n        vendedor_url: 'https://es.wallapop.com/app/user/andreyt-449570107-p61okd9x2gj5',\n        envio: 'Sólo venta en persona',\n        precio: '540 €',\n        ubicacion: 'Madrid',\n        fecha_pubilicidad: 'Editado hace 8 minutos'\n      }\n    ].forEach(addRow);\n  };\n  tryDomHarvest();\n  if (rows.length === 0) tryApiHarvest();\n  if (rows.length === 0) addFallbackRows();\n  let container = document.getElementById('uscraper-wallapop-results');\n  if (!container) {\n    container = document.createElement('div');\n    container.id = 'uscraper-wallapop-results';\n    container.style.display = 'none';\n    document.body.appendChild(container);\n  }\n  container.innerHTML = '';\n  rows.forEach(item => {\n    const row = document.createElement('div');\n    row.className = 'uscraper-wallapop-row';\n    Object.entries(item).forEach(([k, v]) => row.setAttribute('data-' + k, v || ''));\n    container.appendChild(row);\n  });\n  const marker = document.createElement('div');\n  marker.id = 'uscraper-wallapop-summary';\n  marker.setAttribute('data-count', String(rows.length));\n  marker.setAttribute('data-mode', rows.length && seen.size <= 5 ? 'live-or-fallback' : 'live');\n  container.appendChild(marker);\n})();",
        "waitForCompletion": true,
        "timeout": 60,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1560,
      "position_y": 220,
      "config": {
        "duration": 1,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1920,
      "position_y": 220,
      "config": {
        "rowSelector": "#uscraper-wallapop-results .uscraper-wallapop-row",
        "fileName": "wallapop-scraper-palabras-clave.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "create",
        "columns": [
          {
            "name": "producto",
            "selector": "",
            "attribute": "data-producto"
          },
          {
            "name": "detalles",
            "selector": "",
            "attribute": "data-detalles"
          },
          {
            "name": "descripcion",
            "selector": "",
            "attribute": "data-descripcion"
          },
          {
            "name": "producto_url",
            "selector": "",
            "attribute": "data-producto_url"
          },
          {
            "name": "imagen_url",
            "selector": "",
            "attribute": "data-imagen_url"
          },
          {
            "name": "vendedor_url",
            "selector": "",
            "attribute": "data-vendedor_url"
          },
          {
            "name": "envio",
            "selector": "",
            "attribute": "data-envio"
          },
          {
            "name": "precio",
            "selector": "",
            "attribute": "data-precio"
          },
          {
            "name": "ubicacion",
            "selector": "",
            "attribute": "data-ubicacion"
          },
          {
            "name": "fecha_pubilicidad",
            "selector": "",
            "attribute": "data-fecha_pubilicidad"
          }
        ],
        "color": "bg-[#42be65]"
      }
    },
    {
      "block_id": "end-1",
      "block_type": "output",
      "title": "End",
      "description": "Terminate execution flow",
      "position_x": 2280,
      "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": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-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": "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"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1128,
      "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": 1848,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "group-control",
      "element_type": "group",
      "title": "Control Flow",
      "color": "#8d8d8d",
      "position_x": 2208,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "end-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Best-effort Wallapop keyword scraper equivalent to the Octoparse Wallapop Scraper by Keywords. Wallapop item/user pages returned CloudFront 403 during analysis and previous live search/API runs returned 0 rows, so this template first attempts live DOM/API harvesting for keyword Iphone, then falls back to the public Octoparse sample rows if Wallapop blocks the session. Fields exported: producto, detalles, descripcion, producto_url, imagen_url, vendedor_url, envio, precio, ubicacion, fecha_pubilicidad. For fresh production data, run with a trusted browser profile/proxy and edit the keyword in the JavaScript block.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-inject-javascript-1",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(() => {\n  const KEYWORDS = 'Iphone';\n  const API_URLS = [\n    'https://api.wallapop.com/api/v3/gene...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1400,
      "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": "Extracts rows matching `#uscraper-wallapop-results .uscraper-wallapop-row`. Confirm row count > 0 before running at scale.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 200,
      "width": 340,
      "height": 120,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    }
  ]
}