身為網站管理者,定期追蹤網站的效能和 SEO 表現至關重要。然而,手動檢查既耗時又容易忘記。今天,我們將利用 n8n 這個強大的自動化工具,串接 Google PageSpeed Insights API,打造一個能定時回報網站健康狀況的自動化流程,並將報告發送到 Discord,讓你輕鬆掌握網站的最新狀態
n8n 本身沒有內建的 Lighthouse 節點,但幸運的是,Google 提供了一個名為 PageSpeed Insights API 的免費服務,其底層就是使用 Lighthouse 引擎來進行分析,我們可以透過 n8n 的 HTTP Request
節點來呼叫這個 API,取得完整的分析報告。
申請 API 金鑰
https://developers.google.com/speed/docs/insights/v5/get-started?authuser=1&hl=zh-tw
把彈出視窗的「YOUR API KEY」複製起來
[排程觸發] -> [設定網站清單] -> [呼叫 API 檢查] -> [取得分數] -> [傳送結果]
排程觸發:設定一個固定的時間,例如每週日早上,自動啟動流程
設定網站清單:定義要檢查的一個或多個網站網址
呼叫 API 檢查:依序將清單中的網址傳送給 PageSpeed Insights API 進行分析
擷取關鍵分數:從 API 回傳的完整報告中,只抓出我們關心的效能(Performance)和 SEO 分數
彙整並傳送結果:將所有網站的分數整理成一份易讀的訊息,並發送到指定的 Discord 頻道
來到儀表板,新增一個流程「Create Workflow」
初始節點選擇排程「On a schedule」
選擇「Cron」來下指令
選擇一個時間,像我是設定每個禮拜日的早上 10 點
下個節點選擇「Edit Fields (Set)」來設定要檢查的網站清單
點選中間的「Add Field」
欄位名稱設定為「urls」,格式選擇「Array」,內容是包含網址的陣列,例如:
["https://www.hexschool.com", "https://5xcampus.com/"];
下個節點選擇「Split Out」
把上個節點的「urls」變數抓到欄位裡面做拆分
接著選擇「HTTP Request」
方法選擇為「GET」,URL 設定為下
https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={{ $json.urls }}&strategy=desktop&category=performance&category=seo&key=YOUR_API_KEY
接著點選正上方的「Execute step」來測試跑看看,等待一段時間可以收到整包資料
下個節點再選擇「Edit Fields (Set)」來抓出需要的資料
點選中間的「Add Field」
欄位名稱設定如下
url
{
{
$json.lighthouseResult.requestedUrl;
}
}
performanceScore
{
{
Math.round($json.lighthouseResult.categories.performance.score * 100);
}
}
seoScore
{
{
Math.round($json.lighthouseResult.categories.seo.score * 100);
}
}
下個節點選擇「Code」來整理訊息
程式碼如下
let messageBody = "";
// 走訪所有從上一個節點傳來的項目
for (const item of items) {
const url = item.json.url;
const performance = item.json.performanceScore;
const seo = item.json.seoScore;
// 如果 messageBody 不是空的,就先加上分隔線
if (messageBody !== "") {
messageBody += "\n----------------------------------\n";
}
// 組合單一網站的報告內容
messageBody += `**網站:** ${url}\n`;
messageBody += `**效能分數 (Performance):** \`${performance}\` / 100\n`;
messageBody += `**SEO 分數:** \`${seo}\` / 100`;
}
// 最後,回傳一個包含完整訊息的「單一」項目
return [
{
json: {
summaryMessage: messageBody,
},
},
];
下個節點選擇「Discord」來傳送訊息
「Connection Type」選擇「Webhook」,憑證的串接在之前的文章有撰寫過,這邊就不重複惹
Message 把上個節點的變數抓進來
回到畫布點選正下方的「Execute workflow」來測試看看
Discord 有收到訊息代表成功啦
由於有設定排程,所以要記得調整設定的時區
選擇台灣時區
接著記得到最上方切換為「Active」來啟用這個流程
現在,這個 n8n 流程就會像個忠實的檢查員,每週準時為你檢查網站的健康狀況,並自動回報給你
最後附上這個流程的 JSON
{
"name": "lighthouse",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtHour": 10
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [0, 0],
"id": "19013ae7-392e-46bf-8c17-0cd55aa84149",
"name": "Schedule Trigger"
},
{
"parameters": {
"url": "=https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={{ $json.urls }}&strategy=desktop&category=performance&category=seo&key=<YOUR_GOOGLE_API_KEY>",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [660, 0],
"id": "d1692a12-8ebd-479e-b08e-c0eeef9cc1bf",
"name": "HTTP Request"
},
{
"parameters": {
"fieldToSplitOut": "urls",
"options": {}
},
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [440, 0],
"id": "bab43bd3-f13c-4a6c-9926-ae5ed49b8dfa",
"name": "Split Out"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "6a3aea36-198c-461c-abfc-1408cc314aa6",
"name": "urls",
"value": "=[\"https://www.hexschool.com\", \"https://5xcampus.com/\"]",
"type": "array"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [220, 0],
"id": "52c5e6a4-01e8-4e47-b855-c533f02b9e26",
"name": "List"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "b726f03a-faa2-4210-9468-95df2db00422",
"name": "url",
"value": "={{ $json.lighthouseResult.requestedUrl }}",
"type": "string"
},
{
"id": "80cce080-3191-471a-b9a6-2c2b492e18b2",
"name": "performanceScore",
"value": "={{ Math.round($json.lighthouseResult.categories.performance.score * 100) }}",
"type": "string"
},
{
"id": "1b014eb7-3531-46d8-8344-0c0949223f8f",
"name": "seoScore",
"value": "={{ Math.round($json.lighthouseResult.categories.seo.score * 100) }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [880, 0],
"id": "f41b65ae-9237-4e43-9fb1-23d5235525bc",
"name": "Edit Fields"
},
{
"parameters": {
"jsCode": "let messageBody = \"\";\n\n// 走訪所有從上一個節點傳來的項目\nfor (const item of items) {\n const url = item.json.url;\n const performance = item.json.performanceScore;\n const seo = item.json.seoScore;\n\n // 如果 messageBody 不是空的,就先加上分隔線\n if (messageBody !== \"\") {\n messageBody += \"\\n----------------------------------\\n\";\n }\n\n // 組合單一網站的報告內容\n messageBody += `**網站:** ${url}\\n`;\n messageBody += `**效能分數 (Performance):** \\`${performance}\\` / 100\\n`;\n messageBody += `**SEO 分數:** \\`${seo}\\` / 100`;\n}\n\n// 最後,回傳一個包含完整訊息的「單一」項目\nreturn [{\n json: {\n summaryMessage: messageBody\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1100, 0],
"id": "0d232e8b-7b96-457f-8361-f8197b2398e5",
"name": "Code"
},
{
"parameters": {
"authentication": "webhook",
"content": "={{ $json.summaryMessage }}",
"options": {}
},
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [1320, 0],
"id": "1464b030-d148-4d02-a0ac-671db31a9b91",
"name": "Discord",
"webhookId": "<YOUR_WEBHOOK_ID>",
"credentials": {
"discordWebhookApi": {
"id": "<YOUR_CREDENTIAL_ID>",
"name": "Discord Webhook account"
}
}
}
],
"pinData": {},
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "List",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"List": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Discord",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"timezone": "Asia/Taipei",
"callerPolicy": "workflowsFromSameOwner",
"executionTimeout": -1
},
"versionId": "<WORKFLOW_VERSION_ID>",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "<WORKFLOW_ID>",
"tags": []
}