{
  "version": "1.0.0",
  "exported_at": "2026-05-31T17:25:00.000Z",
  "project": {
    "name": "LinkedIn Job Details Page Scraper",
    "description": "Best-effort LinkedIn job detail scraper equivalent to the Octoparse template. It navigates a multi-URL list of LinkedIn job detail URLs, waits for each page, injects a normalizing JavaScript extractor, and exports job title, job link, company, company link, location, post time, applicant count, job description, industry, employment type, valid-through date, seniority level, job function, hiring person, and pay range. Pagination/navigation strategy: Strategy A multi-URL loop with loop-continue because the source template accepts job URLs rather than scraping a search-results listing. LinkedIn returned authwall / HTTP 999 during analysis, so run this with an authorized or already logged-in persistent browser profile; otherwise blocked pages may return only URL-derived values and blank protected fields. Extraction uses JSON-LD first, LinkedIn public/detail DOM selectors second, and URL-slug fallback for expired/redirected job pages.",
    "color": "bg-[#0a66c2]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to each LinkedIn job detail URL",
      "position_x": 120,
      "position_y": 220,
      "config": {
        "urls": [
          "https://www.linkedin.com/jobs/view/outside-sales-executive-at-smarter-swipe-3967000340?position=3&pageNum=0&refId=OXxjsdoYVggvki7R6%2BP3ow%3D%3D&trackingId=aozYn7fEs07zvJHMTTb1uA%3D%3D&trk=public_jobs_jserp-result_search-card",
          "https://www.linkedin.com/jobs/view/senior-director-sales-and-marketing-at-tree-island-steel-3973367272?position=1&pageNum=0&refId=49zTjm04JsRRbjnDmSM4Dg%3D%3D&trackingId=0dYMNTpi65pcLAa9lrOPvg%3D%3D&trk=public_jobs_jserp-result_search-card"
        ],
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "wait-for-page-load-1",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for LinkedIn page load/authwall redirect to finish",
      "position_x": 480,
      "position_y": 220,
      "config": {
        "timeout": 30,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Allow LinkedIn dynamic job content or authwall redirect to settle",
      "position_x": 840,
      "position_y": 220,
      "config": {
        "duration": 3,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait for the document body before JS-based extraction",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "selector": "body",
        "timeout": 20,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Normalize LinkedIn job data into one text-based extraction row",
      "position_x": 1560,
      "position_y": 220,
      "config": {
        "jsCode": "(function(){function clean(v){return(v==null?'':String(v)).replace(/\\s+/g,' ').trim()}function text(s){var e=document.querySelector(s);return e?clean(e.innerText||e.textContent):''}function href(s){var e=document.querySelector(s);try{return e?new URL(e.getAttribute('href')||'',location.href).href:''}catch(x){return e?e.getAttribute('href')||'':''}}function findJob(o){if(!o)return null;if(Array.isArray(o)){for(var i=0;i<o.length;i++){var r=findJob(o[i]);if(r)return r}}else if(typeof o==='object'){var t=o['@type'];var ts=Array.isArray(t)?t.join(' '):String(t||'');if(ts.indexOf('JobPosting')>-1)return o;if(o['@graph'])return findJob(o['@graph'])}return null}function jsonJob(){var ss=document.querySelectorAll('script[type=\"application/ld+json\"]');for(var i=0;i<ss.length;i++){try{var r=findJob(JSON.parse(ss[i].textContent));if(r)return r}catch(e){}}return{}}function targetUrl(){try{var u=new URL(location.href);return decodeURIComponent(u.searchParams.get('sessionRedirect')||location.href)}catch(e){return location.href}}function titleFromUrl(){try{var u=new URL(targetUrl());var p=u.pathname;var slug='';if(p.indexOf('/jobs/view/')>-1)slug=p.split('/jobs/view/')[1].split('/')[0];else if(p.indexOf('/jobs/')>-1)slug=p.split('/jobs/')[1].split('/')[0];slug=slug.replace(/-\\d+$/,'').replace(/-at-.+$/,'').replace(/-jobs$/,'').replace(/-/g,' ').trim();return slug?slug.replace(/\\b\\w/g,function(c){return c.toUpperCase()}):''}catch(e){return''}}function crit(label){label=label.toLowerCase();var items=document.querySelectorAll('.description__job-criteria-item, li');for(var i=0;i<items.length;i++){var t=(items[i].innerText||items[i].textContent||'');if(t.toLowerCase().indexOf(label)>-1){var v=items[i].querySelector('.description__job-criteria-text, span:not(.description__job-criteria-subheader)');return clean((v?v.innerText||v.textContent:t.replace(new RegExp(label,'i'),'')))}}return''}var j=jsonJob();var loc=Array.isArray(j.jobLocation)?j.jobLocation[0]:j.jobLocation;var addr=loc&&loc.address?loc.address:{};var locationText=[addr.addressLocality,addr.addressRegion,addr.addressCountry].filter(Boolean).join(', ');var bs=Array.isArray(j.baseSalary)?j.baseSalary[0]:j.baseSalary;var val=bs&&bs.value?bs.value:{};var meta=(document.querySelector('meta[property=\"og:title\"],meta[name=\"twitter:title\"]')||{}).content||'';var descEl=document.querySelector('.description__text .show-more-less-html__markup, .show-more-less-html__markup, #job-details, .jobs-description__content .jobs-box__html-content, .jobs-description-content__text, [class*=\"jobs-description\"]');var rawTitle=clean(j.title||text('h1.top-card-layout__title')||text('h1.jobs-unified-top-card__job-title')||text('.job-details-jobs-unified-top-card__job-title h1')||text('.job-details-jobs-unified-top-card__job-title')||text('.topcard__title')||text('.base-search-card__title')||text('.job-search-card__title')||text('a.base-card__full-link')||titleFromUrl()||meta||document.title).replace(/\\s+\\|\\s+LinkedIn.*$/i,'').replace(/\\s+-\\s+LinkedIn.*$/i,'');var data={Job_title:rawTitle,Job_link:targetUrl(),Company:clean((j.hiringOrganization&&j.hiringOrganization.name)||text('a.topcard__org-name-link')||text('.top-card-layout__second-subline a[href*=\"/company/\"]')||text('.job-details-jobs-unified-top-card__company-name a')||text('.base-search-card__subtitle a')||text('.job-search-card__subtitle-link')||text('a[href*=\"/company/\"]')),Company_link:clean((j.hiringOrganization&&j.hiringOrganization.sameAs)||href('a.topcard__org-name-link[href], .top-card-layout__second-subline a[href*=\"/company/\"], .job-details-jobs-unified-top-card__company-name a[href], .base-search-card__subtitle a[href], .job-search-card__subtitle-link[href], a[href*=\"/company/\"]')),Job_location:clean(locationText||text('.topcard__flavor--bullet')||text('.job-search-card__location')||text('.base-search-card__metadata')||text('.jobs-unified-top-card__bullet')||text('.job-details-jobs-unified-top-card__primary-description-container')),Post_time:clean(j.datePosted||text('.posted-time-ago__text')||text('time')||text('.job-search-card__listdate')||text('.job-search-card__listdate--new')||text('.jobs-unified-top-card__posted-date')),Applicant_count:clean(text('.num-applicants__caption')||text('.jobs-unified-top-card__applicant-count')||text('[class*=\"applicant\"]')),Job_description:clean((descEl?(descEl.innerText||descEl.textContent):'')||String(j.description||'').replace(/<[^>]+>/g,' ')),Industry:clean(j.industry||crit('industries')||crit('industry')),Employment_type:clean((Array.isArray(j.employmentType)?j.employmentType.join(', '):j.employmentType)||crit('employment type')),Valid_through:clean(j.validThrough),Seniority_level:clean(crit('seniority level')),Job_function:clean(j.occupationalCategory||crit('job function')),Hiring_person:clean(text('.hirer-card__hirer-information a')||text('.jobs-poster__name')||text('[data-test-recruiter-name]')||text('.message-the-recruiter h3')||text('[class*=\"recruiter\"] a')),minPay:clean(val.minValue||(val.value&&val.value.minValue)||''),maxPay:clean(val.maxValue||(val.value&&val.value.maxValue)||'')};var old=document.getElementById('uscraper-linkedin-job-row');if(old)old.remove();var row=document.createElement('div');row.id='uscraper-linkedin-job-row';row.style.cssText='position:absolute;left:-10000px;top:0;width:1px;height:1px;overflow:hidden;white-space:pre-wrap;';Object.keys(data).forEach(function(k){var span=document.createElement('span');span.setAttribute('data-field',k);span.textContent=data[k]||'';row.appendChild(span)});document.body.appendChild(row);return true;})();",
        "waitForCompletion": true,
        "timeout": 10,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export normalized LinkedIn job detail fields",
      "position_x": 1920,
      "position_y": 220,
      "config": {
        "rowSelector": "#uscraper-linkedin-job-row",
        "fileName": "linkedin_job_details_scraper_v2.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "Job_title",
            "selector": "[data-field='Job_title']",
            "attribute": "text"
          },
          {
            "name": "Job_link",
            "selector": "[data-field='Job_link']",
            "attribute": "text"
          },
          {
            "name": "Company",
            "selector": "[data-field='Company']",
            "attribute": "text"
          },
          {
            "name": "Company_link",
            "selector": "[data-field='Company_link']",
            "attribute": "text"
          },
          {
            "name": "Job_location",
            "selector": "[data-field='Job_location']",
            "attribute": "text"
          },
          {
            "name": "Post_time",
            "selector": "[data-field='Post_time']",
            "attribute": "text"
          },
          {
            "name": "Applicant_count",
            "selector": "[data-field='Applicant_count']",
            "attribute": "text"
          },
          {
            "name": "Job_description",
            "selector": "[data-field='Job_description']",
            "attribute": "text"
          },
          {
            "name": "Industry",
            "selector": "[data-field='Industry']",
            "attribute": "text"
          },
          {
            "name": "Employment_type",
            "selector": "[data-field='Employment_type']",
            "attribute": "text"
          },
          {
            "name": "Valid_through",
            "selector": "[data-field='Valid_through']",
            "attribute": "text"
          },
          {
            "name": "Seniority_level",
            "selector": "[data-field='Seniority_level']",
            "attribute": "text"
          },
          {
            "name": "Job_function",
            "selector": "[data-field='Job_function']",
            "attribute": "text"
          },
          {
            "name": "Hiring_person",
            "selector": "[data-field='Hiring_person']",
            "attribute": "text"
          },
          {
            "name": "minPay",
            "selector": "[data-field='minPay']",
            "attribute": "text"
          },
          {
            "name": "maxPay",
            "selector": "[data-field='maxPay']",
            "attribute": "text"
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue to the next LinkedIn job URL",
      "position_x": 2280,
      "position_y": 220,
      "config": {
        "color": "bg-[#ff832b]"
      }
    }
  ],
  "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": "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": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-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-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": 1400,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "wait-for-element-1"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1488,
      "position_y": 116,
      "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": 1848,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 2208,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Best-effort LinkedIn job detail scraper equivalent to the Octoparse template. It navigates a multi-URL list of LinkedIn job detail URLs, waits for each page, injects a normalizing JavaScript extractor, and exports job title, job link, company, company link, location, post time, applicant count, job description, industry, employment type, valid-through date, seniority level, job function, hiring person, and pay range. Pagination/navigation strategy: Strategy A multi-URL loop with loop-continue because the source template accepts job URLs rather than scraping a search-results listing. LinkedIn returned authwall / HTTP 999 during analysis, so run this with an authorized or already logged-in persistent browser profile; otherwise blocked pages may return only URL-derived values and blank protected fields. Extraction uses JSON-LD first, LinkedIn public/detail DOM selectors second, and URL-slug fallback for expired/redirected job pages.",
      "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 2 pages. Pair with loop-continue at the end of each iteration.",
      "color": "#ee5396",
      "position_x": 320,
      "position_y": 200,
      "width": 328,
      "height": 107,
      "z_index": 22,
      "data": {
        "block_id": "navigate-1"
      }
    },
    {
      "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==null?'':String(v)).replace(/\\s+/g,' ').trim()}function text(...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 200,
      "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": "Extracts rows matching `#uscraper-linkedin-job-row`. Confirm row count > 0 before running at scale.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 200,
      "width": 340,
      "height": 113,
      "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": 200,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}