{
  "version": "1.0.0",
  "exported_at": "2026-06-03T00:00:00.000Z",
  "project": {
    "name": "Localch Scraper italiano",
    "description": "Local.ch Italian search-results scraper equivalent to the Octoparse Local.ch Scraper. It extracts keyword, business name, address, specialties, description, rating, review count, phone, fax, mobile, email, and website. Multiple keyword searches are handled with navigate.urls and loop-continue. Pagination is implemented with a JavaScript-marked Next/Successiva control and a safety cap of 20 pages per keyword to avoid infinite loops if Local.ch keeps pagination controls enabled.",
    "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.local.ch/it/q?what=Medici&where=",
          "https://www.local.ch/it/q?what=Bar&where=Zurich"
        ],
        "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": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 840,
      "position_y": 260,
      "config": {
        "jsCode": "(()=>{const labels=['Accept','Accept all','Accetta','Acconsento','Accetta tutto','Tout accepter','Alle akzeptieren','OK'];const btn=[...document.querySelectorAll('button,a,[role=\"button\"]')].find(el=>labels.some(l=>(el.textContent||'').trim().toLowerCase().includes(l.toLowerCase())));if(btn)btn.click();return !!btn;})()",
        "waitForCompletion": true,
        "timeout": 10
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1200,
      "position_y": 260,
      "config": {
        "duration": 3
      }
    },
    {
      "block_id": "inject-javascript-2",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1560,
      "position_y": 260,
      "config": {
        "jsCode": "(()=>{const MAX_PAGES=20;const clean=s=>(s||'').replace(/\\s+/g,' ').trim();const norm=s=>clean(s).toLowerCase();const params=new URL(location.href).searchParams;const keywordKey='localch_'+(params.get('what')||'keyword')+'_'+(params.get('where')||'all');const currentCount=Number(sessionStorage.getItem(keywordKey)||'0')+1;sessionStorage.setItem(keywordKey,String(currentCount));const visible=el=>{const r=el.getBoundingClientRect();return r.width>20&&r.height>20};const address=t=>{t=t||'';const patterns=[/(?:[A-ZÀ-ÿa-z0-9 .,'’\\-]+(?:strasse|straße|weg|platz|gasse|ring|allee|quai|riva|via|rue|route|chemin|vicolo|corso|piazza|avenue)\\s+\\d+[a-zA-Z]?[^\\n,]*,?\\s*\\d{4}\\s+[A-ZÀ-ÿ][^\\n,]*)/i,/(?:[A-ZÀ-ÿa-z0-9 .,'’\\-]+\\s+\\d+[a-zA-Z]?[^\\n,]*,\\s*\\d{4}\\s+[A-ZÀ-ÿ][^\\n,]*)/i,/\\b\\d{4}\\s+[A-ZÀ-ÿ][A-ZÀ-ÿa-z .'-]+\\b/];for(const p of patterns){const m=t.match(p);if(m)return clean(m[0]);}return ''};const rating=t=>{let m=(t||'').match(/\\b([0-5][.,]\\d)\\s*\\/\\s*5\\b/)||(t||'').match(/Valutazione\\s+([0-5](?:[.,]\\d)?)/i)||(t||'').match(/\\b([0-5][.,]\\d)\\b/);return m?m[1].replace(',','.'):''};const reviews=t=>{if(/Nessuna recensione/i.test(t||''))return '0';let m=(t||'').match(/\\((\\d+)\\)/)||(t||'').match(/(\\d+)\\s*(recensioni|Bewertungen|avis|reviews?|valutazioni)/i);return m?m[1]:''};const specialty=t=>{const lines=(t||'').split(/\\n+/).map(clean).filter(Boolean);return lines.find(l=>l.includes('•')&&!/Valutazione|recension|Bewertung|avis|reviews|Aperto|Chiuso|Orario/i.test(l))||''};const description=t=>{const a=address(t);const lines=(t||'').split(/\\n+/).map(clean).filter(Boolean);const bad=/^(Aperto|Chiuso|Orario|Valutazione|Nessuna recensione|\\d+(?:[.,]\\d)?\\s*\\/\\s*5|Mostra|Indicazioni|Telefono|Sito web|E-mail|Email|Route|Mappa)$/i;return lines.find(l=>l.length>45&&!l.includes('•')&&!bad.test(l)&&l!==a&&!/\\d{4}\\s+[A-ZÀ-ÿ]/.test(l))||''};const nameFrom=(el,t,addr)=>{let n=clean((el.querySelector('h1,h2,h3,a[href]')||{}).textContent);if(!n||n.length>160||/in tutte le regioni|Iscrizioni|Risultati|local\\.ch/i.test(n)){n=(t.split(/\\n+/).map(clean).find(l=>l&&l!==addr&&!l.includes('•')&&!/Valutazione|recension|Iscrizioni|Risultati|Aperto|Chiuso|local\\.ch|Mappa|Route/i.test(l)&&l.length<160)||'');}return n};document.querySelectorAll('[data-uscraper-row=\"1\"]').forEach(e=>e.removeAttribute('data-uscraper-row'));document.querySelectorAll('[data-uscraper-next=\"1\"]').forEach(e=>e.removeAttribute('data-uscraper-next'));let candidates=[...document.querySelectorAll('article,section,li,div')].filter(visible).map(el=>({el,t:el.innerText||''})).filter(o=>{const l=clean(o.t).length;return l>45&&l<8000&&address(o.t);});let smallest=[];for(const o of candidates){const childHas=[...o.el.children].some(c=>address(c.innerText||'')&&clean(c.innerText).length>45);if(!childHas)smallest.push(o)}if(smallest.length<5)smallest=candidates;smallest.sort((a,b)=>clean(a.t).length-clean(b.t).length);const seen=new Set();let count=0;for(const o of smallest){const el=o.el,t=o.t,addr=address(t),name=nameFrom(el,t,addr);if(!name||!addr||/in tutte le regioni|Iscrizioni|Risultati/i.test(name))continue;const key=norm(name+'|'+addr);if(seen.has(key))continue;seen.add(key);el.setAttribute('data-uscraper-row','1');el.dataset.name=name;el.dataset.address=addr;el.dataset.specialty=specialty(t);el.dataset.description=description(t);el.dataset.rating=rating(t);el.dataset.reviews=reviews(t);el.dataset.phone='';el.dataset.fax='';el.dataset.mobile='';el.dataset.email='';el.dataset.website='';const tel=[...el.querySelectorAll('a[href^=\"tel:\"]')].map(x=>x.getAttribute('href').replace(/^tel:/,'').replace(/[^0-9+]/g,''));if(tel[0])el.dataset.phone=tel[0];const fax=t.match(/Fax\\s*[:\\n ]\\s*([+0-9][0-9 ()-]{6,})/i);if(fax)el.dataset.fax=fax[1].replace(/[^0-9+]/g,'');const mob=t.match(/(Cellulare|Mobile|Natel)\\s*[:\\n ]\\s*([+0-9][0-9 ()-]{6,})/i);if(mob)el.dataset.mobile=mob[2].replace(/[^0-9+]/g,'');const mail=el.querySelector('a[href^=\"mailto:\"]');if(mail)el.dataset.email=mail.href.replace(/^mailto:/,'').split('?')[0];const em=t.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/i);if(em&&!el.dataset.email)el.dataset.email=em[0];const ext=[...el.querySelectorAll('a[href]')].map(x=>x.href).filter(h=>!h.includes('local.ch')&&!h.includes('maplibre')&&!h.startsWith('tel:')&&!h.startsWith('mailto:')&&!h.includes('javascript:'));if(ext[0])el.dataset.website=ext[0];count++;if(count>=40)break;}if(currentCount<MAX_PAGES){const next=[...document.querySelectorAll('a,button')].find(el=>visible(el)&&!el.disabled&&el.getAttribute('aria-disabled')!=='true'&&!/disabled/i.test(el.className||'')&&(/next/i.test(el.getAttribute('rel')||'')||/next|successiva/i.test(el.getAttribute('aria-label')||'')||/^›$|Avanti|Successiva/i.test(clean(el.textContent)))&&!/prev|precedente|indietro|‹/i.test((el.getAttribute('aria-label')||'')+' '+clean(el.textContent)));if(next)next.setAttribute('data-uscraper-next','1');}return {rows:count,page:currentCount,next:!!document.querySelector('[data-uscraper-next=\"1\"]')};})()",
        "waitForCompletion": true,
        "timeout": 20
      }
    },
    {
      "block_id": "element-exists-0",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 1920,
      "position_y": 260,
      "config": {
        "selector": "[data-uscraper-row=\"1\"]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2280,
      "position_y": 260,
      "config": {
        "rowSelector": "[data-uscraper-row=\"1\"]",
        "fileName": "local-ch-scraper-it.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "columns": [
          {
            "name": "parola_chiave",
            "selector": "(()=>{const p=new URL(location.href).searchParams;const what=p.get('what')||'';const where=p.get('where')||'';return [what,where].filter(Boolean).join(', ')||document.title;})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "nome_attivita",
            "selector": "ROW.dataset.name || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "posizione",
            "selector": "ROW.dataset.address || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "specialita",
            "selector": "ROW.dataset.specialty || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "descrizione",
            "selector": "ROW.dataset.description || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating",
            "selector": "ROW.dataset.rating || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "recensioni",
            "selector": "ROW.dataset.reviews || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "telefono",
            "selector": "ROW.dataset.phone || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "fax",
            "selector": "ROW.dataset.fax || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "cellulare",
            "selector": "ROW.dataset.mobile || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "email",
            "selector": "ROW.dataset.email || ''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "sito_web",
            "selector": "ROW.dataset.website || ''",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "element-exists-1",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 2640,
      "position_y": 260,
      "config": {
        "selector": "[data-uscraper-next=\"1\"]"
      }
    },
    {
      "block_id": "click-1",
      "block_type": "process",
      "title": "Click",
      "description": "Click on element",
      "position_x": 2640,
      "position_y": 580,
      "config": {
        "selector": "[data-uscraper-next=\"1\"]",
        "timeout": 10
      }
    },
    {
      "block_id": "wait-for-page-load-2",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 3000,
      "position_y": 580,
      "config": {
        "timeout": 30
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 3360,
      "position_y": 580,
      "config": {
        "duration": 2
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 3000,
      "position_y": 900,
      "config": {}
    },
    {
      "block_id": "end-1",
      "block_type": "output",
      "title": "End",
      "description": "Terminate execution flow",
      "position_x": 3360,
      "position_y": 900,
      "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": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-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": "inject-javascript-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-2",
      "from_connector_id": "right",
      "to_block_id": "element-exists-0",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-0",
      "from_connector_id": "true",
      "to_block_id": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-0",
      "from_connector_id": "false",
      "to_block_id": "loop-continue-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": "loop-continue-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": "sleep-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-2",
      "from_connector_id": "right",
      "to_block_id": "inject-javascript-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "loop-continue-1",
      "from_connector_id": "right",
      "to_block_id": "end-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": 3560,
      "height": 616,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "wait-for-page-load-2",
          "sleep-2"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 768,
      "position_y": 156,
      "width": 1040,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1",
          "inject-javascript-2"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1848,
      "position_y": 156,
      "width": 1400,
      "height": 936,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "element-exists-0",
          "element-exists-1",
          "click-1",
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2208,
      "position_y": 156,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "group-control",
      "element_type": "group",
      "title": "Control Flow",
      "color": "#8d8d8d",
      "position_x": 3288,
      "position_y": 796,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "end-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Local.ch Italian search-results scraper equivalent to the Octoparse Local.ch Scraper. It extracts keyword, business name, address, specialties, description, rating, review count, phone, fax, mobile, email, and website. Multiple keyword searches are handled with navigate.urls and loop-continue. Pagination is implemented with a JavaScript-marked Next/Successiva control and a safety cap of 20 pages per keyword to avoid infinite loops if Local.ch keeps pagination controls enabled.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-inject-javascript-2",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(()=>{const MAX_PAGES=20;const clean=s=>(s||'').replace(/\\s+/g,' ').trim();const norm=s=>clean(s).to...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 240,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-2"
      }
    },
    {
      "id": "note-block-element-exists-1",
      "element_type": "note",
      "title": "Note: Element Exists",
      "content": "Condition block: checks `[data-uscraper-next=\"1\"]`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 2840,
      "position_y": 240,
      "width": 340,
      "height": 138,
      "z_index": 22,
      "data": {
        "block_id": "element-exists-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": 3200,
      "position_y": 880,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}