通过 Telegram 机器人找工作:AI 驱动的 LinkedIn、Indeed 和 Monster 抓取器
这是一个Miscellaneous、AI Chatbot、Multimodal AI领域的自动化工作流,包含 15 个节点。主要使用 Code、Filter、Airtable、Telegram、HttpRequest 等节点。 基于 AI 的 Telegram 机器人,抓取 LinkedIn、Indeed 和 Monster 职位信息
- •Airtable API Key
- •Telegram Bot Token
- •可能需要目标 API 的认证凭证
- •Google Sheets API 凭证
{
"meta": {
"version": "2.0",
"instanceId": "workflow_job_scraper_telegram"
},
"tags": [
"telegram",
"job-scraping",
"sales",
"marketing",
"automation",
"ai"
],
"nodes": [
{
"id": "telegram_trigger",
"name": "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": "命令过滤器",
"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": "工作搜索过滤器",
"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": "发送欢迎消息",
"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": "解析工作命令",
"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": "发送搜索状态",
"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": "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": "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": "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": "为 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": "格式化工作消息",
"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": "发送工作结果",
"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": "保存到 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": "保存到 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": "记录使用分析",
"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": {
"Command Filter": {
"main": [
[
{
"node": "Send Welcome Message",
"type": "main",
"index": 0
}
]
]
},
"Job Search Filter": {
"main": [
[
{
"node": "Parse Job Command",
"type": "main",
"index": 0
}
]
]
},
"Parse Job Command": {
"main": [
[
{
"node": "Send Search Status",
"type": "main",
"index": 0
}
]
]
},
"Send Search Status": {
"main": [
[
{
"node": "LinkedIn Jobs Scraper",
"type": "main",
"index": 0
},
{
"node": "Indeed Jobs Scraper",
"type": "main",
"index": 0
},
{
"node": "Monster Jobs Scraper",
"type": "main",
"index": 0
}
]
]
},
"Format Jobs Message": {
"main": [
[
{
"node": "Send Job Results",
"type": "main",
"index": 0
},
{
"node": "Log Usage Analytics",
"type": "main",
"index": 0
}
]
]
},
"Indeed Jobs Scraper": {
"main": [
[
{
"node": "Process Jobs for Telegram",
"type": "main",
"index": 0
}
]
]
},
"Monster Jobs Scraper": {
"main": [
[
{
"node": "Process Jobs for Telegram",
"type": "main",
"index": 0
}
]
]
},
"Telegram Bot Trigger": {
"main": [
[
{
"node": "Command Filter",
"type": "main",
"index": 0
},
{
"node": "Job Search Filter",
"type": "main",
"index": 0
}
]
]
},
"LinkedIn Jobs Scraper": {
"main": [
[
{
"node": "Process Jobs for Telegram",
"type": "main",
"index": 0
}
]
]
},
"Process Jobs for Telegram": {
"main": [
[
{
"node": "Format Jobs Message",
"type": "main",
"index": 0
},
{
"node": "Save to Google Sheets",
"type": "main",
"index": 0
},
{
"node": "Save to Airtable",
"type": "main",
"index": 0
}
]
]
}
},
"triggerCount": 1
}如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
这是一个中级难度的工作流,适用于Miscellaneous、AI Chatbot、Multimodal AI等场景。适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
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!"
分享此工作流