AutomationFlowsSocial Media › Scrape Linkedin Job Listings with Scrapeunblocker and Google Sheets

Scrape Linkedin Job Listings with Scrapeunblocker and Google Sheets

ByZain Khan @zain on n8n.io

This workflow runs every 8 hours to scrape LinkedIn job search results for a chosen keyword and location using ScrapeUnblocker, then parses job details and appends them to a Google Sheets spreadsheet. Runs every 8 hours on a schedule. Sets the job search keyword and location,…

Cron / scheduled trigger★★★★☆ complexity10 nodesN8N Nodes ScrapeunblockerGoogle Sheets
Social Media Trigger: Cron / scheduled Nodes: 10 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #17397 — we link there as the canonical source.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "mmmwxbhqMNBbYGXN",
  "name": "Workflow 4 - Job Board Aggregator",
  "tags": [],
  "nodes": [
    {
      "id": "c1e723cb-3a63-4806-97b9-2b6b198271b6",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -976,
        16
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "2a14399a-6aaa-48a5-b273-e4626edd4160",
      "name": "Set Search Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        -752,
        16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "kw1",
              "name": "keyword",
              "type": "string",
              "value": "Digital Marketing Manager"
            },
            {
              "id": "loc1",
              "name": "location",
              "type": "string",
              "value": "Lahore, Pakistan"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "37cb6fac-27e3-432b-90a5-b0b7e1a00205",
      "name": "Build Search URLs",
      "type": "n8n-nodes-base.code",
      "position": [
        -544,
        16
      ],
      "parameters": {
        "jsCode": "const keyword = encodeURIComponent($json.keyword);\nconst location = encodeURIComponent($json.location);\n\nconst linkedinUrl = `https://www.linkedin.com/jobs/search/?keywords=${keyword}&location=${location}`;\nconst indeedUrl = `https://www.indeed.com/jobs?q=${keyword}&l=${location}`;\n\nreturn [\n  { json: { source: 'linkedin', url: linkedinUrl, keyword: $json.keyword, location: $json.location } },\n  { json: { source: 'indeed', url: indeedUrl, keyword: $json.keyword, location: $json.location } }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "51b8d0b1-58ee-4390-875d-e7d4bf128b99",
      "name": "IF Source = LinkedIn",
      "type": "n8n-nodes-base.if",
      "position": [
        -320,
        16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.source }}",
              "rightValue": "linkedin"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "737fa0e0-41b1-4d66-95a6-985fb3883156",
      "name": "ScrapeUnblocker",
      "type": "n8n-nodes-scrapeunblocker.scrapeUnblocker",
      "position": [
        0,
        0
      ],
      "parameters": {
        "url": "={{ $json.url }}"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "ed9c6cfc-5bb6-438a-ba03-15fa04c686d9",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        208,
        0
      ],
      "parameters": {
        "jsCode": "// Robustly find the HTML string wherever it lives in the input item\nfunction findHtml(value) {\n  if (typeof value === 'string' && value.includes('<html')) {\n    return value;\n  }\n  if (Array.isArray(value)) {\n    for (const v of value) {\n      const found = findHtml(v);\n      if (found) return found;\n    }\n  }\n  if (value && typeof value === 'object') {\n    for (const key of Object.keys(value)) {\n      const found = findHtml(value[key]);\n      if (found) return found;\n    }\n  }\n  return null;\n}\n\nconst html = findHtml($json);\n\nif (!html) {\n  throw new Error('No HTML found in input. Input structure: ' + JSON.stringify($json).slice(0, 200));\n}\n\nconst jobs = [];\n\nconst cardRegex = /<div[^>]*data-entity-urn=\"urn:li:jobPosting:(\\d+)\"[\\s\\S]*?<\\/div>\\s*<\\/li>/g;\nlet cardMatch;\n\nwhile ((cardMatch = cardRegex.exec(html)) !== null) {\n  const block = cardMatch[0];\n  const jobId = cardMatch[1];\n\n  const urlMatch = block.match(/class=\"base-card__full-link[^\"]*\"[^>]*href=\"([^\"]+)\"/);\n  const titleMatch = block.match(/class=\"base-search-card__title\">\\s*([^<]+)/);\n  const companyMatch = block.match(/class=\"base-search-card__subtitle\">[\\s\\S]*?<a[^>]*>\\s*([^<]+)/);\n  const locationMatch = block.match(/class=\"job-search-card__location\">\\s*([^<]+)/);\n  const dateMatch = block.match(/class=\"job-search-card__listdate\"[^>]*datetime=\"([^\"]+)\"/);\n\n  jobs.push({\n    jobId: jobId,\n    title: titleMatch ? titleMatch[1].trim() : null,\n    company: companyMatch ? companyMatch[1].trim() : null,\n    location: locationMatch ? locationMatch[1].trim() : null,\n    postDate: dateMatch ? dateMatch[1].trim() : null,\n    url: urlMatch ? urlMatch[1].replace(/&amp;/g, '&').split('?')[0] : null,\n    source: 'LinkedIn',\n    dateScraped: new Date().toISOString()\n  });\n}\n\nconst seen = new Set();\nconst deduped = jobs.filter(j => {\n  if (seen.has(j.jobId)) return false;\n  seen.add(j.jobId);\n  return true;\n});\n\nreturn deduped.map(job => ({ json: job }));"
      },
      "typeVersion": 2
    },
    {
      "id": "8a1f4805-3e44-44bd-8e09-d94a002835c5",
      "name": "Append row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        416,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $json.url }}",
            "Title": "={{ $json.title }}",
            "Job ID": "={{ $json.jobId }}",
            "Source": "={{ $json.source }}",
            "Company": "={{ $json.company }}",
            "Location": "={{ $json.location }}",
            "Post Date": "={{ $json.postDate }}",
            "Date Scraped": "={{ $json.dateScraped }}"
          },
          "schema": [
            {
              "id": "Job ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Job ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Company",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Company",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Post Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Post Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date Scraped",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date Scraped",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K1CvGzVGOGpSfY6rAknO3XCyZ-hqr6KYH4ZKkiZpySM/edit#gid=0",
          "cachedResultName": "jobs"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1K1CvGzVGOGpSfY6rAknO3XCyZ-hqr6KYH4ZKkiZpySM",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K1CvGzVGOGpSfY6rAknO3XCyZ-hqr6KYH4ZKkiZpySM/edit?usp=drivesdk",
          "cachedResultName": "Job Board Aggregator"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c13b1a67-2ce5-411b-a321-da392de89e7c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1728,
        -304
      ],
      "parameters": {
        "width": 592,
        "height": 720,
        "content": "## Automated LinkedIn Job Board Scraper\n\n### How It Works\n* **Schedule & Input:** Runs every 8 hours, taking target search parameters (`keyword` & `location`).\n* **URL Building & Filtering:** Generates encoded search URLs for job platforms (LinkedIn/Indeed) and routes LinkedIn searches downstream via an IF condition.\n* **Scraping:** Fetches search results HTML using **ScrapeUnblocker** to bypass anti-bot protections.\n\n\n### Quick Setup Checklist\n1. **ScrapeUnblocker:** Authenticate active credentials.\n2. **Google Sheets:** Link credentials and verify target spreadsheet (`Job Board Aggregator`), sheet tab (`jobs`), and column mapping.\n\n### Customization\n* **Job Board Routing:** Expand `Build Search URLs` and add branches to `IF Source = LinkedIn` to scrape Indeed or other platforms.\n* **Regex Parsing:** Update card regex patterns inside `Code in JavaScript` if LinkedIn alters card containers or `data-entity-urn` tags."
      },
      "typeVersion": 1
    },
    {
      "id": "99db11e9-00fd-4233-aa99-7e0ffeecb6b0",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1056,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 384,
        "content": "## 1. Schedule Trigger & Search URL Generation\nTriggers the workflow every 8 hours, sets target search variables, builds encoded URLs for job sites, and routes LinkedIn tasks."
      },
      "typeVersion": 1
    },
    {
      "id": "30440fee-7ac7-4444-80d8-c1f66e2c3d7a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 976,
        "height": 384,
        "content": "## 2. Scraping, Regex Parsing & Google Sheets Export\nFetches target page HTML via ScrapeUnblocker, parses job card details, deduplicates by Job ID, and appends listings to Google Sheets."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "15eb6764-3079-4cd3-9cc4-5d30108947dd",
  "nodeGroups": [],
  "connections": {
    "ScrapeUnblocker": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set Search Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Search URLs": {
      "main": [
        [
          {
            "node": "IF Source = LinkedIn",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF Source = LinkedIn": {
      "main": [
        [
          {
            "node": "ScrapeUnblocker",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Search Variables": {
      "main": [
        [
          {
            "node": "Build Search URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow runs every 8 hours to scrape LinkedIn job search results for a chosen keyword and location using ScrapeUnblocker, then parses job details and appends them to a Google Sheets spreadsheet. Runs every 8 hours on a schedule. Sets the job search keyword and location,…

Source: https://n8n.io/workflows/17397/ — original creator credit. Request a take-down →

More Social Media workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Social Media

Automate your LinkedIn outreach with this n8n workflow powered by Linked API. Sends connection requests, monitors acceptance, delivers your pre-written messages, and follows up automatically – all tra

Google Sheets, N8N Nodes Linked Api
Social Media

This template is ideal for sales teams, recruiters, business development professionals, and relationship managers who need to monitor changes in their network's LinkedIn profiles. Perfect for agencies

Google Sheets, HTTP Request, Slack
Social Media

This workflow runs daily and reads a Google Sheets content calendar to auto-publish scheduled posts to Instagram and Facebook via the Meta Graph API, then posts the same content to LinkedIn and update

Google Sheets, HTTP Request, LinkedIn
Social Media

Save time - Eliminate manual LinkedIn posting and content scheduling tasks Stay consistent - Automated daily posting keeps your LinkedIn profile active and engaging Keep control - Preview every post b

HTTP Request, Telegram, Google Sheets +2
Social Media

Louis LinkedIn Automation OS. Uses googleSheets. Scheduled trigger; 24 nodes.

Google Sheets