{
  "version": "1.0.0",
  "exported_at": "2026-06-02T12:30:00.000Z",
  "project": {
    "name": "Gelbe Seiten Details Scraper Cloud by URLs",
    "description": "Gelbe Seiten detail-page lead scraper equivalent to the Octoparse Cloud-by-URLs template. Seeded with /gsbiz/ URLs from the Octoparse preview; replace or extend navigate.urls with fresh detail URLs from a Gelbe Seiten listing scraper. Uses a multi-URL loop with append mode. Removed/expired pages showing 'Der gesuchte Teilnehmer konnte nicht gefunden werden' are skipped. Extraction uses scoped JS heuristics for valid detail pages, including cleaned title, opening-status, breadcrumb, contact, address, photos, opening hours, and description fields.",
    "color": "bg-[#ffdc00]",
    "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": 456,
      "position_y": 220,
      "config": {
        "urls": [
          "https://www.gelbeseiten.de/gsbiz/b7822bd7-2704-4619-8948-3a7b45f2d93d",
          "https://www.gelbeseiten.de/gsbiz/7116a8a6-0bfb-42bd-bc5f-c2457dda864a",
          "https://www.gelbeseiten.de/gsbiz/5f58bc9b-d1b1-4dbd-964d-a590f14a4d09",
          "https://www.gelbeseiten.de/gsbiz/6650e212-e377-4ca2-988c-4df977e7764a",
          "https://www.gelbeseiten.de/gsbiz/adde7d3a-4996-4b8b-84c1-69fa10e7b52c"
        ],
        "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": 792,
      "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": 1128,
      "position_y": 220,
      "config": {
        "duration": 2,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "text-contains-1",
      "block_type": "process",
      "title": "Text Contains",
      "description": "Check if page contains text",
      "position_x": 1464,
      "position_y": 220,
      "config": {
        "selector": "body",
        "text": "Der gesuchte Teilnehmer konnte nicht gefunden werden.",
        "caseSensitive": false,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 1800,
      "position_y": 520,
      "config": {
        "color": "bg-[#8d8d8d]"
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1464,
      "position_y": 520,
      "config": {
        "jsCode": "(() => { const texts = ['Akzeptieren', 'Alle akzeptieren', 'Accept', 'Zustimmen', 'Einverstanden']; const btns = Array.from(document.querySelectorAll('button, a, input[type=button], input[type=submit]')); for (const b of btns) { const t = (b.innerText || b.value || b.getAttribute('aria-label') || '').trim(); if (texts.some(x => t.toLowerCase().includes(x.toLowerCase()))) { try { b.click(); } catch(e) {} } } const expandWords = ['Mehr anzeigen', 'Details anzeigen', 'Öffnungszeiten anzeigen', 'Kontakt anzeigen', 'E-Mail anzeigen', 'E-Mail', 'Email', 'Website anzeigen', 'Alle Informationen anzeigen']; for (const b of btns) { const t = (b.innerText || b.value || b.getAttribute('aria-label') || '').trim(); if (expandWords.some(x => t.toLowerCase() === x.toLowerCase() || t.toLowerCase().includes(x.toLowerCase()))) { try { b.click(); } catch(e) {} } } window.scrollTo(0, document.body.scrollHeight); setTimeout(() => window.scrollTo(0, 0), 300); })();",
        "waitForCompletion": true,
        "timeout": 10,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1968,
      "position_y": 800,
      "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": 2304,
      "position_y": 800,
      "config": {
        "selector": "body",
        "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": 2640,
      "position_y": 800,
      "config": {
        "rowSelector": "body",
        "fileName": "gelbe_seiten_details_scraper_cloud_final.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "branche",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const vals=[]; ['[itemprop=category]','.mod-TeilnehmerKopf__branchen a','.mod-TeilnehmerKopf__branche','[class*=Branche] a','[class*=branche] a'].forEach(sel=>vals.push(...Array.from(root.querySelectorAll(sel)).map(e=>clean(e.textContent)))); const good=Array.from(new Set(vals.filter(t=>t && !/Gelbe Seiten|Bewertung|Route/i.test(t)))); if(good.length) return good.join('|'); const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const txt='\\n'+(clone.innerText||'')+'\\n'; const m=txt.match(/\\n([^\\n]{2,90}:\\s*[^\\n]{3,180})\\n/); return m && !/Ihre gewünschte Verbindung|Hinweis|Öffnungszeiten|Route|Bewertung/i.test(m[1]) ? clean(m[1]) : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "beschreibung",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const explicit=root.querySelector('[itemprop=description], .mod-Beschreibung, [class*=Beschreibung], [class*=beschreibung], [class*=Description], [class*=description]'); if(explicit) return clean((explicit.innerText||explicit.textContent||'').replace(/^Über das Unternehmen\\s*/i,'')); const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const txt=clone.innerText||''; const m=txt.match(/Über das Unternehmen\\s*([\\s\\S]*?)(?:\\n\\s*(?:Im Web|Bewertungen|Öffnungszeiten|Weitere Informationen)\\b|$)/i); return m?clean(m[1]):''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "fax",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const el=root.querySelector('[itemprop=faxNumber], a[href^=fax]'); if(el) return clean((el.textContent||el.getAttribute('href')||'').replace(/^fax:/i,'')); const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const m=clean(clone.innerText).match(/Fax[^0-9+]*(\\+?\\d[\\d\\s()\\/-]{5,})/i); return m?m[1].trim():''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "zahlungsweise",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const txt=clone.innerText||''; const m=txt.match(/Zahlungsweise\\s*([\\s\\S]*?)(?:\\n\\s*(?:Öffnungszeiten|Über das Unternehmen|Im Web|Bewertungen|Weitere Informationen)\\b|$)/i); return m?clean(m[1]):''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "referenz_fotos_liste",
            "selector": "(() => { const root=ROW.querySelector('main,[role=main]')||ROW; const imgs=Array.from(root.querySelectorAll('img[src]')).map(img=>img.src).filter(src=>/(gelbeseiten\\.v4all\\.de|ies\\.v4all\\.de)/i.test(src)&&/(400x300|maxhoehe_150|_maxhoehe_)/i.test(src)&&!/webgs\\/images|logo|favicon|sprite|google-play|app-store|award|preis/i.test(src)); return Array.from(new Set(imgs)).join('||'); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "oeffnungszeiten",
            "selector": "(() => { const clean=s=>(s||'').replace(/[ \\t]+/g,' ').replace(/\\n\\s*/g,'\\n').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const txt=clone.innerText||''; const m=txt.match(/Öffnungszeiten\\s*([\\s\\S]*?)(?:\\n\\s*(?:Über das Unternehmen|Im Web|Bewertungen|Zahlungsweise|Weitere Informationen)\\b|$)/i); if(m) return clean(m[1].replace(/Jetzt\\s+(?:geöffnet|geschlossen)[^\\n]*/ig,'')); const vals=Array.from(root.querySelectorAll('[itemprop=openingHours], time, [class*=ffnungs], [class*=Opening], [class*=opening]')).map(e=>clean(e.innerText||e.textContent||e.getAttribute('content')||e.getAttribute('datetime')||'')).filter(t=>/[0-9]{1,2}[:.][0-9]{2}|Ruhetag|Montag|Dienstag|Mittwoch|Donnerstag|Freitag|Samstag|Sonntag/i.test(t)); return Array.from(new Set(vals)).join('\\n'); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "reise_info",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; if(/Anfahrt mit Bus und Bahn/i.test(root.innerText||'')) return 'Anfahrt mit Bus und Bahn'; const el=Array.from(root.querySelectorAll('a,button')).find(e=>/^(Route|Route planen|Anfahrt)$/i.test(clean(e.textContent||e.getAttribute('aria-label')||'')) || e.id==='modAktionsleisteRoute'); return el ? clean(el.textContent||el.getAttribute('aria-label')||'Route') : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "website",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const blocked=/gelbeseiten\\.de|dastelefonbuch\\.de|dasoertliche\\.de|facebook\\.com|instagram\\.com|pinterest\\.de|tiktok\\.com|apple\\.com|google\\.com|bcrw\\.apple\\.com/i; const anchors=Array.from(root.querySelectorAll('a[href]')).filter(a=>/^https?:/i.test(a.href)&&!blocked.test(a.href)); const byText=anchors.find(a=>/^(Website|Webseite)$/i.test(clean(a.textContent))); return (byText||anchors[0]||{}).href||''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "telefonnummer",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const a=root.querySelector('a[href^=tel]'); if(a) return clean((a.textContent||a.getAttribute('href')||'').replace(/^tel:/i,'')); const el=root.querySelector('[itemprop=telephone]'); if(el) return clean(el.textContent||el.getAttribute('content')); const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const txt=clean(clone.innerText); const nums=txt.match(/(?:\\+49|0)\\d[\\d\\s\\/()-]{5,}\\d/g)||[]; return nums.map(clean).find(n=>n.replace(/\\D/g,'').length>=7)||''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "titel",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const el=root.querySelector('[itemprop=name], .mod-TeilnehmerKopf__name, h1, [class*=Name], [class*=Titel], [class*=title]'); let t=clean(el&&el.textContent); t=t.split(/\\s+(?:\\d,\\d|\\d\\.\\d)\\s+/)[0]; t=t.split(/\\s+Ärzte:|\\s+Gratis anrufen|\\s+E-Mail|\\s+Website|\\s+Route/i)[0]; return clean(t); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "adresse",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const el=root.querySelector('[itemprop=address], address, .mod-AdresseKompakt__adress-text, [class*=Adresse], [class*=address], [class*=Anschrift]'); if(el) return clean(el.textContent); const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const m=(clone.innerText||'').match(/([^\\n,]+\\s+\\d+[\\w\\-\\/]*,\\s*\\d{5}\\s+[^\\n]+)/); return m?clean(m[1]):''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "oeffnungsinfo_heute",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const raw=clone.innerText||''; let m=raw.match(/Jetzt\\s+(?:geöffnet|geschlossen)\\s*[–-]\\s*(?:Öffnet|Schließt)\\s*um\\s*\\d{1,2}[:.]\\d{2}/i); if(m) return clean(m[0]); m=raw.match(/Jetzt\\s+(?:geöffnet|geschlossen)/i); return m?clean(m[0]):''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "scrapen_zeit",
            "selector": "(() => new Date().toISOString())()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "url",
            "selector": "(() => location.href)()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "breadcrumb",
            "selector": "(() => { const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const root=ROW.querySelector('main,[role=main]')||ROW; const links=Array.from(root.querySelectorAll('.mod-Breadcrumb a, nav[aria-label*=readcrumb] a')).map(e=>clean(e.textContent)).filter(Boolean); const out=[]; for(const x of links){ if(!out.includes(x)) out.push(x); } return out.join(' > '); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "e_mail",
            "selector": "(() => { const root=ROW.querySelector('main,[role=main]')||ROW; const a=root.querySelector('a[href^=mailto]'); if(a) return (a.getAttribute('href')||'').replace(/^mailto:/i,'').split('?')[0]; const clone=root.cloneNode(true); clone.querySelectorAll('script,style,noscript,footer,.mod-Footer').forEach(e=>e.remove()); const m=(clone.innerText||'').match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/i); return m?m[0]:''; })()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-2",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 2976,
      "position_y": 800,
      "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": "sleep-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-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": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-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": "loop-continue-2",
      "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": 384,
      "position_y": 116,
      "width": 2168,
      "height": 876,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "sleep-2",
          "wait-for-element-1"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1392,
      "position_y": 116,
      "width": 1832,
      "height": 876,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "text-contains-1",
          "loop-continue-1",
          "loop-continue-2"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1392,
      "position_y": 416,
      "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": 2568,
      "position_y": 696,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Gelbe Seiten detail-page lead scraper equivalent to the Octoparse Cloud-by-URLs template. Seeded with /gsbiz/ URLs from the Octoparse preview; replace or extend navigate.urls with fresh detail URLs from a Gelbe Seiten listing scraper. Uses a multi-URL loop with append mode. Removed/expired pages showing 'Der gesuchte Teilnehmer konnte nicht gefunden werden' are skipped. Extraction uses scoped JS heuristics for valid detail pages, including cleaned title, opening-status, breadcrumb, contact, address, photos, opening hours, and description fields.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-navigate-1",
      "element_type": "note",
      "title": "Note: Navigate",
      "content": "Multi-URL loop over 5 pages. Pair with loop-continue at the end of each iteration.",
      "color": "#ee5396",
      "position_x": 656,
      "position_y": 200,
      "width": 328,
      "height": 107,
      "z_index": 22,
      "data": {
        "block_id": "navigate-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": 1664,
      "position_y": 200,
      "width": 340,
      "height": 131,
      "z_index": 22,
      "data": {
        "block_id": "text-contains-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": 2000,
      "position_y": 500,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    },
    {
      "id": "note-block-inject-javascript-1",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(() => { const texts = ['Akzeptieren', 'Alle akzeptieren', 'Accept', 'Zustimmen', 'Einverstanden']; ...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1664,
      "position_y": 500,
      "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": "Structured export with JS columns (branche, beschreibung, fax, zahlungsweise, referenz_fotos_liste). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2840,
      "position_y": 780,
      "width": 340,
      "height": 135,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    },
    {
      "id": "note-block-loop-continue-2",
      "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": 3176,
      "position_y": 780,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-2"
      }
    }
  ]
}