
你已經成功地建立了一個 n8n 自動化排程爬蟲,它每天 dutifully地為你抓取 PTT 的最新文章。但你很快就發現了一個新的、令人頭痛的問題:數據重複。
你的 Google Sheets 表格中,第一天有 20 篇文章,第二天變成了 40 篇,但其中有 15 篇是跟昨天完全一樣的舊資料。日積月累,你的資料庫變得越來越臃腫,充滿了大量重複的紀錄,不僅難以分析,更浪費了後續流程的處理資源。
你真正想要的,是一個更聰明的爬蟲。一個能夠「記住」它上次看過什麼,並且在下一次執行時,只告訴你「哪些是全新的資料」或「哪些是內容有變動的資料」的智慧系統。
這,就是「增量爬取 (Incremental Scraping)」的藝術,而實現它的核心,在於「數據去重與比對」。這篇文章將是你的 n8n 數據比對終極指南。我們將手把手教你如何為你的爬蟲建立一個「記憶體」,並活用 Merge
節點這個強大的工具,來精準地比對新舊資料,讓你從此告別重複數據的惡夢。
告別重複數據!為什麼你的排程爬蟲需要一個「記憶」?
一個沒有「記憶」的排程爬蟲,是「無狀態的 (Stateless)」。它每次執行,都像失憶一樣,把目標網站當作第一次見面,抓回它看到的所有內容。這種做法會帶來幾個嚴重的問題:
- 數據庫冗餘: 你的儲存空間會被大量一模一樣的資料所佔據。
- 資源浪費: 對於下游的自動化流程(例如發送通知、寫入 CRM),你會不斷地對早已處理過的舊資料,重複執行一樣的動作,浪費了大量的 API 呼叫次數與執行時間。
- 無法偵測變動: 你無法知道一項商品是「價格降低了」,還是一則論壇文章是「被編輯更新了」,因為你每次看到的,都只是當下的最終狀態。
要解決這個問題,我們必須讓爬蟲變得「有狀態 (Stateful)」。我們需要為它建立一個外部的「記憶體」,用來存放「所有已經處理過的資料紀錄」。在每一次新的爬取任務開始時,爬蟲會先回頭看看自己的記憶,然後只處理那些它「沒見過」或「跟記憶中不一樣」的新資訊。
建立你的爬蟲記憶體:選擇 Google Sheets 或資料庫作為「已處理紀錄」
這個所謂的「記憶體」,其實就是一個用來儲存歷史紀錄的資料庫。對於 n8n 使用者來說,我們有兩個絕佳的選擇:
- Google Sheets (適合入門與中小型專案):
- 優點: 極度簡單、直觀、無需額外設定。你可以直接建立一個新的試算表,命名為「PTT 已處理文章」,用來存放所有爬取過的 PTT 文章連結。
- 缺點: 當紀錄數量超過數萬筆時,讀寫效能會顯著下降。
- 資料庫 (MySQL / PostgreSQL / MongoDB,適合大型專案):
- 優點: 效能極佳,能夠輕鬆處理數十萬、甚至數百萬筆紀錄。查詢與更新的速度遠超 Google Sheets。你可以參考我們的 n8n 資料庫整合教學。
- 缺點: 需要額外的資料庫設定與管理。
選擇建議: 對於大多數個人的爬蟲專案,從 Google Sheets 開始是完全足夠且最方便的。
核心戰術:使用 Merge
節點比對新舊資料,找出差異
一旦我們有了「記憶體」(歷史資料),又有了當次爬取到的「新資料」,接下來的關鍵,就是如何高效地找出這兩批資料之間的「差異」。這正是 n8n Merge
節點大顯身手的舞台。
比對的核心邏輯 (Read-Compare-Write Pattern):
- 抓取新資料 (Scrape): 執行你的爬蟲邏輯,得到一份「當前最新」的資料列表。
- 讀取舊資料 (Read History): 從你的記憶體(Google Sheets 或資料庫)中,讀取「所有過去處理過」的資料列表。
- 進行比對 (Compare): 使用
Merge
節點,以一個「唯一識別碼 (Unique ID)」(例如文章的 URL、商品的 SKU)作為Key
,來比對這兩份列表。 - 篩選出差異:
Merge
節點的輸出結果,可以讓我們輕易地用IF
節點,篩選出「只存在於新資料中」(新增)或「兩邊都存在但內容有變」(更新)的項目。 - 處理並更新記憶: 只針對這些有差異的項目,執行後續的自動化動作,並將這些「新增」或「更新」的項目,寫回到我們的記憶體中,供下一次比對使用。

