{
  "version": "1.0.0",
  "exported_at": "2026-06-01T00:00:00.000Z",
  "project": {
    "name": "AutoScout24 Product Listing Scraper",
    "description": "Scrapes AutoScout24 Germany vehicle listing pages for title, product URL, price, price rating, mileage, registration, power, label/status, fuel, seller, seller location, rating, owners, condition, transmission, and fuel consumption. Uses known URL-list pagination for pages 1-10 and appends all rows into one CSV. Selectors use .listing-impressions-tracking rows plus row-relative JavaScript because AutoScout24 uses dynamic CSS-module classes. Product URLs are constructed from the stable data-guid attribute as https://www.autoscout24.de/angebote/{uuid}, matching AutoScout24's short offer URL format.",
    "color": "bg-[#4589ff]",
    "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.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=1&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=2&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=3&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=4&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=5&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=6&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=7&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=8&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=9&sort=standard&source=homepage_search-mask&ustate=N%2CU",
          "https://www.autoscout24.de/lst?atype=C&cy=D&desc=0&ocs_listing=include&page=10&sort=standard&source=homepage_search-mask&ustate=N%2CU"
        ],
        "color": "bg-[#4589ff]",
        "tags": [
          "autoscout24",
          "pagination-url-list"
        ]
      }
    },
    {
      "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": "element-exists-1",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 792,
      "position_y": 220,
      "config": {
        "selector": "button[class*='accept' i]",
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "click-1",
      "block_type": "process",
      "title": "Click",
      "description": "Click on element",
      "position_x": 1128,
      "position_y": 520,
      "config": {
        "selector": "button[class*='accept' i]",
        "timeout": 8,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1464,
      "position_y": 520,
      "config": {
        "duration": 1,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 1800,
      "position_y": 520,
      "config": {
        "selector": ".listing-impressions-tracking",
        "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": 2136,
      "position_y": 520,
      "config": {
        "rowSelector": ".listing-impressions-tracking",
        "fileName": "autoscout24_product_listing_scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "anzahl_der_angebote",
            "selector": "(() => { const txt = document.body.innerText || ''; const m = txt.match(/([0-9]{1,3}(?:\\.[0-9]{3})*|[0-9]+)\\s*(?:Angebote|Fahrzeuge|Treffer)/i); return m ? m[1] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "seite",
            "selector": "(() => { try { return new URLSearchParams(window.location.search).get('page') || '1'; } catch(e) { return ''; } })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "titel_des_produkts",
            "selector": "(() => { const visible = Array.from(ROW.querySelectorAll('[class*=\"headline\" i], [class*=\"title\" i], h2, h3')).map(e => e.textContent.trim()).find(t => t && !/Details zum offenen Angebot|Zum Angebot/i.test(t)); if (visible) return visible; const txt = ROW.textContent || ''; const cleaned = txt.replace(/€\\s*[0-9.]+(?:,[0-9]{2})?/g, '').replace(/Sehr guter Preis|Guter Preis|Fairer Preis|Erhöhter Preis|Ohne Preisbewertung/ig, '').replace(/[0-9]{1,3}(?:\\.[0-9]{3})*\\s*km|[0-9]+\\s*km/ig, '').replace(/(0[1-9]|1[0-2])\\/\\d{4}/g, '').replace(/[0-9]{2,4}\\s*kW\\s*\\([0-9]{2,4}\\s*PS\\)/ig, '').replace(/Automatik|Schaltgetriebe|Halbautomatik|Diesel|Benzin|Elektro\\/Benzin|Elektro|Hybrid/ig, '').replace(/\\s+/g, ' ').trim(); return cleaned.split('DE-')[0].trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "produkt_url",
            "selector": "(() => { const guid = ROW.getAttribute('data-guid') || ROW.getAttribute('data-listing-id') || ROW.getAttribute('id'); if (guid && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(guid)) return 'https://www.autoscout24.de/angebote/' + guid; const html = ROW.outerHTML || ''; const mGuid = html.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i); if (mGuid) return 'https://www.autoscout24.de/angebote/' + mGuid[0]; const direct = ROW.querySelector('a[href*=\"/angebote/\"]'); if (direct && direct.href) return direct.href; const closest = ROW.closest && ROW.closest('a[href*=\"/angebote/\"]'); if (closest && closest.href) return closest.href; return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "preis",
            "selector": "(() => { const holder = ROW.matches('[data-price]') ? ROW : ROW.querySelector('[data-price]'); const dp = holder ? holder.getAttribute('data-price') : ''; if (dp && /^\\d+$/.test(dp)) return '€ ' + Number(dp).toLocaleString('de-DE'); const txt = ROW.textContent || ''; const m = txt.match(/€\\s*[0-9.]+(?:,[0-9]{2})?/); return m ? m[0].replace(/\\s+/g, ' ').trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "empfohlener_grad",
            "selector": "(() => { const txt = ROW.textContent || ''; const m = txt.match(/Sehr guter Preis|Guter Preis|Fairer Preis|Erhöhter Preis|Ohne Preisbewertung/i); if (m) return m[0]; const raw = ROW.getAttribute('data-price-label') || ''; const map = { 'top-price': 'Sehr guter Preis', 'good-price': 'Guter Preis', 'fair-price': 'Fairer Preis', 'increased-price': 'Erhöhter Preis', 'no-price-rating': 'Ohne Preisbewertung' }; return map[raw] || raw; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "kilometerstand",
            "selector": "(() => { const dataMileage = ROW.getAttribute('data-mileage'); if (dataMileage && /^\\d+$/.test(dataMileage)) return Number(dataMileage).toLocaleString('de-DE') + ' km'; const txt = ROW.textContent || ''; const m = txt.match(/[0-9]{1,3}(?:\\.[0-9]{3})*\\s*km|[0-9]+\\s*km/i); return m ? m[0].trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "erstzulassung",
            "selector": "(() => { const reg = ROW.getAttribute('data-first-registration') || ''; if (reg && !/^new$/i.test(reg)) return reg.replace('-', '/'); const txt = ROW.textContent || ''; const m = txt.match(/(0[1-9]|1[0-2])\\/\\d{4}/); return m ? m[0] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "leistung",
            "selector": "(() => { const txt = ROW.textContent || ''; let m = txt.match(/[0-9]{2,4}\\s*kW\\s*\\([0-9]{2,4}\\s*PS\\)/i); if (m) return m[0]; m = txt.match(/\\b([0-9]{2,4})\\s*kW\\b/i); if (m) return m[1] + ' kW'; m = txt.match(/\\b([0-9]{2,4})\\s*PS\\b/i); if (m) return m[1] + ' PS'; return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "etikett",
            "selector": "(() => { const reg = ROW.getAttribute('data-first-registration') || ''; if (/^new$/i.test(reg)) return 'Neu'; const txt = ROW.textContent || ''; const m = txt.match(/Lieferung möglich|Neu|Reserviert|Top Angebot/i); return m ? m[0] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "kraftstoff",
            "selector": "(() => { const raw = ROW.getAttribute('data-fuel-type') || ''; const map = { d: 'Diesel', b: 'Benzin', e: 'Elektro', l: 'Autogas', c: 'Erdgas', h: 'Hybrid', p: 'Elektro/Benzin' }; if (map[raw]) return map[raw]; const txt = ROW.textContent || ''; const m = txt.match(/Elektro\\/Benzin|Elektro\\/Diesel|Diesel|Benzin|Elektro|Hybrid|Autogas|Erdgas|Wasserstoff/i); return m ? m[0] : raw; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "verkaeufer",
            "selector": "(() => { const loc = ((ROW.textContent || '').replace(/\\s+/g, ' ').match(/DE-\\d{5}/) || [])[0]; const sellerBox = ROW.querySelector('[class*=\"seller\" i], [data-testid*=\"seller\" i]'); let txt = (sellerBox ? sellerBox.textContent : ROW.textContent || '').replace(/\\s+/g, ' ').trim(); txt = txt.replace(/Details zum offenen Angebot/ig, '').replace(/\\+ Weitere Fahrzeuge anzeigen/ig, '').trim(); if (loc && txt.includes(loc)) return txt.split(loc)[0].trim(); const m = txt.match(/(?:Preis|Bewertung)?\\s*([^€]+?)(?=DE-\\d{5}|$)/); return m ? m[1].trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "standort_des_verkaeufers",
            "selector": "(() => { const txt = (ROW.textContent || '').replace(/\\s+/g, ' ').trim(); const m = txt.match(/DE-\\d{5}\\s*[^+€]+?(?=\\+|$)/); return m ? m[0].trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "kundenbewertung",
            "selector": "(() => { const seller = ROW.querySelector('[class*=\"seller\" i], [data-testid*=\"seller\" i]') || ROW; const txt = seller.textContent || ''; const m = txt.match(/[0-5][,.][0-9]/); return m ? m[0] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "anzahl_der_fahrzeughalter",
            "selector": "(() => { const txt = ROW.textContent || ''; const m = txt.match(/[0-9]+\\s*Fahrzeughalter/i); return m ? m[0] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "zustand",
            "selector": "(() => { const txt = ROW.textContent || ''; const m = txt.match(/Repariert|Unfallfrei|Gebraucht|Beschädigt|Vorführfahrzeug|Jahreswagen|Tageszulassung/i); return m ? m[0] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "getriebe",
            "selector": "(() => { const txt = ROW.textContent || ''; let m = txt.match(/Automatik|Schaltgetriebe|Halbautomatik/i); if (m) return m[0]; if (/\\bdsg\\b|\\bstronic\\b|\\btiptronic\\b|\\bautomatik\\b/i.test(txt)) return 'Automatik'; if (/\\bschalter\\b|\\bschalt\\b|\\bmanual\\b/i.test(txt)) return 'Schaltgetriebe'; return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "kraftstoffverbrauch",
            "selector": "(() => { const txt = ROW.textContent || ''; const m = txt.match(/[0-9]+(?:[,\\.][0-9]+)?\\s*l\\s*\\/\\s*100\\s*km\\s*\\([^)]*\\)/i); return m ? m[0] : ''; })()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 2472,
      "position_y": 520,
      "config": {
        "duration": 2,
        "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": "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-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": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-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": "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": 116,
      "width": 2672,
      "height": 596,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "wait-for-element-1",
          "sleep-2"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 720,
      "position_y": 116,
      "width": 2336,
      "height": 596,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "element-exists-1",
          "click-1",
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2064,
      "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 AutoScout24 Germany vehicle listing pages for title, product URL, price, price rating, mileage, registration, power, label/status, fuel, seller, seller location, rating, owners, condition, transmission, and fuel consumption. Uses known URL-list pagination for pages 1-10 and appends all rows into one CSV. Selectors use .listing-impressions-tracking rows plus row-relative JavaScript because AutoScout24 uses dynamic CSS-module classes. Product URLs are constructed from the stable data-guid attribute as https://www.autoscout24.de/angebote/{uuid}, matching AutoScout24's short offer URL format.",
      "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 `button[class*='accept' i]`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 992,
      "position_y": 200,
      "width": 340,
      "height": 138,
      "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 (anzahl_der_angebote, seite, titel_des_produkts, produkt_url, preis). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2336,
      "position_y": 500,
      "width": 340,
      "height": 136,
      "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": 3008,
      "position_y": 500,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}