{
  "id": "RcWm1VlQCiJ2MMOB",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Automated Job Finder Agent with Scrapeless and Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "b5953186-c060-4aac-b22a-4b9025839b66",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        660,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "36da4916-543d-4569-bd02-a7518df18fd4",
      "name": "Scrapeless",
      "type": "n8n-nodes-scrapeless.scrapeless",
      "position": [
        880,
        0
      ],
      "parameters": {
        "url": "https://www.ycombinator.com/jobs",
        "resource": "crawler",
        "operation": "crawl",
        "limitCrawlPages": 2
      },
      "credentials": {
        "scrapelessApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "19c3e8cc-c94b-4fa5-b307-32c3b5ac51a1",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        360,
        240
      ],
      "parameters": {
        "jsCode": "\nconst raw = items[0].json;             \n\nconst output = raw.map(obj => ({\n  json: {\n \n    markdown: obj.markdown,\n\n  }\n}));\n\n\nreturn output;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a217d476-3bd6-4b2e-9bac-42a896c4c093",
      "name": "Code1",
      "type": "n8n-nodes-base.code",
      "position": [
        660,
        240
      ],
      "parameters": {
        "jsCode": "return items.map(item => {\n  const md = item.json.markdown;\n\n  // 1. Find the \u201cjobs added recently\u201d header line dynamically (case\u2011insensitive)\n  const splitRegex = /^#{1,3}\\s*.+jobs added recently\\s*$/im;\n  // Split into [introSection, jobsSection]\n  const parts = md.split(splitRegex);\n  const introSectionRaw = parts[0] || '';\n  const jobsSectionRaw = parts.slice(1).join('') || '';\n\n  // 2. Clean up the intro text\n  const intro = introSectionRaw\n    .replace(/^#+\\s*/gm, '') // strip any leading \u201c#\u201d headings\n    .trim();\n\n  // 3. Extract each job title + link (ignore image\u2011only links)\n  const jobs = [];\n  const re = /\\-\\s*\\[(?!\\!)([^\\]]+)\\]\\((https?:\\/\\/[^\\)]+)\\)/g;\n  let match;\n  while ((match = re.exec(jobsSectionRaw))) {\n    jobs.push({\n      title: match[1].trim(),\n      link:  match[2].trim(),\n    });\n  }\n\n  // 4. Return a new item\n  return {\n    json: {\n      intro,\n      jobs,\n    },\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "1152e225-f480-4ccd-8f97-d4eced0aa24c",
      "name": "Code2",
      "type": "n8n-nodes-base.code",
      "position": [
        920,
        240
      ],
      "parameters": {
        "jsCode": "const output = [];\n\nitems.forEach(item => {\n  const intro = item.json.intro;\n  const jobs  = item.json.jobs || [];\n\n  jobs.forEach(job => {\n    output.push({\n      json: {\n        intro,             \n        jobTitle: job.title,\n        jobLink:  job.link\n      }\n    });\n  });\n});\n\nreturn output;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f45298a1-65bd-41a7-bad3-997024ebb08e",
      "name": "Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        700,
        460
      ],
      "parameters": {
        "columns": {
          "value": {
            "Job Link": "={{ $json.jobLink }}",
            "Job Title": "={{ $json.jobTitle }}"
          },
          "schema": [
            {
              "id": "Job Title",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Job Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Job Link",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Job Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Job Title"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FjjJjC-f6KqNLyVPgCTGusQs-e1cL-qCTD-7aCbI5-w/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1FjjJjC-f6KqNLyVPgCTGusQs-e1cL-qCTD-7aCbI5-w",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FjjJjC-f6KqNLyVPgCTGusQs-e1cL-qCTD-7aCbI5-w/edit?usp=drivesdk",
          "cachedResultName": "Job Info"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "4bd91f22-f338-4f5c-bf27-f63f58de3363",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 4,
        "width": 620,
        "height": 120,
        "content": "##  Automated Job Scraper (Every 6 Hours)\n\u23f0 Schedule Trigger: Runs every 6 hours to fetch fresh data.\n\ud83d\udd78\ufe0f Crawl Step: Scrapes job listings from a specific website using Scrapeless."
      },
      "typeVersion": 1
    },
    {
      "id": "46375003-a127-4441-834f-261e7978c263",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1080,
        240
      ],
      "parameters": {
        "color": 6,
        "width": 580,
        "height": 120,
        "content": "## Data Cleaning & Labeling Functions\nThese functions clean the raw job data and assign appropriate labels  based on keywords and patterns."
      },
      "typeVersion": 1
    },
    {
      "id": "664c7215-bb23-43be-9c0a-648787c8d4c7",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        140,
        460
      ],
      "parameters": {
        "color": 5,
        "width": 500,
        "height": 120,
        "content": "## Save to Google Sheets\nAfter cleaning and labeling, the final structured job data is stored in Google Sheets for easy access and analysis.\n\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e4fe8bcd-ace3-4e61-9f3c-57220ecb6b06",
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "Code2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code2": {
      "main": [
        [
          {
            "node": "Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrapeless": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Scrapeless",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}