8
n8n 中文网amn8n.com

n8n挑战赛_Haeng_Franz_Rott

高级

这是一个Market Research领域的自动化工作流,包含 22 个节点。主要使用 If, Code, Gmail, Webhook, HttpRequest 等节点。 使用Firecrawl、Sheets和Gmail警报监控动态网站变化

前置要求
  • Google 账号和 Gmail API 凭证
  • HTTP Webhook 端点(n8n 会自动生成)
  • 可能需要目标 API 的认证凭证
  • Google Sheets API 凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "psYzSydCkrbiJU2j",
  "meta": {
    "instanceId": "5116f2f7706b559eceadfeb527d2f261505621d6d31889c13b53a0633d9b86eb"
  },
  "name": "n8n_Challenge_Haeng_Franz_Rott",
  "tags": [],
  "nodes": [
    {
      "id": "042eb5f7-dbf1-47c5-a03f-f4e965a48d62",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "notes": "Trigger node – waits for an HTTP request on /webhook/n8n-challenge and starts the workflow. The final response is supplied by the Respond* nodes.",
      "position": [
        -1820,
        -140
      ],
      "webhookId": "a2d68f11-97d1-4dbd-85e1-3a38b81b29bb",
      "parameters": {
        "path": "example_path",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 1
    },
    {
      "id": "71f3e740-7974-4302-94c8-161daa6c71c7",
      "name": "Firecrawl HTTP 请求",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Calls Firecrawl API to scrape the target web page in Markdown and HTML. Uses Bearer-token authentication configured in credentials.",
      "onError": "continueErrorOutput",
      "position": [
        -1600,
        -140
      ],
      "parameters": {
        "url": "<insert_url>",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"url\": \"https://we-hang.com/pages/n8n-automation-expert-challenge\",\n  \"formats\": [\n    \"markdown\",\n    \"html\"\n  ]\n} ",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "id": "GNtnoudkdHfoKp6C",
          "name": "Bearer Auth account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e8e42131-3da1-46ea-814a-247082658576",
      "name": "获取时间戳",
      "type": "n8n-nodes-base.code",
      "notes": "JavaScript Code node – attaches a millisecond timestamp to the scraped content (legacy high-port flag kept untouched for compatibility).",
      "onError": "continueErrorOutput",
      "position": [
        -1380,
        -140
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nconst updatedItems = items.map((item) => {\n  if (item.json.data.port > 5000) {\n    item.json.data[\"high-port\"] = true;\n  }\n  return item.json;\n});\n\nconst timestamp = new Date().getTime();\n\nreturn { updatedItems, timestamp };\n"
      },
      "typeVersion": 2
    },
    {
      "id": "7262962a-e5c8-4e87-9b17-80b43557782a",
      "name": "更新当前内容",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Writes the freshly scraped content into row 2 of the *comparison* sheet (columns current_timestamp & current_content).",
      "onError": "continueErrorOutput",
      "position": [
        -1160,
        -140
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_number": "2",
            "current_content": "={{ $json.updatedItems[0].data.markdown }}",
            "current_timestamp": "={{ $json.timestamp }}"
          },
          "schema": [
            {
              "id": "last_timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "current_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "current_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "Häng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "0aqVYx6pUytfPyGJ",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "d26b1096-0288-4ca7-8a0c-388996226728",
      "name": "读取当前和最新内容",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Loads the same row 2, giving us both last_content and current_content for comparison.",
      "onError": "continueErrorOutput",
      "position": [
        -940,
        -140
      ],
      "parameters": {
        "options": {
          "returnAllMatches": "returnFirstMatch"
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "Häng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "0aqVYx6pUytfPyGJ",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4,
      "alwaysOutputData": true
    },
    {
      "id": "52c5313a-1ebb-4875-8c8b-61b407bc6cab",
      "name": "是否相等?",
      "type": "n8n-nodes-base.if",
      "notes": "IF node – checks whether the scraped content changed. True branch → unchanged, False branch → changed.",
      "onError": "continueErrorOutput",
      "position": [
        -720,
        -140
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.last_content }}",
              "value2": "={{ $json.current_content }}"
            }
          ]
        },
        "combineOperation": "any"
      },
      "executeOnce": true,
      "typeVersion": 1
    },
    {
      "id": "cd72f620-e31f-4c0d-8835-59ed187a1ccd",
      "name": "回复未更改",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "Returns a 200 OK response to the original webhook caller when no change was detected.",
      "position": [
        -500,
        -240
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "3ac13426-967f-46a8-af12-a5cac4bd4b20",
      "name": "读取最新和最新内容",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Reads the current sheet row again on the ‘changed’ path so subsequent code nodes have the freshest values.",
      "onError": "continueErrorOutput",
      "position": [
        -500,
        -40
      ],
      "parameters": {
        "options": {
          "returnAllMatches": "returnFirstMatch"
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "Häng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "0aqVYx6pUytfPyGJ",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4,
      "alwaysOutputData": true
    },
    {
      "id": "6ca28b23-f8da-4dd1-af41-ca42f76b69f7",
      "name": "提取差异",
      "type": "n8n-nodes-base.code",
      "notes": "Splits last & current content into arrays, determines new vs missing segments, attaches another timestamp.",
      "onError": "continueErrorOutput",
      "position": [
        -280,
        -240
      ],
      "parameters": {
        "jsCode": "const items = $input.all().map((item) => item.json);\n\nconst result = items.map((item) => {\n  const lastContent = item.last_content.split(\",\");\n  const currentContent = item.current_content.split(\",\");\n  const newContent = currentContent.filter((i) => !lastContent.includes(i));\n  const missingContent = lastContent.filter((i) => !currentContent.includes(i));\n  return {\n    ...item,\n    newContent,\n    missingContent,\n    timestamp: new Date().getTime(),\n  };\n});\n\nreturn result;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "ec0188a2-f4c0-4f8d-b155-fe5eb67faf8f",
      "name": "Gmail",
      "type": "n8n-nodes-base.gmail",
      "notes": "Sends a plain-text email detailing what changed (first diff only) to n8nchallenge@we-hang.com.",
      "onError": "continueErrorOutput",
      "position": [
        -60,
        -240
      ],
      "webhookId": "c591ca46-7626-4de5-968c-9bfce7d97b38",
      "parameters": {
        "sendTo": "=example@gmail.com",
        "message": "=Guten Tag, \n\nEs gab eine Änderung an der beobachteten Website:\n\nUm \"{{ $json.timestamp }}\" wurde \"{{ $json.missingContent[0] }}\" durch \"{{ $json.newContent[0] }}\" ersetzt.\n\nViele Grüße ",
        "options": {},
        "subject": "Relevante Inhaltsänderung auf Website",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "va5DkYihiKASjVJw",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "1b85582b-48e1-4f70-8df2-fa5dbd505ddd",
      "name": "追加日志行",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Adds a new row to *Log* sheet with timestamp & full current content – creates a historical audit trail.",
      "onError": "continueErrorOutput",
      "position": [
        -60,
        -40
      ],
      "parameters": {
        "columns": {
          "value": {
            "content": "={{ $json.current_content }}",
            "timestamp": "={{ $json.current_timestamp }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=0",
          "cachedResultName": "Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "Häng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "0aqVYx6pUytfPyGJ",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "a57f34af-ddca-4973-8c52-7947006cc5fa",
      "name": "更新最新内容",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Moves current values into the *last_* columns (row 2) so the next run will compare against them.",
      "onError": "continueErrorOutput",
      "position": [
        -60,
        160
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_number": "2",
            "last_content": "={{ $json.current_content }}",
            "last_timestamp": "={{ $json.current_timestamp }}"
          },
          "schema": [
            {
              "id": "last_timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_timestamp",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "current_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_content",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "current_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "Häng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "0aqVYx6pUytfPyGJ",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "69c262ab-fcc5-480f-acff-01c982b68673",
      "name": "回复已更改",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "Returns a success response to the original HTTP call confirming that a change was processed.",
      "position": [
        160,
        60
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "ccbaaf84-52cf-40dd-9147-e09e5c91e71e",
      "name": "📋 设置概览",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2140,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "🎯 工作流用途:"
      },
      "typeVersion": 1
    },
    {
      "id": "1adc1940-ff74-4454-b841-6e9379c76d9e",
      "name": "🔐 凭据设置",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1700,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "⚙️ 所需凭据:"
      },
      "typeVersion": 1
    },
    {
      "id": "38fc9213-614c-467e-af3f-18fe8c62a99e",
      "name": "📊 GOOGLE SHEETS 设置",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1320,
        100
      ],
      "parameters": {
        "width": 400,
        "height": 300,
        "content": "📋 电子表格结构:"
      },
      "typeVersion": 1
    },
    {
      "id": "d9a32777-2a21-46ba-a179-534f27616b28",
      "name": "⚙️ 配置",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1240,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "🔧 自定义设置:"
      },
      "typeVersion": 1
    },
    {
      "id": "6b09600c-1a63-4b96-bf3a-eaeb6dfd02f0",
      "name": "🧪 测试与激活",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        980,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "✅ 测试步骤:"
      },
      "typeVersion": 1
    },
    {
      "id": "a43347e4-f5b3-4122-b3b8-45ff925a3402",
      "name": "🤖 自动化设置",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -780,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "⏰ 调度选项:"
      },
      "typeVersion": 1
    },
    {
      "id": "8184238c-654e-4b3e-b5f9-e9e8f423fe0f",
      "name": "🔧 维护与监控",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -340,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "📈 监控:"
      },
      "typeVersion": 1
    },
    {
      "id": "4b6fd3db-6276-4885-b704-d5709a9ad630",
      "name": "🔒 安全与最佳实践",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        100,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "🛡️ 安全考虑:"
      },
      "typeVersion": 1
    },
    {
      "id": "10a36c1e-34ef-46dd-83a7-0cd4c6034a6c",
      "name": "🔍 常见问题与解决方案",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        540,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "⚠️ 常见问题:"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "732c1f33-081b-46d4-8fa3-1b497856198b",
  "connections": {
    "Gmail": {
      "main": [
        [
          {
            "node": "Respond Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Firecrawl HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Equal?": {
      "main": [
        [
          {
            "node": "Respond Unchanged",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Read Latest and Latest Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Timestamp": {
      "main": [
        [
          {
            "node": "Update Current Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Log Row": {
      "main": [
        [
          {
            "node": "Respond Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Differences": {
      "main": [
        [
          {
            "node": "Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Latest Content": {
      "main": [
        [
          {
            "node": "Respond Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Firecrawl HTTP Request": {
      "main": [
        [
          {
            "node": "Get Timestamp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Current Content": {
      "main": [
        [
          {
            "node": "Read Current and Latest Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Latest and Latest Content": {
      "main": [
        [
          {
            "node": "Extract Differences",
            "type": "main",
            "index": 0
          },
          {
            "node": "Append Log Row",
            "type": "main",
            "index": 0
          },
          {
            "node": "Update Latest Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Current and Latest Content": {
      "main": [
        [
          {
            "node": "Is Equal?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 市场调研

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量22
分类1
节点类型8
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

外部链接
在 n8n.io 查看

分享此工作流