實戰演練一:抓取 PTT 最新文章,並自動過濾已存在紀錄
- 目標: 每天定時爬取 PTT 電影版第一頁的文章,但只將「全新的、從未出現過」的文章,新增到我們的 Google Sheets 中。
- 記憶體: 一個名為「PTT Scraped Posts」的 Google Sheets,其中 A 欄存放
link
(文章的唯一 URL)。 - 流程設計:
Schedule
->...PTT Scraper...
->HTML Extract
(抓取新資料):- 這部分是我們熟悉的 PTT 爬蟲流程,最終輸出當前最新的文章列表。
Google Sheets (Read)
(讀取舊資料):- Operation:
Read
- 設定讀取「PTT Scraped Posts」這個試算表的所有
link
欄位資料。
- Operation:
Merge
節點 (進行比對):- Input 1: 連接
HTML Extract
的輸出 (新資料)。 - Input 2: 連接
Google Sheets (Read)
的輸出 (舊資料)。 - Mode:
Merge by Key
- Key for Input 1:
link
(新資料中的文章連結欄位) - Key for Input 2:
link
(舊資料中的文章連結欄位) - Join: 選擇
Full Outer Join
(保留所有資料,方便我們找出只存在於一邊的項目)。
- Input 1: 連接
IF
節點 (篩選出「新」文章):Merge
節點的輸出中,如果一筆資料是「全新的」,那麼它來自 Input 2 (舊資料) 的欄位就會是空的。我們可以利用這個特性來篩選。- Condition:
{{ $json.input_2_data.link }}
Is Empty。 - 只有符合這個條件的(也就是舊資料中沒有的)Items,才會從
true
路徑輸出。
Google Sheets (Append)
(更新記憶):- 將
IF
節點true
路徑的輸出,連接到Google Sheets
的Append
操作。 - 將這些被確認為「全新」的文章,新增到我們的「PTT Scraped Posts」記憶體中,為下一次的執行做準備。
- 你也可以將這些新文章,同時發送到 Slack 或 Telegram。
- 將
實戰演練二 (進階):監控商品價格,只在「價格變動」時發出通知
- 目標: 每天監控一個商品頁面的價格,只有當「價格與上次記錄的不同」時,才發送降價通知。
- 記憶體: 一個 Google Sheets,包含
product_id
和last_price
兩個欄位。
核心邏輯差異: 在 Merge
節點之後,我們需要用 IF
節點來設定一個不同的條件:
- 第一個條件: 確保這筆資料在新舊列表中都存在(
{{ $json.input_2_data.product_id }}
Is Not Empty)。 - 第二個條件 (AND): 比較新舊價格是否不相等 (
{{ $json.input_1_data.price }}
Not Equal{{ $json.input_2_data.last_price }}
)。
只有同時滿足這兩個條件的商品,才是我們需要關注的「價格已更新」的目標。
數據比對的最佳實踐與效能考量
- 選擇一個好的「唯一識別碼 (Unique Key)」: 這是去重與比對成功的基石。對於文章,通常是 URL;對於商品,是 SKU 或 ID;對於用戶,是 Email 或用戶 ID。這個 Key 必須是穩定且獨一無二的。
- 效能考量: 當你的歷史紀錄超過數萬筆時,每次都把整個 Google Sheets 讀取回 n8n 進行比對,會變得非常緩慢。這時,就應該考慮將你的「記憶體」升級到 PostgreSQL 或 MySQL 資料庫。資料庫能夠在伺服器端,高效地完成大量的數據比對與篩選工作。

結語
學會數據去重與比對,是將你的 n8n 爬蟲從一個單純的「資料抓取器」,升級為一個智慧的「變動偵測器 (Change Detector)」的關鍵。
透過建立一個外部的「記憶體」,並活用 Merge
節點強大的比對能力,你的自動化流程將不再被重複的舊數據所淹沒。你能夠精準地聚焦在那些「新增」的機會與「更新」的變化上,讓你的通知更有價值、你的數據庫更乾淨、你的整個自動化系統也因此變得更高效、更具智慧。
更多精選文章請參考
n8n 與 Zapier 比較:該選哪個?2025年最完整功能、費用、優缺點分析
開源自動化工具推薦:從工作流程到測試,找到最適合你的免費方案
n8n 發送 Email 超詳細教學:從 SMTP 設定到 Gmail 節點串接,一篇搞定!
n8n Notion 串接終極指南:2025 年打造自動化工作流程,效率翻倍!