{
  "version": "1.0.0",
  "exported_at": "2026-06-02T15:40:00.000Z",
  "project": {
    "name": "InfoJobs Details Scraper",
    "description": "Scrapes InfoJobs job detail pages by URL and exports job title, URL, company, company URL, rating/qualification, location, work mode, posting time, salary, minimum experience, contract type, minimum studies, description, category, level, and vacancies. Navigation uses a multi-detail-URL loop with append mode so all provided job URLs are written to one CSV. InfoJobs may show a CAPTCHA/robot check; this best-effort template records extraction_status, avoids footer false positives, and outputs safe URL-derived fallback title/location when blocked.",
    "color": "bg-[#4589ff]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "set-window-size-1",
      "block_type": "process",
      "title": "Set Window Size",
      "description": "Set browser viewport size",
      "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": 480,
      "position_y": 220,
      "config": {
        "urls": [
          "https://www.infojobs.net/malaga/mozo-conductor-lavador-vehiculos-incorporacion-inmediata/of-i729cebf99d4b2fbc78d959caa39fc4?applicationOrigin=search-new&page=1&sortBy=RELEVANCE",
          "https://www.infojobs.net/madrid/lavador-conductor-vehiculos-madrid/of-i5f1d33d5b94de08d708059f4e51bf4?applicationOrigin=search-new&page=1&sortBy=RELEVANCE"
        ],
        "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": 840,
      "position_y": 220,
      "config": {
        "timeout": 45
      }
    },
    {
      "block_id": "element-exists-1",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "selector": "#captcha-box, .geetest_holder, .geetest_radar_btn, h1.contrast"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1560,
      "position_y": 120,
      "config": {
        "duration": 15
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1560,
      "position_y": 500,
      "config": {
        "duration": 3
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1920,
      "position_y": 320,
      "config": {
        "rowSelector": "body",
        "fileName": "infojobs_detalles_scraper.csv",
        "includeHeaders": true,
        "fileMode": "append",
        "columns": [
          {
            "name": "extraction_status",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return 'captcha_or_robot_check_detected';if(document.querySelector('main h1,h1[class*=ij-Heading],h1:not(.contrast)'))return 'ok';return 'loaded_but_job_selectors_not_confirmed';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "empleo",
            "selector": "(()=>{const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));if(d?.title)return d.title;const h=document.querySelector('main h1,h1[class*=ij-Heading],h1:not(.contrast)')?.innerText?.trim();if(h)return h;const p=decodeURIComponent(location.pathname).split('/').filter(Boolean);const slug=p.length>1?p[1]:'';return slug?slug.replace(/-/g,' ').toUpperCase():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "empleo_url",
            "selector": "location.href",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "empresa",
            "selector": "(()=>{const t=document.body.innerText||'';const cap=document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t);if(cap)return '';const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));if(d?.hiringOrganization?.name)return d.hiringOrganization.name;const a=document.querySelector('main a[href*=\"ofertas-trabajo.infojobs.net\"],main a[href*=\"/em-\"]');return a?.innerText?.trim()||''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "empresa_url",
            "selector": "(()=>{const t=document.body.innerText||'';const cap=document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t);if(cap)return '';const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));if(d?.hiringOrganization?.sameAs||d?.hiringOrganization?.url)return d.hiringOrganization.sameAs||d.hiringOrganization.url;const a=document.querySelector('main a[href*=\"ofertas-trabajo.infojobs.net\"],main a[href*=\"/em-\"]');return a?.href||''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "calificacion",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const m=t.replace(/\\s+/g,' ').match(/(?:Calificación|Valoración)?\\s*(\\d[,.]\\d)(?:\\s*\\/\\s*5|\\s*opiniones|\\s*valoraciones)?/i);return m?m[1].replace('.',','):''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "ubicacion",
            "selector": "(()=>{const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));const loc=d?.jobLocation;const arr=Array.isArray(loc)?loc:(loc?[loc]:[]);const v=arr.map(l=>{const a=l?.address||{};return [a.addressLocality,a.addressRegion,a.addressCountry].filter(Boolean).join(', ')}).filter(Boolean).join(' | ');if(v)return v;const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t)){const city=decodeURIComponent(location.pathname).split('/').filter(Boolean)[0]||'';return city?city.charAt(0).toUpperCase()+city.slice(1):'';}const m=t.replace(/\\s+/g,' ').match(/Ubicación\\s*:?(.*?)(?=\\s*(Modalidad|Salario|Experiencia|Contrato|Publicada)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "modalidad",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const x=t.replace(/\\s+/g,' ');const m=x.match(/Modalidad\\s*:?(.*?)(?=\\s*(Publicada|Salario|Experiencia|Contrato|Estudios|Categoría)\\b|$)/i);if(m)return m[1].trim();const p=x.match(/\\b(Presencial|Híbrido|Teletrabajo|Remoto)\\b/i);return p?p[1]:''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "tiempo_de_publicacion",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));if(d?.datePosted)return d.datePosted;const m=t.replace(/\\s+/g,' ').match(/Publicada\\s*:?(.*?)(?=\\s*(Salario|Experiencia|Contrato|Estudios|Descripción|Categoría)\\b|$)/i);return m?('Publicada '+m[1].trim()).trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "salario",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));const bs=d?.baseSalary;if(bs){const v=bs.value||{};const amount=(v.minValue&&v.maxValue)?(v.minValue+' - '+v.maxValue):(v.value||v.minValue||v.maxValue||'');const out=[amount,bs.currency||v.currency,v.unitText].filter(Boolean).join(' ');if(out)return out;}const m=t.replace(/\\s+/g,' ').match(/Salario\\s*:?(.*?)(?=\\s*(Experiencia|Contrato|Tipo de contrato|Estudios|Descripción|Categoría)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "experiencia_minima",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const m=t.replace(/\\s+/g,' ').match(/Experiencia\\s*mínima\\s*:?(.*?)(?=\\s*(Tipo de contrato|Contrato|Estudios mínimos|Estudios|Descripción|Categoría|Nivel|Número de vacantes)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "tipo_de_contrato",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));if(d?.employmentType)return Array.isArray(d.employmentType)?d.employmentType.join(', '):d.employmentType;const m=t.replace(/\\s+/g,' ').match(/(?:Tipo de contrato|Contrato)\\s*:?(.*?)(?=\\s*(Estudios mínimos|Estudios|Descripción|Categoría|Nivel|Número de vacantes)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "estudios_minimos",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const m=t.replace(/\\s+/g,' ').match(/Estudios\\s*mínimos\\s*:?(.*?)(?=\\s*(Descripción|Categoría|Nivel|Número de vacantes|Vacantes)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "descripcion",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const strip=s=>(s||'').replace(/<[^>]*>/g,' ').replace(/\\s+/g,' ').trim();const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));if(d?.description)return strip(d.description);const m=t.replace(/\\s+/g,' ').match(/Descripción\\s*:?(.*?)(?=\\s*(Categoría|Nivel|Número de vacantes|Vacantes)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "categoria",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const d=[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s=>{try{return JSON.parse(s.textContent)}catch(e){return null}}).flatMap(x=>Array.isArray(x)?x:[x]).find(x=>x&&String(x['@type']||'').includes('JobPosting'));if(d?.occupationalCategory)return Array.isArray(d.occupationalCategory)?d.occupationalCategory.join(', '):d.occupationalCategory;if(d?.industry)return d.industry;const m=t.replace(/\\s+/g,' ').match(/Categoría\\s*:?(.*?)(?=\\s*(Nivel|Número de vacantes|Vacantes)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "nivel",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const m=t.replace(/\\s+/g,' ').match(/Nivel\\s*:?(.*?)(?=\\s*(Número de vacantes|Vacantes)\\b|$)/i);return m?m[1].trim():''})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "numero_de_vacantes",
            "selector": "(()=>{const t=document.body.innerText||'';if(document.querySelector('#captcha-box,.geetest_holder,.geetest_radar_btn')||/¿Eres humano o un robot\\?|Hacer clic para comprobar|actividad poco habitual/i.test(t))return '';const m=t.replace(/\\s+/g,' ').match(/(?:Número de vacantes|Vacantes)\\s*:?(\\d+)/i);return m?m[1]:''})()",
            "attribute": "text",
            "isJs": true
          }
        ],
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates"
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 2280,
      "position_y": 320,
      "config": {}
    }
  ],
  "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": "element-exists-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "true",
      "to_block_id": "sleep-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "false",
      "to_block_id": "sleep-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-1",
      "from_connector_id": "right",
      "to_block_id": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-2",
      "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-1",
      "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": 408,
      "position_y": 16,
      "width": 1400,
      "height": 676,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "sleep-2"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1128,
      "position_y": 116,
      "width": 1400,
      "height": 396,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "element-exists-1",
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 1848,
      "position_y": 216,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes InfoJobs job detail pages by URL and exports job title, URL, company, company URL, rating/qualification, location, work mode, posting time, salary, minimum experience, contract type, minimum studies, description, category, level, and vacancies. Navigation uses a multi-detail-URL loop with append mode so all provided job URLs are written to one CSV. InfoJobs may show a CAPTCHA/robot check; this best-effort template records extraction_status, avoids footer false positives, and outputs safe URL-derived fallback title/location when blocked.",
      "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 `#captcha-box, .geetest_holder, .geetest_radar_btn, h1.contrast`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 1400,
      "position_y": 200,
      "width": 340,
      "height": 151,
      "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 (extraction_status, empleo, empleo_url, empresa, empresa_url). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 300,
      "width": 340,
      "height": 133,
      "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": 2480,
      "position_y": 300,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}