{
  "version": "1.0.0",
  "exported_at": "2026-06-02T00:00:00.000Z",
  "project": {
    "name": "CapCar Data Scraper",
    "description": "Extracts vehicle listing data from CapCar listing/search pages, including title, subtitle, price, year, mileage, energy, gearbox, label, image URL, and detail page URL. Starts from the sample CapCar listing URL and follows the site's a[rel=\"next\"] pagination link until no next page remains, appending all pages to one CSV.",
    "color": "bg-[#145DF0]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 120,
      "position_y": 220,
      "config": {
        "url": "https://www.capcar.fr/voiture-occasion?category=Break",
        "color": "bg-[#4589ff]",
        "tags": [
          "capcar",
          "listing",
          "input-url"
        ]
      }
    },
    {
      "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": 220,
      "config": {
        "timeout": 30,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 840,
      "position_y": 220,
      "config": {
        "selector": "main a[href*=\"/voiture-occasion/\"][class*=\"shadow-card\"]",
        "timeout": 30,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "rowSelector": "main a[href*=\"/voiture-occasion/\"][class*=\"shadow-card\"]",
        "fileName": "capcar-voiture-data-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "Titre",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); const priceIdx = lines.findIndex(l => /€/.test(l)); if (priceIdx >= 0) return lines[priceIdx + 1] || ''; const yearIdx = lines.findIndex(l => /^(19|20)\\d{2}$/.test(l)); return yearIdx > 1 ? lines[yearIdx - 2] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Sous_Titre",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); const priceIdx = lines.findIndex(l => /€/.test(l)); if (priceIdx >= 0) return lines[priceIdx + 2] || ''; const yearIdx = lines.findIndex(l => /^(19|20)\\d{2}$/.test(l)); return yearIdx > 0 ? lines[yearIdx - 1] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Prix",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); return lines.find(l => /\\d[\\d\\s ]*€/.test(l)) || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Année",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); return lines.find(l => /^(19|20)\\d{2}$/.test(l)) || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Kilométrage",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); return lines.find(l => /\\bkm\\b/i.test(l)) || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Énergie",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); const kmIdx = lines.findIndex(l => /\\bkm\\b/i.test(l)); if (kmIdx >= 0 && lines[kmIdx + 1]) return lines[kmIdx + 1]; return lines.find(l => /^(Essence|Diesel|Hybride|Hybride rechargeable|Hybride essence|Electrique|Électrique|Autre|Essence \\/ Bioéthanol)$/i.test(l)) || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Boîte_de_vitesse",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); const kmIdx = lines.findIndex(l => /\\bkm\\b/i.test(l)); if (kmIdx >= 0 && lines[kmIdx + 2]) return lines[kmIdx + 2]; return lines.find(l => /^(Automatique|Manuelle)$/i.test(l)) || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Étiquette",
            "selector": "(() => { const lines = (ROW.innerText || ROW.textContent || '').split(/\\n+/).map(s => s.trim()).filter(Boolean); const priceIdx = lines.findIndex(l => /€/.test(l)); if (priceIdx > 0) return lines.slice(0, priceIdx).join(' '); const first = lines[0] || ''; return /AFFAIRE|GARANTIE|PRIX|PRESTIGE|MAIN/i.test(first) ? first : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "Photo_URL",
            "selector": "(() => { const img = ROW.querySelector('img'); if (img) return img.currentSrc || img.src || img.getAttribute('src') || img.getAttribute('data-src') || ''; const source = ROW.querySelector('source[srcset]'); if (source) return (source.getAttribute('srcset') || '').split(',')[0].trim().split(/\\s+/)[0] || ''; return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "URL_de_la_page_détaillée",
            "selector": "(() => { const href = ROW.href || ROW.getAttribute('href') || ROW.querySelector('a')?.href || ROW.querySelector('a')?.getAttribute('href') || ''; try { return new URL(href, location.origin).href; } catch (e) { return href; } })()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "element-exists-1",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 1560,
      "position_y": 220,
      "config": {
        "selector": "a[rel=\"next\"]",
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "click-1",
      "block_type": "process",
      "title": "Click",
      "description": "Click on element",
      "position_x": 1920,
      "position_y": 560,
      "config": {
        "selector": "a[rel=\"next\"]",
        "timeout": 15,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "wait-for-page-load-2",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 2280,
      "position_y": 560,
      "config": {
        "timeout": 30,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-2",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 2640,
      "position_y": 560,
      "config": {
        "selector": "main a[href*=\"/voiture-occasion/\"][class*=\"shadow-card\"]",
        "timeout": 30,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 3000,
      "position_y": 560,
      "config": {
        "duration": 1,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "end-1",
      "block_type": "output",
      "title": "End",
      "description": "Terminate execution flow",
      "position_x": 1560,
      "position_y": 560,
      "config": {
        "color": "bg-[#8d8d8d]"
      }
    }
  ],
  "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": "wait-for-element-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-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": "element-exists-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "true",
      "to_block_id": "click-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "false",
      "to_block_id": "end-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "click-1",
      "from_connector_id": "right",
      "to_block_id": "wait-for-page-load-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-page-load-2",
      "from_connector_id": "right",
      "to_block_id": "wait-for-element-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-2",
      "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"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 48,
      "position_y": 116,
      "width": 3200,
      "height": 636,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "wait-for-element-1",
          "wait-for-page-load-2",
          "wait-for-element-2",
          "sleep-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 1128,
      "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": 1488,
      "position_y": 116,
      "width": 680,
      "height": 636,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "element-exists-1",
          "click-1"
        ]
      }
    },
    {
      "id": "group-control",
      "element_type": "group",
      "title": "Control Flow",
      "color": "#8d8d8d",
      "position_x": 1488,
      "position_y": 456,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "end-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Extracts vehicle listing data from CapCar listing/search pages, including title, subtitle, price, year, mileage, energy, gearbox, label, image URL, and detail page URL. Starts from the sample CapCar listing URL and follows the site's a[rel=\"next\"] pagination link until no next page remains, appending all pages to one CSV.",
      "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 (Titre, Sous_Titre, Prix, Année, Kilométrage). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 1400,
      "position_y": 200,
      "width": 340,
      "height": 128,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    },
    {
      "id": "note-block-element-exists-1",
      "element_type": "note",
      "title": "Note: Element Exists",
      "content": "Condition block: checks `a[rel=\"next\"]`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 200,
      "width": 340,
      "height": 134,
      "z_index": 22,
      "data": {
        "block_id": "element-exists-1"
      }
    },
    {
      "id": "note-block-click-1",
      "element_type": "note",
      "title": "Note: Click",
      "content": "Pagination click — add waits after this block; the page reloads asynchronously.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 540,
      "width": 316,
      "height": 106,
      "z_index": 22,
      "data": {
        "block_id": "click-1"
      }
    }
  ]
}