管過 400 隻爬蟲的人,被 Vibe Coding 帶溝裡了
AI 開發實踐·12 分鐘

管過 400 隻爬蟲的人,被 Vibe Coding 帶溝裡了

我在外商管過 400+ 電商爬蟲,用過 Airflow、dbt,對 pipeline 架構很熟。但用 Claude Code vibe coding 自己的工具時,我忘了這一切。三次重構失敗,最後回到爬蟲思維才解決

Y
Young Tsai

先說一下背景

我在外商做過 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 開發工具但覺得系統越長越亂,找我聊聊

claude-codeshell-scriptpythonrefactoringcrawler-patternfreelancedata-pipeline