先說一下背景
我在外商做過 data engineer,同時管超過 400 隻電商爬蟲。每隻爬蟲都有進度書籤(checkpoint)、健康檢查、統一的管線框架。用過 Airflow 排程、dbt 做資料轉換、Scrapy 做爬蟲管理。這些工具的設計哲學我很熟,不是那種「聽過」的熟,是「半夜三點被監控系統叫起來修正式環境事故」的熟
然後我離開外商開始一個人接案,用 Claude Code 幫自己建工具
「幫我寫一個 script,每天自動把 Email 拉下來存成 Markdown」
十分鐘,能跑。再來行事曆,再來通訊軟體,再來錄音逐字稿,再來家庭共享檔案
五條資料管線,五個 shell script,每個都是 Claude Code 十分鐘生出來的
我還加了 CI/CD,GitHub Actions 定時跑,cron job 全自動
你問我當時為什麼不用 Airflow?不用 dbt?不寫 Python?
因為我覺得「這又不是正式環境,只是我自己的小工具,何必那麼認真」
管過 400 隻爬蟲的人,用 vibe coding 生了 5 個沒有任何框架的 script,還覺得理所當然
每個都能跑啊,幹嘛想那麼多
三個月後我回來看,發現一件事
我不敢動它們
Vibe Coding 的甜蜜陷阱
Vibe coding 有個特性:它讓你覺得問題已經解決了
Claude Code 幫你生了一個能跑的 script,CI/CD 自動排程,GitHub Actions 每天打綠勾,心裡覺得「搞定了」
但「能跑」跟「能維護」是兩件事
第一個月:五條管線都在跑,一切美好
第二個月:我加了一個新欄位,改了 Email 的 script,行事曆的 script 沒改到。沒事,還能跑
第三個月:通訊軟體那條管線的追蹤器壞了。JSON 格式錯誤,但 script 寫了 || true,錯誤被吞掉了。它繼續跑,繼續打綠勾,只是不再同步任何東西
我花了一個多月才發現它壞了
五個 script,五套追蹤機制。有的用 JSON,有的用純文字,有的根本沒有。每個 script 都是獨立生出來的,各自發明各自的格式,互相不知道對方的存在
更糟的是 Claude Code 裡也有一套 skill 在做類似的事。Shell 改了輸出格式,skill 不知道;skill 加了新邏輯,shell 沒跟上。兩套系統做同一件事,永遠對不齊
如果這是正式環境,我早就用 Airflow 統一排程、用 dbt 做資料品質檢查了。但因為是「自己的小工具」,我什麼都沒用
我終於承認:我在沒有設計的情況下,用 vibe coding 長出了一個系統
第一次重構:抽共用函式(修好了!)
好,那來整理一下
我跟 Claude Code 說:「把五個 script 重複的邏輯抽出來,做一個共用的 lib.sh」
十五分鐘後,有了一個漂亮的共用函式庫:健康檢查、進度書籤讀寫、錯誤回報,全部集中管理
跑起來,沒問題。搞定了!
然後我改了 Email 管線的書籤格式
行事曆管線炸了
原因:shell 沒有 class,所有狀態只能用全域變數。EMAIL_LAST_RUN、CALENDAR_LAST_RUN,五條管線的變數全擠在同一個空間裡,改一個名字,其他四個可能靜靜地讀到錯的值
DRY 的問題解決了,架構的問題一點沒變
第二次重構:模擬框架(這次一定行!)
既然 shell function 不夠,那我來做個框架
每條管線定義一個 config,再寫一個通用的 runner 去執行:
PIPELINE_NAME="email"
COLLECT_FN="collect_email"
Runner 用 bash 的 indirect expansion 動態呼叫:
collect_fn="${PIPELINE_NAME}_collect"
${!collect_fn}
你知道 ${!collect_fn} 是什麼嗎?它是 bash 的一個魔法語法,把一個變數的值再當作變數名去解析。聽起來很酷,debug 的時候想死
沒有 IDE 支援,沒有型別檢查,出錯只能用 set -x 把每一行都印出來,然後在一百行 trace 裡用肉眼找哪裡爆了
我坐在螢幕前三秒,突然意識到一件事:
我在用 shell 模擬 Python
那為什麼不直接用 Python?
這不是我要的生活
咖啡機前的頓悟
第二次重構失敗後,我去泡了杯咖啡
站在那裡突然想到:等等,這五條管線在做什麼?
簡單講就是四件事:
- 去外面抓東西回來
- 看懂抓回來的格式
- 記住上次抓到哪,下次從那裡繼續
- 抓完回報一聲:我還活著,這次抓了幾筆
如果你做過網路爬蟲,你會覺得這四件事很眼熟。因為 Google 爬網頁就是這樣:抓取、解析、記進度、回報狀態。Scrapy 框架的 Spider 也是這樣設計的
我的五條管線跟爬蟲是同一個問題,只是我抓的不是網頁,是 Email、行事曆、通訊紀錄
我管了兩年爬蟲的人,自己用的時候居然忘了
不是不知道,是 vibe coding 讓我跳過了「想」。Claude Code 說一句話就能跑,我就一直說、一直跑,從來沒停下來問自己:「這個問題的最佳做法(best practice)是什麼?」
答案一直在我腦子裡。爬蟲架構,Python 社群解決過不知道幾百遍了,Scrapy 的 Spider pattern 就是現成的答案
我只是忘了用
第三次重構:回到老本行
不再硬套 shell,直接用 Python 寫一個 BasePipeline 類別
想像你要教一個新人管爬蟲。你不會讓他從零開始寫,你會給他一個骨架:「抓什麼你自己定義,怎麼追蹤進度、怎麼回報狀態,框架幫你處理」
就是這個意思:
class BasePipeline:
def fetch(self):
"""去外面抓東西,你自己定義"""
raise NotImplementedError
def parse(self, raw):
"""看懂抓回來的東西,你自己定義"""
raise NotImplementedError
def run(self):
"""骨架:抓 → 解析 → 記進度 → 回報"""
checkpoint = self.load_checkpoint()
raw_items = self.fetch()
new_items = [i for i in raw_items if i["id"] > checkpoint]
for item in new_items:
try:
self.save(self.parse(item))
except Exception as e:
self.report_error(e, item)
self.update_checkpoint(new_items[-1]["id"])
self.report_health(len(new_items))
加一條新管線,就是繼承骨架、填兩個方法:
class CalendarPipeline(BasePipeline):
def fetch(self):
return pull_ics_events(self.config["url"])
def parse(self, raw):
return {"title": raw["summary"], "start": raw["dtstart"]}
健康檢查、進度書籤、錯誤回報,全部繼承。不用再寫一遍
結果
重構完那天早上跑 pytest,0.04 秒,15 個全綠。我盯著螢幕看了五秒
砍掉 1,490 行(shell 583 + 重複的 skill 907),新增 1,042 行(Python 668 + tests 374)
net -155 行,刪比加多。29 files changed
加一條新管線,15 分鐘,不用碰其他任何東西
AI 方便 vs 系統化:不是二選一
這次踩坑讓我想清楚一件事
LLM 很方便,說一句話就能生 code,十分鐘能跑。但有些事情,系統化的 Python 模組、規則式(rule-based)的框架,反而更可靠
不是說 AI 不好,是它們解決不同層次的問題:
LLM 擅長:理解模糊的需求、處理非結構化資料、快速生成雛形(prototype) 系統化框架擅長:狀態追蹤、錯誤恢復、一致性保證、可測試性
我現在的管線裡,「抓」和「解析」有些會用 LLM(比如把一堆雜亂的通訊紀錄整理成待辦事項),但「記進度」和「健康檢查」絕對是規則式的 Python code
你不會想讓 LLM 幫你記書籤。它會自己瞎掰一個出來
AI 負責理解,系統負責記憶。兩個都要,但別搞混哪個該用在哪裡
這個平衡不是一次就能找到的,是不斷迭代的過程。我的第一版全靠 AI 生(太依賴),第二版全部自己設計(太慢),第三版才找到甜蜜點:LLM 做雛形(prototype),人腦做架構,Python 做系統
Shell Script 的正確定位
說清楚,shell 沒有不好
它快,它輕,任何環境都有,不需要 virtualenv,不需要 pip install,chmod +x,跑
但當你的雛形(prototype)活超過三個月、被系統其他部分依賴、需要追蹤狀態,它已經不是 prototype 了
Shell script 是 prototype,不是 architecture
判斷訊號:當你的 shell 裡出現 python3 -c "import json..." 的時候,就是該換語言的時候。我的五個 script 裡有四個都有這行,我花了六個月才看見
一個人接案特別容易踩這個坑,因為沒有人幫你踩煞車。沒有 code review,沒有人問「你確定這個設計長期能維護嗎?」你趕,就直接 merge;你忙,就說「下次再重構」
下次從來不會到來,直到管線在你睡覺的時候悄悄壞掉
AI 時代,爬蟲思維比以前更重要
最後講一個我覺得很重要的事
傳統爬蟲爬的是 HTML。結構化的、有 DOM 的、可以用 CSS selector 解析的。但我這五條管線抓的是 Email、行事曆、通訊紀錄、錄音逐字稿
這些東西沒有統一格式,有些甚至不是文字
以前每個來源要寫專門的解析器,很麻煩。但現在有多模態 AI,你可以把一段錄音丟給它拿回逐字稿加摘要,把一串信件丟給它提煉出三個待辦事項
爬蟲的骨架(抓 → 解析 → 記進度 → 回報)沒變,但「解析」這一步被 AI 徹底改寫了
以前解析靠 regex 和 parser。現在解析可以是「把原始資料丟給 LLM,讓它幫你理解」
所以任何資訊來源都可以變成你的管線。社群媒體的提及、客戶的語音留言、手寫筆記拍照上傳,框架是同一個,繼承 BasePipeline 就好
爬蟲思維在 AI 時代反而更重要了。不是因為技術變了,是因為能爬的東西變多了
回到那杯咖啡
這篇文章不是在教你寫 Python crawler
重點是那個站在咖啡機前的瞬間。你突然想起自己其實知道答案,只是被工具的速度帶著跑,忘了停下來用腦子
如果你也在用 AI 寫 code,不管是 Claude Code、Cursor、Copilot,我的建議是:
跑起來之後,泡杯咖啡,問自己一個問題:如果沒有 AI,我會怎麼設計這個東西?
你腦子裡的答案,可能比 AI 給你的 code 更值錢
我是 Young,data engineer 出身,現在一個人用 AI 接案,同時管 10 個專案。如果你也在用 AI 開發工具但覺得系統越長越亂,找我聊聊
