Busca trabajo a través de un bot de Telegram: un scraper impulsado por AI para LinkedIn, Indeed y Monster
Este es unMiscellaneous, AI Chatbot, Multimodal AIflujo de automatización del dominio deautomatización que contiene 15 nodos.Utiliza principalmente nodos como Code, Filter, Airtable, Telegram, HttpRequest. Un bot de Telegram basado en IA para extraer información de trabajos de LinkedIn, Indeed y Monster
- •Clave de API de Airtable
- •Bot Token de Telegram
- •Pueden requerirse credenciales de autenticación para la API de destino
- •Credenciales de API de Google Sheets
Nodos utilizados (15)
Categoría
{
"meta": {
"version": "2.0",
"instanceId": "workflow_job_scraper_telegram"
},
"tags": [
"telegram",
"job-scraping",
"sales",
"marketing",
"automation",
"ai"
],
"nodes": [
{
"id": "telegram_trigger",
"name": "Activador del 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": "Filtro de Comandos",
"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": "Filtro de Búsqueda de Empleo",
"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": "Enviar Mensaje de Bienvenida",
"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": "Analizar Comando de Empleo",
"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": "Enviar Estado de Búsqueda",
"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": "Rastreador de Empleos 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": "Rastreador de Empleos 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": "Rastreador de Empleos 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": "Procesar Empleos para 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": "Formatear Mensaje de Empleos",
"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": "Enviar Resultados de Empleo",
"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": "Guardar en Hojas Google",
"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": "Guardar en 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": "Registrar Analíticas de Uso",
"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
}¿Cómo usar este flujo de trabajo?
Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.
¿En qué escenarios es adecuado este flujo de trabajo?
Intermedio - Varios, Chatbot de IA, IA Multimodal
¿Es de pago?
Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.
Flujos de trabajo relacionados recomendados
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!"
Compartir este flujo de trabajo