实时竞争性建筑监控
这是一个Market Research领域的自动化工作流,包含 13 个节点。主要使用 If, Code, Wait, EmailSend, HttpRequest 等节点。 带电子邮件通知和数据API的自动化建筑项目警报
- •可能需要目标 API 的认证凭证
分类
{
"id": "tAZrn9nO8QUWfGQx",
"meta": {
"instanceId": "dd69efaf8212c74ad206700d104739d3329588a6f3f8381a46a481f34c9cc281",
"templateCredsSetupCompleted": true
},
"name": "实时竞争性建筑监控",
"tags": [],
"nodes": [
{
"id": "878dbf6e-dc80-457d-b212-03e98c69042f",
"name": "计划触发器",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
0
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.1
},
{
"id": "bba4ec2c-854e-4c51-ba14-f19ab0af919c",
"name": "邮件触发器",
"type": "n8n-nodes-base.emailReadImap",
"position": [
0,
180
],
"parameters": {
"options": {}
},
"credentials": {
"imap": {
"id": "zTEGYssr7MSVeCs3",
"name": "IMAP-test"
}
},
"typeVersion": 2
},
{
"id": "46fdbb5a-478a-488d-ba1f-c752f1d708b9",
"name": "检查邮件主题",
"type": "n8n-nodes-base.if",
"position": [
220,
180
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "condition1",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "Construction Alert Request"
}
]
}
},
"typeVersion": 2
},
{
"id": "af98d975-c83d-4cf6-b060-a33f8c5d3211",
"name": "提取位置信息",
"type": "n8n-nodes-base.code",
"position": [
440,
80
],
"parameters": {
"jsCode": "// Extract area/location from email body\nconst emailBody = $input.first().json.text || $input.first().json.html;\nconst lines = emailBody.split('\\n');\n\nlet area = '';\nlet city = '';\nlet state = '';\nlet zipcode = '';\n\n// Look for area information in email\nfor (const line of lines) {\n if (line.toLowerCase().includes('area:') || line.toLowerCase().includes('location:')) {\n area = line.split(':')[1]?.trim() || '';\n }\n if (line.toLowerCase().includes('city:')) {\n city = line.split(':')[1]?.trim() || '';\n }\n if (line.toLowerCase().includes('state:')) {\n state = line.split(':')[1]?.trim() || '';\n }\n if (line.toLowerCase().includes('zip:') || line.toLowerCase().includes('zipcode:')) {\n zipcode = line.split(':')[1]?.trim() || '';\n }\n}\n\n// If no structured data found, try to extract from general text\nif (!area && !city) {\n const addressRegex = /([A-Za-z\\s]+),\\s*([A-Z]{2})\\s*(\\d{5})?/;\n const match = emailBody.match(addressRegex);\n if (match) {\n city = match[1];\n state = match[2];\n zipcode = match[3] || '';\n }\n}\n\nreturn {\n json: {\n searchArea: area || city,\n city: city,\n state: state,\n zipcode: zipcode,\n originalEmail: $input.first().json,\n searchQuery: `${area || city} ${state} construction permits`.trim()\n }\n};"
},
"typeVersion": 2
},
{
"id": "85f1df36-93ce-4895-bbde-022ebe40a1e7",
"name": "搜索政府数据",
"type": "n8n-nodes-base.httpRequest",
"position": [
660,
0
],
"parameters": {
"url": "https://api.usa.gov/jobs/search.json",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpQueryAuth",
"queryParameters": {
"parameters": [
{
"name": "keyword",
"value": "construction permit"
},
{
"name": "location_name",
"value": "={{ $json.searchArea }}"
},
{
"name": "size",
"value": "20"
}
]
}
},
"credentials": {
"httpQueryAuth": {
"id": "xA2e6hA40RZ8bzrI",
"name": "Query Auth account - test"
}
},
"typeVersion": 4.1
},
{
"id": "acc6341d-273f-4534-afb7-27771759a1df",
"name": "搜索建筑工地",
"type": "n8n-nodes-base.httpRequest",
"position": [
660,
160
],
"parameters": {
"url": "https://www.construction.com/api/search",
"options": {
"timeout": 10000
},
"sendQuery": true,
"sendHeaders": true,
"queryParameters": {
"parameters": [
{
"name": "q",
"value": "={{ $json.searchArea }} construction projects"
},
{
"name": "type",
"value": "projects"
},
{
"name": "limit",
"value": "15"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "User-Agent",
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
},
{
"name": "Accept",
"value": "application/json"
}
]
}
},
"typeVersion": 4.1
},
{
"id": "f8ca860e-b794-4749-9fa9-bb340e955845",
"name": "处理建筑数据",
"type": "n8n-nodes-base.code",
"position": [
900,
40
],
"parameters": {
"jsCode": "const governmentData = $input.all()[0]?.json?.results || [];\nconst constructionData = $input.all()[1]?.json?.projects || [];\nconst searchInfo = $('Extract Location Info').first().json;\n\n// Process government construction data\nconst govProjects = governmentData.map(item => ({\n title: item.position_title || 'Government Construction Project',\n location: item.locations?.[0] || searchInfo.searchArea,\n description: item.job_summary || 'No description available',\n source: 'Government Database',\n url: item.url || '#',\n startDate: item.start_date || 'TBD',\n type: 'Public Project'\n}));\n\n// Process construction industry data (fallback mock data if API fails)\nlet constructionProjects = [];\nif (constructionData.length > 0) {\n constructionProjects = constructionData.map(item => ({\n title: item.name || item.title || 'Construction Project',\n location: item.location || searchInfo.searchArea,\n description: item.description || 'Commercial construction project',\n source: 'Construction Industry',\n url: item.url || '#',\n startDate: item.start_date || 'Q2 2024',\n type: item.type || 'Private Project'\n }));\n} else {\n // Fallback mock data for demo purposes\n constructionProjects = [\n {\n title: `New Commercial Complex - ${searchInfo.searchArea}`,\n location: searchInfo.searchArea,\n description: 'Mixed-use commercial and residential development',\n source: 'Local Planning Department',\n url: '#',\n startDate: 'March 2024',\n type: 'Mixed Development'\n },\n {\n title: `Office Building Construction - ${searchInfo.city}`,\n location: `${searchInfo.city}, ${searchInfo.state}`,\n description: '5-story office building with retail space',\n source: 'Building Permits',\n url: '#',\n startDate: 'April 2024',\n type: 'Commercial'\n }\n ];\n}\n\n// Combine all projects\nconst allProjects = [...govProjects, ...constructionProjects];\n\n// Filter for recent/upcoming projects\nconst recentProjects = allProjects.filter(project => {\n const startDate = new Date(project.startDate);\n const now = new Date();\n const threeMonthsFromNow = new Date(now.getTime() + (90 * 24 * 60 * 60 * 1000));\n \n return startDate >= now || project.startDate.includes('2024') || project.startDate === 'TBD';\n});\n\nreturn {\n json: {\n searchArea: searchInfo.searchArea,\n totalProjects: recentProjects.length,\n projects: recentProjects.slice(0, 10), // Limit to top 10\n searchQuery: searchInfo.searchQuery,\n generatedAt: new Date().toISOString(),\n originalEmail: searchInfo.originalEmail\n }\n};"
},
"typeVersion": 2
},
{
"id": "5e85f511-81ac-42bf-af01-f465531874bb",
"name": "检查是否找到项目",
"type": "n8n-nodes-base.if",
"position": [
1320,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "condition1",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.totalProjects }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2
},
{
"id": "3a614463-2f2d-4d28-8761-9dcb4349b653",
"name": "生成邮件报告",
"type": "n8n-nodes-base.code",
"position": [
1540,
0
],
"parameters": {
"jsCode": "const data = $input.first().json;\nconst projects = data.projects;\n\n// Create HTML email content\nlet htmlContent = `\n<html>\n<head>\n <style>\n body { font-family: Arial, sans-serif; margin: 20px; }\n .header { background-color: #f4f4f4; padding: 20px; border-radius: 5px; }\n .project { border: 1px solid #ddd; margin: 10px 0; padding: 15px; border-radius: 5px; }\n .project-title { color: #333; font-weight: bold; font-size: 16px; }\n .project-meta { color: #666; font-size: 12px; margin: 5px 0; }\n .project-desc { margin: 10px 0; }\n .summary { background-color: #e8f4fd; padding: 15px; border-radius: 5px; margin: 20px 0; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <h2>🏗️ Construction Project Alert Report</h2>\n <p><strong>Search Area:</strong> ${data.searchArea}</p>\n <p><strong>Report Generated:</strong> ${new Date(data.generatedAt).toLocaleString()}</p>\n </div>\n \n <div class=\"summary\">\n <h3>📊 Summary</h3>\n <p><strong>Total Projects Found:</strong> ${data.totalProjects}</p>\n <p><strong>Search Query:</strong> ${data.searchQuery}</p>\n </div>\n \n <h3>🔍 Upcoming Construction Projects</h3>\n`;\n\nif (projects.length === 0) {\n htmlContent += '<p>No upcoming construction projects found in the specified area.</p>';\n} else {\n projects.forEach((project, index) => {\n htmlContent += `\n <div class=\"project\">\n <div class=\"project-title\">${project.title}</div>\n <div class=\"project-meta\">\n 📍 Location: ${project.location} | \n 📅 Start Date: ${project.startDate} | \n 🏢 Type: ${project.type}\n </div>\n <div class=\"project-desc\">\n <strong>Description:</strong> ${project.description}\n </div>\n <div class=\"project-meta\">\n <strong>Source:</strong> ${project.source}\n </div>\n </div>\n `;\n });\n}\n\nhtmlContent += `\n <div style=\"margin-top: 30px; padding: 15px; background-color: #f9f9f9; border-radius: 5px;\">\n <h4>💡 Next Steps</h4>\n <ul>\n <li>Review each project for potential competition</li>\n <li>Contact project owners for partnership opportunities</li>\n <li>Monitor progress and timeline changes</li>\n <li>Update your competitive analysis</li>\n </ul>\n </div>\n \n <p style=\"margin-top: 30px; color: #666; font-size: 12px;\">\n This report was automatically generated by your Construction Alert System.<br>\n To modify your alert preferences, reply to this email with your requirements.\n </p>\n</body>\n</html>\n`;\n\n// Create plain text version\nlet textContent = `Construction Project Alert Report\\n\\n`;\ntextContent += `Search Area: ${data.searchArea}\\n`;\ntextContent += `Total Projects Found: ${data.totalProjects}\\n`;\ntextContent += `Report Generated: ${new Date(data.generatedAt).toLocaleString()}\\n\\n`;\n\nif (projects.length === 0) {\n textContent += 'No upcoming construction projects found in the specified area.\\n';\n} else {\n textContent += 'UPCOMING CONSTRUCTION PROJECTS:\\n';\n textContent += '=' .repeat(40) + '\\n\\n';\n \n projects.forEach((project, index) => {\n textContent += `${index + 1}. ${project.title}\\n`;\n textContent += ` Location: ${project.location}\\n`;\n textContent += ` Start Date: ${project.startDate}\\n`;\n textContent += ` Type: ${project.type}\\n`;\n textContent += ` Description: ${project.description}\\n`;\n textContent += ` Source: ${project.source}\\n\\n`;\n });\n}\n\nreturn {\n json: {\n subject: `🏗️ Construction Alert: ${data.totalProjects} Projects Found in ${data.searchArea}`,\n htmlContent: htmlContent,\n textContent: textContent,\n recipientEmail: data.originalEmail.from,\n searchArea: data.searchArea,\n projectCount: data.totalProjects\n }\n};"
},
"typeVersion": 2
},
{
"id": "4782972d-6b57-4faf-9ce1-cedbee42ecff",
"name": "发送提醒邮件",
"type": "n8n-nodes-base.emailSend",
"position": [
1760,
0
],
"webhookId": "9dae36d2-91a9-4ef4-90ae-60754055afd2",
"parameters": {
"html": "={{ $json.htmlContent }}",
"options": {},
"subject": "={{ $json.subject }}",
"toEmail": "={{ $json.recipientEmail }}",
"fromEmail": "alerts@yourcompany.com"
},
"credentials": {
"smtp": {
"id": "G1kyF8cSWTZ4vouN",
"name": "SMTP -test"
}
},
"typeVersion": 2.1
},
{
"id": "49d55c27-73f1-4436-99f9-f0e4ff2cf8ac",
"name": "发送无结果邮件",
"type": "n8n-nodes-base.emailSend",
"position": [
1540,
200
],
"webhookId": "5375f687-193e-403e-a599-bbba10c97977",
"parameters": {
"text": "No upcoming construction projects were found for the requested area: {{ $('Extract Location Info').first().json.searchArea }}\\n\\nSearch was triggered at: {{ new Date().toLocaleString() }}\\n\\nOriginal request from: {{ $('Extract Location Info').first().json.originalEmail.from }}",
"options": {},
"subject": "No Construction Projects Found",
"toEmail": "admin@yourcompany.com",
"fromEmail": "alerts@yourcompany.com",
"emailFormat": "text"
},
"credentials": {
"smtp": {
"id": "G1kyF8cSWTZ4vouN",
"name": "SMTP -test"
}
},
"typeVersion": 2.1
},
{
"id": "9f9e205e-a6c6-4bf0-b25b-8d608eabc294",
"name": "等待数据",
"type": "n8n-nodes-base.wait",
"position": [
1120,
40
],
"webhookId": "fc75279b-7f48-421a-8222-b57f48dc06e2",
"parameters": {},
"typeVersion": 1.1
},
{
"id": "e5e98309-33a4-4b60-9cd6-f51925d77d7c",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
-360
],
"parameters": {
"width": 860,
"height": 300,
"content": ""
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "5e298be6-7660-412d-b5bb-15136626b35d",
"connections": {
"Email Trigger": {
"main": [
[
{
"node": "Check Email Subject",
"type": "main",
"index": 0
}
]
]
},
"Wait For Data": {
"main": [
[
{
"node": "Check if Projects Found",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Extract Location Info",
"type": "main",
"index": 0
}
]
]
},
"Check Email Subject": {
"main": [
[
{
"node": "Extract Location Info",
"type": "main",
"index": 0
}
]
]
},
"Extract Location Info": {
"main": [
[
{
"node": "Search Government Data",
"type": "main",
"index": 0
},
{
"node": "Search Construction Sites",
"type": "main",
"index": 0
}
]
]
},
"Generate Email Report": {
"main": [
[
{
"node": "Send Alert Email",
"type": "main",
"index": 0
}
]
]
},
"Search Government Data": {
"main": [
[
{
"node": "Process Construction Data",
"type": "main",
"index": 0
}
]
]
},
"Check if Projects Found": {
"main": [
[
{
"node": "Generate Email Report",
"type": "main",
"index": 0
}
],
[
{
"node": "Send No Results Email",
"type": "main",
"index": 0
}
]
]
},
"Process Construction Data": {
"main": [
[
{
"node": "Wait For Data",
"type": "main",
"index": 0
}
]
]
},
"Search Construction Sites": {
"main": [
[
{
"node": "Process Construction Data",
"type": "main",
"index": 0
}
]
]
}
}
}如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级 - 市场调研
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
Oneclick AI Squad
@oneclick-aiThe AI Squad Initiative is a pioneering effort to build, automate and scale AI-powered workflows using n8n.io. Our mission is to help individuals and businesses integrate AI agents seamlessly into their daily operations from automating tasks and enhancing productivity to creating innovative, intelligent solutions. We design modular, reusable AI workflow templates that empower creators, developers and teams to supercharge their automation with minimal effort and maximum impact.
分享此工作流