{
  "version": "1.0.0",
  "exported_at": "2026-06-01T04:10:00.000Z",
  "project": {
    "name": "Leboncoin Data Scraper",
    "description": "Scrapes Leboncoin listing/search result pages for title, image, price, category, address, modification date, description snippet, condition, seller/owner, professional flag, scrape time, and detail URL. Uses a click-next pagination loop to collect all available result pages for each listing URL. Best-effort: Leboncoin may require consent handling or block automation/CAPTCHA; some fields such as full description or seller name may only be partially available on listing cards.",
    "color": "bg-[#ff832b]",
    "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": {
        "urls": [
          "https://www.leboncoin.fr/recherche?text=v%C3%A9lo&locations=Paris_75015__48.84106_2.29933_2752_5000"
        ],
        "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": 456,
      "position_y": 220,
      "config": {
        "timeout": 30,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 792,
      "position_y": 220,
      "config": {
        "duration": 3,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "element-exists-1",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 1128,
      "position_y": 220,
      "config": {
        "selector": "#didomi-notice-agree-button, button#didomi-notice-agree-button, [data-testid=\"uc-accept-all-button\"], button[aria-label=\"Accepter\"], button[title=\"Accepter\"], button:has-text(\"Accepter\")",
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "click-1",
      "block_type": "process",
      "title": "Click",
      "description": "Click on element",
      "position_x": 1464,
      "position_y": 520,
      "config": {
        "selector": "#didomi-notice-agree-button, button#didomi-notice-agree-button, [data-testid=\"uc-accept-all-button\"], button[aria-label=\"Accepter\"], button[title=\"Accepter\"]",
        "timeout": 5,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1800,
      "position_y": 520,
      "config": {
        "duration": 2,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 2136,
      "position_y": 520,
      "config": {
        "selector": "a[href*=\"/ad/\"], a[href*=\"www.leboncoin.fr/ad/\"], [data-qa-id=\"aditem_container\"], [data-test-id=\"ad-card\"], [data-test-id=\"listing-card\"], [data-test-id*=\"adcard\"]",
        "timeout": 45,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2472,
      "position_y": 520,
      "config": {
        "rowSelector": "a[href*=\"/ad/\"], a[href*=\"www.leboncoin.fr/ad/\"], [data-qa-id=\"aditem_container\"], [data-test-id=\"ad-card\"], [data-test-id=\"listing-card\"], [data-test-id*=\"adcard\"]",
        "fileName": "leboncoin-data-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "titre",
            "selector": "(() => { const el = ROW.querySelector('[data-qa-id=\"aditem_title\"], [data-test-id*=\"title\"], h2, h3, [title]'); const txt = (el?.textContent || el?.getAttribute('title') || ROW.getAttribute('aria-label') || ROW.getAttribute('title') || '').replace(/\\s+/g, ' ').trim(); if (txt) return txt; const all = (ROW.textContent || '').replace(/\\s+/g, ' ').trim(); return all.split('€').pop()?.trim().split(/\\s{2,}|\\n/)[0] || all.slice(0, 140); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "image",
            "selector": "(() => { const img = ROW.querySelector('img') || ROW.closest('article, li, div')?.querySelector('img'); if (!img) return ''; const src = img.currentSrc || img.src || img.getAttribute('src') || ''; if (src) return src; const srcset = img.getAttribute('srcset') || ''; return srcset.split(',').pop()?.trim().split(' ')[0] || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "prix",
            "selector": "(() => { const ctx = ROW.closest('article, li, div') || ROW; const el = ctx.querySelector('[data-qa-id*=\"price\"], [data-test-id*=\"price\"]'); const txt = (el?.textContent || ctx.textContent || ROW.textContent || '').replace(/\\s+/g, ' ').trim(); const m = txt.match(/\\d[\\d\\s\\u202f.,]*\\s?€/); return (el?.textContent || m?.[0] || '').replace(/\\s+/g, ' ').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "categorie",
            "selector": "(() => { const crumbs = Array.from(document.querySelectorAll('nav a, [aria-label=\"breadcrumb\"] a')).map(a => a.textContent.trim()).filter(Boolean); if (crumbs.length) return crumbs[crumbs.length - 1]; const href = (ROW.matches('a[href]') ? ROW.getAttribute('href') : ROW.querySelector('a[href*=\"/ad/\"]')?.getAttribute('href')) || ''; const m = href.match(/\\/ad\\/([^\\/]+)/); return m ? decodeURIComponent(m[1]).replace(/-/g, ' ') : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "adresse",
            "selector": "(() => { const ctx = ROW.closest('article, li, div') || ROW; const el = ctx.querySelector('[data-qa-id*=\"location\"], [data-test-id*=\"location\"], [aria-label*=\"localisation\" i]'); if (el) return el.textContent.replace(/\\s+/g, ' ').trim(); const txt = (ctx.textContent || ROW.textContent || '').replace(/\\s+/g, ' ').trim(); const m = txt.match(/[A-ZÀ-ÿ][A-Za-zÀ-ÿ'’(). -]+\\s+\\d{5}(?:\\s+\\d+(?:e|er)?\\s+Arrondissement)?/); return m?.[0] || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "derniere_modification",
            "selector": "(() => { const ctx = ROW.closest('article, li, div') || ROW; const el = ctx.querySelector('time, [data-qa-id*=\"date\"], [data-test-id*=\"date\"]'); if (el) return (el.getAttribute('datetime') || el.textContent || '').replace(/\\s+/g, ' ').trim(); const txt = (ctx.textContent || ROW.textContent || '').replace(/\\s+/g, ' ').trim(); const m = txt.match(/(?:aujourd’hui|aujourd'hui|hier|\\d{1,2}\\/\\d{1,2}\\/\\d{4})\\s*(?:à\\s*\\d{1,2}:\\d{2})?/i); return m?.[0] || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "description",
            "selector": "(() => { const ctx = ROW.closest('article, li, div') || ROW; const values = Array.from(ctx.querySelectorAll('[data-qa-id*=\"description\"], [data-test-id*=\"description\"], p, span')).map(e => e.textContent.replace(/\\s+/g, ' ').trim()).filter(t => t.length > 30 && !/cookie|connexion|favoris/i.test(t)); values.sort((a, b) => b.length - a.length); return values[0] || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "etat",
            "selector": "(() => { const ctx = ROW.closest('article, li, div') || ROW; const txt = (ctx.textContent || ROW.textContent || '').replace(/\\s+/g, ' ').trim(); const states = ['État neuf', 'Comme neuf', 'Très bon état', 'Bon état', 'État satisfaisant', 'Reconditionné', 'Neuf']; return states.find(s => txt.toLowerCase().includes(s.toLowerCase())) || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "proprietaire",
            "selector": "(() => { const ctx = ROW.closest('article, li, div') || ROW; const el = ctx.querySelector('[data-qa-id*=\"owner\"], [data-qa-id*=\"seller\"], [data-qa-id*=\"company\"], [data-test-id*=\"owner\"], [data-test-id*=\"seller\"], [data-test-id*=\"company\"], [data-test-id*=\"store\"]'); return (el?.textContent || '').replace(/\\s+/g, ' ').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "pro",
            "selector": "(() => { const ctx = ROW.closest('article, li, div') || ROW; const txt = (ctx.textContent || ROW.textContent || '').replace(/\\s+/g, ' ').trim(); return /(^|\\s)(Pro|Professionnel)(\\s|$)/i.test(txt) ? 'Pro' : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "current_time",
            "selector": "(() => new Date().toISOString().replace('T', ' ').slice(0, 19))()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "detail_url",
            "selector": "(() => { const a = ROW.matches('a[href]') ? ROW : (ROW.querySelector('a[href*=\"/ad/\"]') || ROW.querySelector('a[href]') || ROW.closest('a[href]')); const href = a?.getAttribute('href') || ''; return href ? new URL(href, location.href).href : ''; })()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "element-exists-2",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 2808,
      "position_y": 520,
      "config": {
        "selector": "a[rel=\"next\"], [data-qa-id=\"pagination_next\"]:not([disabled]):not([aria-disabled=\"true\"]), a[aria-label=\"Page suivante\"]:not([aria-disabled=\"true\"]), a[aria-label=\"Suivant\"]:not([aria-disabled=\"true\"]), button[aria-label=\"Page suivante\"]:not([disabled]):not([aria-disabled=\"true\"]), button[aria-label=\"Suivant\"]:not([disabled]):not([aria-disabled=\"true\"])",
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "click-2",
      "block_type": "process",
      "title": "Click",
      "description": "Click on element",
      "position_x": 3144,
      "position_y": 520,
      "config": {
        "selector": "a[rel=\"next\"], [data-qa-id=\"pagination_next\"]:not([disabled]):not([aria-disabled=\"true\"]), a[aria-label=\"Page suivante\"]:not([aria-disabled=\"true\"]), a[aria-label=\"Suivant\"]:not([aria-disabled=\"true\"]), button[aria-label=\"Page suivante\"]:not([disabled]):not([aria-disabled=\"true\"]), button[aria-label=\"Suivant\"]:not([disabled]):not([aria-disabled=\"true\"])",
        "timeout": 10,
        "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": 3480,
      "position_y": 520,
      "config": {
        "timeout": 30,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "sleep-3",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 3816,
      "position_y": 758,
      "config": {
        "duration": 3,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 2808,
      "position_y": 520,
      "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": "sleep-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-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": "wait-for-element-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "click-1",
      "from_connector_id": "right",
      "to_block_id": "sleep-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-2",
      "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-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-2",
      "from_connector_id": "true",
      "to_block_id": "click-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-2",
      "from_connector_id": "false",
      "to_block_id": "loop-continue-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "click-2",
      "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": "sleep-3",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-3",
      "from_connector_id": "right",
      "to_block_id": "wait-for-element-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": 4016,
      "height": 834,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "sleep-2",
          "wait-for-element-1",
          "wait-for-page-load-2",
          "sleep-3"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1056,
      "position_y": 116,
      "width": 2336,
      "height": 596,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "element-exists-1",
          "click-1",
          "element-exists-2",
          "click-2",
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2400,
      "position_y": 416,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Leboncoin listing/search result pages for title, image, price, category, address, modification date, description snippet, condition, seller/owner, professional flag, scrape time, and detail URL. Uses a click-next pagination loop to collect all available result pages for each listing URL. Best-effort: Leboncoin may require consent handling or block automation/CAPTCHA; some fields such as full description or seller name may only be partially available on listing cards.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-element-exists-1",
      "element_type": "note",
      "title": "Note: Element Exists",
      "content": "Condition block: checks `#didomi-notice-agree-button, button#didomi-notice-agree-button, [data-testid=\"uc-accept-all-button\"], button[aria-label=`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 1328,
      "position_y": 200,
      "width": 340,
      "height": 170,
      "z_index": 22,
      "data": {
        "block_id": "element-exists-1"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (titre, image, prix, categorie, adresse). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2672,
      "position_y": 500,
      "width": 340,
      "height": 126,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    },
    {
      "id": "note-block-element-exists-2",
      "element_type": "note",
      "title": "Note: Element Exists",
      "content": "Condition block: checks `a[rel=\"next\"], [data-qa-id=\"pagination_next\"]:not([disabled]):not([aria-disabled=\"true\"]), a[aria-label=\"Page suivante\"]`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 3008,
      "position_y": 500,
      "width": 340,
      "height": 170,
      "z_index": 22,
      "data": {
        "block_id": "element-exists-2"
      }
    },
    {
      "id": "note-block-click-2",
      "element_type": "note",
      "title": "Note: Click",
      "content": "Pagination click — add waits after this block; the page reloads asynchronously.",
      "color": "#ee5396",
      "position_x": 3344,
      "position_y": 500,
      "width": 316,
      "height": 106,
      "z_index": 22,
      "data": {
        "block_id": "click-2"
      }
    },
    {
      "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": 3008,
      "position_y": 500,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}