Trouver un travail via un bot Telegram : un scrapeur AI pour LinkedIn, Indeed et Monster
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
- •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
Nœuds utilisés (15)
Catégorie
{
"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
}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.
Workflows recommandés
n8n Automation Expert | Template Creator | 2+ Years Experience
@tegarkaruniailhamHelping 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!"
Partager ce workflow