Trouver un travail via un bot Telegram : un scrapeur AI pour LinkedIn, Indeed et Monster

Intermédiaire

Ceci est unMiscellaneous, AI Chatbot, Multimodal AIworkflow d'automatisation du domainecontenant 15 nœuds.Utilise principalement des nœuds comme Code, Filter, Airtable, Telegram, HttpRequest. Robot Telegram basé sur l'IA pour scraper les offres d'emploi LinkedIn, Indeed et Monster

Prérequis
  • Clé API Airtable
  • Token Bot Telegram
  • Peut nécessiter les informations d'identification d'authentification de l'API cible
  • Informations d'identification Google Sheets API
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "meta": {
    "version": "2.0",
    "instanceId": "workflow_job_scraper_telegram"
  },
  "tags": [
    "telegram",
    "job-scraping",
    "sales",
    "marketing",
    "automation",
    "ai"
  ],
  "nodes": [
    {
      "id": "telegram_trigger",
      "name": "Déclencheur du bot Telegram",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        260,
        200
      ],
      "parameters": {
        "updates": [
          "message"
        ]
      },
      "credentials": {
        "telegramApi": {
          "id": "telegram_bot_credentials",
          "name": "Job Scraper Bot"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "telegram_command_filter",
      "name": "Filtre de commande",
      "type": "n8n-nodes-base.filter",
      "position": [
        480,
        200
      ],
      "parameters": {
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{$json.message.text}}",
              "rightValue": "/start"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "job_search_filter",
      "name": "Filtre de recherche d'emploi",
      "type": "n8n-nodes-base.filter",
      "position": [
        480,
        350
      ],
      "parameters": {
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "startsWith"
              },
              "leftValue": "={{$json.message.text}}",
              "rightValue": "/jobs"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "welcome_message",
      "name": "Envoyer le message de bienvenue",
      "type": "n8n-nodes-base.telegram",
      "position": [
        700,
        200
      ],
      "parameters": {
        "text": "🤖 **Job Scraper Bot Activated!** 🚀\n\n*Welcome to your personal job hunting assistant!*\n\n**Available Commands:**\n/jobs [keyword] [location] - Search for jobs\n/status - Check bot status\n/help - Show this help\n\n**Examples:**\n• `/jobs sales manager New York`\n• `/jobs marketing remote`\n• `/jobs developer San Francisco`\n\n*Let me find the perfect job opportunities for you!* 💼",
        "chatId": "={{$json.message.chat.id}}",
        "resource": "message",
        "operation": "sendMessage",
        "parseMode": "Markdown"
      },
      "credentials": {
        "telegramApi": {
          "id": "telegram_bot_credentials",
          "name": "Job Scraper Bot"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "parse_job_command",
      "name": "Analyser la commande d'emploi",
      "type": "n8n-nodes-base.code",
      "position": [
        700,
        350
      ],
      "parameters": {
        "jsCode": "// Parse Telegram job search command\nconst message = $input.first().json.message;\nconst text = message.text;\nconst chatId = message.chat.id;\nconst userId = message.from.id;\nconst userName = message.from.first_name || 'User';\n\n// Parse command: /jobs [keyword] [location]\nconst parts = text.split(' ');\nlet keyword = 'sales marketing';\nlet location = 'New York';\n\nif (parts.length >= 2) {\n  keyword = parts.slice(1, -1).join(' ') || 'sales marketing';\n  location = parts[parts.length - 1] || 'New York';\n}\n\n// If only one parameter, treat as keyword\nif (parts.length === 2) {\n  keyword = parts[1];\n  location = 'New York';\n}\n\n// Create search parameters\nconst searchParams = {\n  keyword: keyword,\n  location: location,\n  chatId: chatId,\n  userId: userId,\n  userName: userName,\n  timestamp: new Date().toISOString()\n};\n\nreturn [{\n  json: {\n    ...searchParams,\n    originalMessage: message,\n    searchQuery: `${keyword} in ${location}`\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "search_status_message",
      "name": "Envoyer le statut de la recherche",
      "type": "n8n-nodes-base.telegram",
      "position": [
        920,
        350
      ],
      "parameters": {
        "text": "🔍 **Searching for Jobs...**\n\n*Keyword:* `{{$json.keyword}}`\n*Location:* `{{$json.location}}`\n\n*Please wait while I scan LinkedIn, Indeed, and Monster for the best opportunities...* ⏳",
        "chatId": "={{$json.chatId}}",
        "resource": "message",
        "operation": "sendMessage",
        "parseMode": "Markdown"
      },
      "credentials": {
        "telegramApi": {
          "id": "telegram_bot_credentials",
          "name": "Job Scraper Bot"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "linkedin_scraper_telegram",
      "name": "Collecteur d'emplois LinkedIn",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1140,
        250
      ],
      "parameters": {
        "url": "https://api.brightdata.com/datasets/v3/trigger",
        "method": "POST",
        "options": {
          "retry": {
            "enabled": true,
            "maxTries": 3,
            "waitBetween": 2000
          },
          "timeout": 30000
        },
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "dataset_id",
              "value": "gd_lpfbbndm1xnopbrcr0"
            },
            {
              "name": "country",
              "value": "US"
            },
            {
              "name": "keyword",
              "value": "={{$json.keyword}}"
            },
            {
              "name": "location",
              "value": "={{$json.location}}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "indeed_scraper_telegram",
      "name": "Collecteur d'emplois Indeed",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1140,
        350
      ],
      "parameters": {
        "url": "https://api.brightdata.com/datasets/v3/trigger",
        "method": "POST",
        "options": {
          "retry": {
            "enabled": true,
            "maxTries": 3,
            "waitBetween": 2000
          },
          "timeout": 30000
        },
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "dataset_id",
              "value": "gd_l4dx9j9sscpvs7no2"
            },
            {
              "name": "what",
              "value": "={{$json.keyword}}"
            },
            {
              "name": "where",
              "value": "={{$json.location}}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "monster_scraper_telegram",
      "name": "Collecteur d'emplois Monster",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1140,
        450
      ],
      "parameters": {
        "url": "https://api.monster.com/job-search/v2/search",
        "method": "GET",
        "options": {
          "retry": {
            "enabled": true,
            "maxTries": 3,
            "waitBetween": 2000
          },
          "timeout": 30000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{$json.keyword}}"
            },
            {
              "name": "where",
              "value": "={{$json.location}}"
            },
            {
              "name": "page",
              "value": "1"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "telegram_job_processor",
      "name": "Traiter les emplois pour Telegram",
      "type": "n8n-nodes-base.code",
      "position": [
        1360,
        350
      ],
      "parameters": {
        "jsCode": "// Enhanced job processing with Telegram context\nconst items = $input.all();\nconst processedJobs = [];\nlet chatId, userName, searchQuery;\n\n// Get Telegram context from first item\nif (items.length > 0 && items[0].json.chatId) {\n  chatId = items[0].json.chatId;\n  userName = items[0].json.userName || 'User';\n  searchQuery = items[0].json.searchQuery || 'jobs';\n}\n\nfor (const item of items) {\n  const source = item.json;\n  \n  // Skip items that are just telegram context\n  if (source.chatId && !source.company_name && !source.jobkey && !source.jobId) {\n    continue;\n  }\n  \n  // Determine source platform\n  let platform = 'unknown';\n  if (source.company_name || source.job_title) {\n    platform = 'linkedin';\n  } else if (source.jobkey || source.jobtitle) {\n    platform = 'indeed';\n  } else if (source.jobId) {\n    platform = 'monster';\n  }\n  \n  // Standardize job data structure\n  const standardizedJob = {\n    platform: platform,\n    job_id: source.job_id || source.jobkey || source.jobId || '',\n    title: source.job_title || source.jobtitle || source.title || '',\n    company: source.company_name || source.company || source.companyName || '',\n    location: source.location || source.formattedLocation || '',\n    description: source.description || source.snippet || '',\n    salary: source.salary || source.salary_formatted || '',\n    url: source.url || source.link || '',\n    posted_date: source.date_posted || source.date || source.postDate || '',\n    scraped_at: new Date().toISOString(),\n    // Telegram context\n    telegram_chat_id: chatId,\n    telegram_user: userName,\n    search_query: searchQuery,\n    // Enhanced filtering\n    is_relevant: checkRelevance(source.job_title || source.title || '', source.description || source.snippet || ''),\n    experience_level: extractExperience(source.description || source.snippet || ''),\n    remote_option: checkRemote(source.description || source.snippet || ''),\n    salary_range: extractSalary(source.salary || source.salary_formatted || '')\n  };\n  \n  processedJobs.push({ json: standardizedJob });\n}\n\n// Filter and deduplicate\nconst filteredJobs = processedJobs.filter(job => job.json.is_relevant);\nconst uniqueJobs = [];\nconst seen = new Set();\n\nfor (const job of filteredJobs) {\n  const key = `${job.json.title}-${job.json.company}`.toLowerCase().replace(/[^a-z0-9]/g, '');\n  if (!seen.has(key) && uniqueJobs.length < 10) { // Limit to 10 jobs for Telegram\n    seen.add(key);\n    uniqueJobs.push(job);\n  }\n}\n\n// Add summary statistics\nif (uniqueJobs.length > 0 && chatId) {\n  const summary = {\n    json: {\n      telegram_chat_id: chatId,\n      telegram_user: userName,\n      search_query: searchQuery,\n      total_jobs_found: uniqueJobs.length,\n      platforms_searched: [...new Set(uniqueJobs.map(job => job.json.platform))],\n      remote_jobs: uniqueJobs.filter(job => job.json.remote_option).length,\n      search_timestamp: new Date().toISOString(),\n      is_summary: true\n    }\n  };\n  uniqueJobs.unshift(summary);\n}\n\nfunction checkRelevance(title, description) {\n  const text = (title + ' ' + description).toLowerCase();\n  const keywords = ['sales', 'marketing', 'business development', 'account manager', 'digital marketing', \n                   'marketing manager', 'sales representative', 'business analyst', 'account executive'];\n  return keywords.some(keyword => text.includes(keyword));\n}\n\nfunction extractExperience(description) {\n  const senior_keywords = ['senior', '5+ years', 'lead', 'principal', 'director'];\n  const entry_keywords = ['entry level', '0-2 years', 'junior', 'associate'];\n  const text = description.toLowerCase();\n  \n  if (senior_keywords.some(keyword => text.includes(keyword))) return 'senior';\n  if (entry_keywords.some(keyword => text.includes(keyword))) return 'entry';\n  return 'mid';\n}\n\nfunction checkRemote(description) {\n  return description.toLowerCase().includes('remote') || \n         description.toLowerCase().includes('work from home') ||\n         description.toLowerCase().includes('telecommute');\n}\n\nfunction extractSalary(salary) {\n  if (!salary) return 'Not specified';\n  // Clean and format salary information\n  return salary.replace(/[^0-9$,k-]/gi, '').substring(0, 50);\n}\n\nreturn uniqueJobs;"
      },
      "typeVersion": 2
    },
    {
      "id": "format_telegram_message",
      "name": "Formater le message d'emplois",
      "type": "n8n-nodes-base.code",
      "position": [
        1580,
        350
      ],
      "parameters": {
        "jsCode": "// Format jobs for Telegram message\nconst items = $input.all();\nlet chatId, userName, summary;\nconst jobs = [];\n\n// Separate summary from jobs\nfor (const item of items) {\n  if (item.json.is_summary) {\n    summary = item.json;\n    chatId = item.json.telegram_chat_id;\n    userName = item.json.telegram_user;\n  } else {\n    jobs.push(item.json);\n  }\n}\n\nif (jobs.length === 0) {\n  return [{\n    json: {\n      telegram_chat_id: chatId,\n      telegram_message: `😞 **No Jobs Found**\\n\\n*Sorry ${userName}, I couldn't find any relevant job opportunities for your search.*\\n\\n*Try different keywords or locations!*`,\n      has_jobs: false\n    }\n  }];\n}\n\n// Create formatted message\nlet message = `🎯 **Job Search Results** 🎯\\n\\n`;\nmessage += `*Found ${summary.total_jobs_found} relevant opportunities*\\n`;\nmessage += `*Platforms: ${summary.platforms_searched.join(', ')}*\\n`;\nmessage += `*Remote jobs: ${summary.remote_jobs}*\\n\\n`;\nmessage += `───────────────────\\n\\n`;\n\n// Format individual jobs\nfor (let i = 0; i < Math.min(jobs.length, 5); i++) {\n  const job = jobs[i];\n  const platformIcon = {\n    'linkedin': '💼',\n    'indeed': '🔍', \n    'monster': '👹'\n  }[job.platform] || '💼';\n  \n  message += `${platformIcon} **${job.title}**\\n`;\n  message += `🏢 *${job.company}*\\n`;\n  message += `📍 ${job.location}\\n`;\n  \n  if (job.salary_range && job.salary_range !== 'Not specified') {\n    message += `💰 ${job.salary_range}\\n`;\n  }\n  \n  if (job.remote_option) {\n    message += `🌐 *Remote Available*\\n`;\n  }\n  \n  message += `📊 *${job.experience_level} level*\\n`;\n  \n  if (job.url) {\n    message += `🔗 [Apply Now](${job.url})\\n`;\n  }\n  \n  message += `\\n───────────────────\\n\\n`;\n}\n\nif (jobs.length > 5) {\n  message += `*... and ${jobs.length - 5} more jobs available!*\\n\\n`;\n}\n\nmessage += `⚡ *Use /jobs [keyword] [location] for new search*\\n`;\nmessage += `💾 *Jobs saved to Google Sheets & Airtable*`;\n\nreturn [{\n  json: {\n    telegram_chat_id: chatId,\n    telegram_message: message,\n    has_jobs: true,\n    job_count: jobs.length,\n    formatted_jobs: jobs.slice(0, 5)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "send_job_results",
      "name": "Envoyer les résultats d'emploi",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1800,
        350
      ],
      "parameters": {
        "text": "={{$json.telegram_message}}",
        "chatId": "={{$json.telegram_chat_id}}",
        "options": {
          "disable_web_page_preview": true
        },
        "resource": "message",
        "operation": "sendMessage",
        "parseMode": "Markdown"
      },
      "credentials": {
        "telegramApi": {
          "id": "telegram_bot_credentials",
          "name": "Job Scraper Bot"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "telegram_google_sheets",
      "name": "Sauvegarder dans Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1580,
        500
      ],
      "parameters": {
        "options": {
          "useAppend": true
        },
        "operation": "appendOrUpdate",
        "sheetName": "Telegram_Jobs",
        "documentId": "your_google_sheet_id",
        "authentication": "oAuth2",
        "columnToMatchOn": "job_id"
      },
      "typeVersion": 4
    },
    {
      "id": "telegram_airtable",
      "name": "Sauvegarder dans Airtable",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1580,
        600
      ],
      "parameters": {
        "baseId": "your_airtable_base_id",
        "options": {
          "bulkSize": 10,
          "ignoreMissingColumns": true
        },
        "tableId": "telegram_jobs_table",
        "operation": "create",
        "authentication": "airtableTokenApi"
      },
      "typeVersion": 2
    },
    {
      "id": "usage_analytics",
      "name": "Journaliser les analyses d'utilisation",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1800,
        500
      ],
      "parameters": {
        "url": "https://hooks.zapier.com/hooks/catch/YOUR_WEBHOOK_ID/",
        "method": "POST",
        "options": {
          "timeout": 10000
        },
        "jsonBody": "={{ {\n  \"user_id\": $json.telegram_user,\n  \"chat_id\": $json.telegram_chat_id,\n  \"search_query\": $json.search_query,\n  \"jobs_found\": $json.job_count,\n  \"timestamp\": $json.search_timestamp,\n  \"platform\": \"telegram\",\n  \"workflow\": \"job_search\"\n} }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.1
    }
  ],
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "saveManualExecutions": true
  },
  "updatedAt": "2025-09-05T11:41:00.000Z",
  "versionId": "2",
  "staticData": {},
  "connections": {
    "telegram_command_filter": {
      "main": [
        [
          {
            "node": "welcome_message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "job_search_filter": {
      "main": [
        [
          {
            "node": "parse_job_command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "parse_job_command": {
      "main": [
        [
          {
            "node": "search_status_message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "search_status_message": {
      "main": [
        [
          {
            "node": "linkedin_scraper_telegram",
            "type": "main",
            "index": 0
          },
          {
            "node": "indeed_scraper_telegram",
            "type": "main",
            "index": 0
          },
          {
            "node": "monster_scraper_telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "format_telegram_message": {
      "main": [
        [
          {
            "node": "send_job_results",
            "type": "main",
            "index": 0
          },
          {
            "node": "usage_analytics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "indeed_scraper_telegram": {
      "main": [
        [
          {
            "node": "telegram_job_processor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "monster_scraper_telegram": {
      "main": [
        [
          {
            "node": "telegram_job_processor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "telegram_trigger": {
      "main": [
        [
          {
            "node": "telegram_command_filter",
            "type": "main",
            "index": 0
          },
          {
            "node": "job_search_filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "linkedin_scraper_telegram": {
      "main": [
        [
          {
            "node": "telegram_job_processor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "telegram_job_processor": {
      "main": [
        [
          {
            "node": "format_telegram_message",
            "type": "main",
            "index": 0
          },
          {
            "node": "telegram_google_sheets",
            "type": "main",
            "index": 0
          },
          {
            "node": "telegram_airtable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "triggerCount": 1
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Intermédiaire - Divers, Chatbot IA, IA Multimodale

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Informations sur le workflow
Niveau de difficulté
Intermédiaire
Nombre de nœuds15
Catégorie3
Types de nœuds7
Description de la difficulté

Adapté aux utilisateurs expérimentés, avec des workflows de complexité moyenne contenant 6-15 nœuds

Auteur
n8n Automation Expert | Template Creator | 2+ Years Experience

n8n Automation Expert | Template Creator | 2+ Years Experience

@tegarkaruniailham

Helping business owners & marketers automate their processes with n8n. Specialist in custom workflows, API integrations, and template development. 📈 100+ successful automation projects 🔧 Premium n8n templates available 💡 Free consultation for custom automation Book a consultation for your business digital transformation!"

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34