{
  "version": "1.0.0",
  "exported_at": "2026-06-02T16:00:00.000Z",
  "project": {
    "name": "Marktplazt Mittelstand Leads Scraper",
    "description": "Scrapes Marktplatz Mittelstand business lead detail pages and exports fields equivalent to the Octoparse preview: title, street, postal code, city, contact person, phone, fax, mobile, website, email, opening hours, and detail URL. Pagination/navigation is implemented as a multi-URL detail-page loop over Marktplatz detail URLs from the preview; each valid detail page is appended to one CSV. A condition skips Marktplatz error pages containing “Oopsie”, because some historical catalog URLs redirect to unavailable pages. The output filename uses a fresh snake_case name to avoid mixing results with previous append-mode test runs. Replace or extend navigate.urls[] with detail URLs discovered for other keyword pairs such as arzt;berlin.",
    "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": 260,
      "config": {
        "urls": [
          "https://www.marktplatz-mittelstand.de/duesseldorf/525996-fotograf-schilling",
          "https://www.marktplatz-mittelstand.de/duesseldorf/12477066-jojo-fotograf",
          "https://www.marktplatz-mittelstand.de/koeln/627711-carmen-rosa-dein-spanischer-supermarkt-in-koeln",
          "https://www.marktplatz-mittelstand.de/meerbusch/196203-fotograf-buschmann-architektur-industrie-messe-reportage-werbung-49-0-211-45-36-37",
          "https://www.marktplatz-mittelstand.de/schwarzenbek/52004037-mr-barber-friseur-schwarzenbek",
          "https://www.marktplatz-mittelstand.de/duesseldorf/52070059-fotograf-duesseldorf",
          "https://www.marktplatz-mittelstand.de/koeln/50415703-heng-long-asia-supermarkt-koeln",
          "https://www.marktplatz-mittelstand.de/meerbusch/597840-ralf-zenker-fotograf",
          "https://www.marktplatz-mittelstand.de/koeln/15029912-ho-s-supermarkt"
        ],
        "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": 480,
      "position_y": 260,
      "config": {
        "timeout": 30
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 840,
      "position_y": 260,
      "config": {
        "selector": "body",
        "timeout": 30,
        "visible": true
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Run custom JavaScript",
      "position_x": 1200,
      "position_y": 260,
      "config": {
        "jsCode": "(function(){function clean(v){return (v||'').toString().replace(/\\s+/g,' ').trim();}function abs(u){try{return new URL(u,location.href).href}catch(e){return u||''}}function flatten(a){var r=[];(function f(x){if(!x)return;if(Array.isArray(x)){x.forEach(f);}else r.push(x);})(a);return r;}function jsons(){var out=[];document.querySelectorAll('script[type=\"application/ld+json\"]').forEach(function(s){try{var j=JSON.parse(s.textContent);(function walk(x){if(!x)return;if(Array.isArray(x)){x.forEach(walk);return;}if(typeof x==='object'){out.push(x);if(x['@graph'])walk(x['@graph']);}})(j);}catch(e){}});return out;}var data=jsons();function typeHas(o,t){var ty=o&&o['@type'];return Array.isArray(ty)?ty.join(' ').toLowerCase().indexOf(t)>=0:(ty||'').toString().toLowerCase().indexOf(t)>=0;}function biz(){return data.find(function(o){return typeHas(o,'localbusiness')||typeHas(o,'organization')||o.telephone||o.address;})||{};}function addr(){var a=biz().address||{};if(typeof a==='string')return {streetAddress:a};return a||{};}function bodyRaw(){return document.body?document.body.innerText||'':'';}function body(){return clean(bodyRaw());}function lines(){return bodyRaw().split(/\\n+/).map(clean).filter(Boolean);}function meta(n){var m=document.querySelector('meta[property=\"'+n+'\"],meta[name=\"'+n+'\"]');return m?clean(m.content):'';}function labelText(names){var ls=lines();for(var i=0;i<names.length;i++){var n=names[i],re=new RegExp('^'+n+'\\\\b\\\\s*:?\\\\s*(.*)$','i');for(var j=0;j<ls.length;j++){var m=ls[j].match(re);if(m){var v=clean(m[1]);if(v)return v;if(ls[j+1])return clean(ls[j+1]);}}}return '';}function phoneNear(names){var ls=lines(),phone=/[+]?(?:\\d[\\d\\s()\\/.\\-]{5,}\\d)/;for(var i=0;i<names.length;i++){var n=names[i],re=new RegExp(n,'i');for(var j=0;j<ls.length;j++){if(re.test(ls[j])){var after=ls[j].replace(new RegExp('.*'+n+'\\\\s*:?\\\\s*','i'),'');var m=after.match(phone);if(m)return clean(m[0]);for(var k=1;k<=2;k++){if(ls[j+k]){m=ls[j+k].match(phone);if(m)return clean(m[0]);}}}}}return '';}function mail(){var a=document.querySelector('a[href^=\"mailto:\"]');if(a)return clean(a.getAttribute('href').replace(/^mailto:/i,'').split('?')[0]);var m=body().match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/i);return m?m[0]:'';}function tel(){var b=biz();if(b.telephone)return clean(b.telephone);var a=document.querySelector('a[href^=\"tel:\"]');if(a)return clean(a.getAttribute('href').replace(/^tel:/i,''));return phoneNear(['Telefonnummer','Telefon','Tel\\\\.']);}function fax(){var b=biz();if(b.faxNumber)return clean(b.faxNumber);return phoneNear(['Faxnummer','Fax']);}function mob(){return phoneNear(['Mobilnummer','Mobil','Mobile','Handy']);}function site(){var b=biz();var host=location.hostname.replace(/^www\\./,'');function ok(u){u=abs(u);var l=u.toLowerCase();return /^https?:/i.test(u)&&l.indexOf(host)<0&&l.indexOf('marktplatz-mittelstand.de')<0&&l.indexOf('google.com/maps')<0&&l.indexOf('maps.google.')<0&&l.indexOf('openstreetmap')<0&&l.indexOf('leaflet')<0&&l.indexOf('firmenweb.de')<0;}if(b.url&&ok(b.url))return abs(b.url);var links=Array.from(document.querySelectorAll('a[href]')).map(function(a){return abs(a.getAttribute('href'));}).filter(ok);return links[0]||'';}function fmtSpec(spec){var arr=flatten(spec);if(!arr.length)return '';return arr.map(function(o){if(typeof o==='string')return clean(o);var d=Array.isArray(o.dayOfWeek)?o.dayOfWeek.join('/'):(o.dayOfWeek||'');var op=o.opens||'',cl=o.closes||'';if(op==='00:00'&&cl==='24:00')return clean(d+' Durchgehend geöffnet');if(op||cl)return clean(d+' '+op+' bis '+cl);return clean(JSON.stringify(o));}).filter(Boolean).join(' ');}function opening(){var b=biz();if(b.openingHoursSpecification)return fmtSpec(b.openingHoursSpecification);if(b.openingHours)return Array.isArray(b.openingHours)?b.openingHours.map(clean).join(' '):clean(b.openingHours);var t=bodyRaw();var m=t.match(/Öffnungszeiten([\\s\\S]*?)(Branchen|Map|Bewertungen|Firma bewerten|Unternehmen in der Nähe|$)/i);return m?clean(m[1]):'';}window.__us_mm={get:function(f){var a=addr(),b=biz();if(f==='title')return clean((document.querySelector('h1')||{}).innerText)||meta('og:title')||clean(document.title).replace(/\\s*\\|.*$/,'');if(f==='street')return clean(a.streetAddress)||labelText(['Adresse_Straße','Straße','Strasse']);if(f==='postal')return clean(a.postalCode)||((body().match(/\\b\\d{5}\\b/)||[])[0]||'');if(f==='city')return clean(a.addressLocality)||labelText(['Addresse_Ort','Adresse_Ort','Ort']);if(f==='contact')return clean((b.employee&&b.employee.name)||(b.founder&&b.founder.name)||'')||labelText(['Ansprechpartner','Kontaktperson']);if(f==='phone')return tel();if(f==='fax')return fax();if(f==='mobile')return mob();if(f==='website')return site();if(f==='email')return mail();if(f==='opening')return opening();if(f==='detail_url')return location.href;return '';}};})();",
        "waitForCompletion": true,
        "timeout": 10
      }
    },
    {
      "block_id": "text-contains-1",
      "block_type": "process",
      "title": "Text Contains",
      "description": "Check if page contains text",
      "position_x": 1560,
      "position_y": 260,
      "config": {
        "text": "Oopsie",
        "selector": "body",
        "timeout": 5,
        "caseSensitive": false
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1560,
      "position_y": 580,
      "config": {
        "rowSelector": "body",
        "fileName": "marktplazt_mittelstand_leads_scraper_clean.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "columns": [
          {
            "name": "titel",
            "selector": "window.__us_mm.get('title')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "adresse_strasse",
            "selector": "window.__us_mm.get('street')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "postleitzahl",
            "selector": "window.__us_mm.get('postal')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "addresse_ort",
            "selector": "window.__us_mm.get('city')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "ansprechpartner",
            "selector": "window.__us_mm.get('contact')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "telefonnummer",
            "selector": "window.__us_mm.get('phone')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "faxnummer",
            "selector": "window.__us_mm.get('fax')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "mobilnummer",
            "selector": "window.__us_mm.get('mobile')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "webseite",
            "selector": "window.__us_mm.get('website')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "email",
            "selector": "window.__us_mm.get('email')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "oeffnungszeiten",
            "selector": "window.__us_mm.get('opening')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "detail_url",
            "selector": "window.__us_mm.get('detail_url')",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 1920,
      "position_y": 580,
      "config": {}
    }
  ],
  "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": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-1",
      "from_connector_id": "right",
      "to_block_id": "text-contains-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "text-contains-1",
      "from_connector_id": "true",
      "to_block_id": "loop-continue-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "text-contains-1",
      "from_connector_id": "false",
      "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"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 48,
      "position_y": 156,
      "width": 1040,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "wait-for-element-1"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1128,
      "position_y": 156,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1488,
      "position_y": 156,
      "width": 680,
      "height": 616,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "text-contains-1",
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 1488,
      "position_y": 476,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Marktplatz Mittelstand business lead detail pages and exports fields equivalent to the Octoparse preview: title, street, postal code, city, contact person, phone, fax, mobile, website, email, opening hours, and detail URL. Pagination/navigation is implemented as a multi-URL detail-page loop over Marktplatz detail URLs from the preview; each valid detail page is appended to one CSV. A condition skips Marktplatz error pages containing “Oopsie”, because some historical catalog URLs redirect to unavailable pages. The output filename uses a fresh snake_case name to avoid mixing results with previous append-mode test runs. Replace or extend navigate.urls[] with detail URLs discovered for other keyword pairs such as arzt;berlin.",
      "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: `(function(){function clean(v){return (v||'').toString().replace(/\\s+/g,' ').trim();}function abs(u){...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1400,
      "position_y": 240,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-1"
      }
    },
    {
      "id": "note-block-text-contains-1",
      "element_type": "note",
      "title": "Note: Text Contains",
      "content": "Condition block: checks `body`. 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": 240,
      "width": 340,
      "height": 131,
      "z_index": 22,
      "data": {
        "block_id": "text-contains-1"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (titel, adresse_strasse, postleitzahl, addresse_ort, ansprechpartner). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 560,
      "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": 2120,
      "position_y": 560,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}