! 本篇文章將會介紹 截圖驗證:眼見為憑的自動化驗收,期望大家都能讓每一發自動化動作都留下可稽核、可除錯的證據 :D
你能看到這篇文章,代表昨晚 20:00 那串自動化動作成功了:開頁、填表、點發佈、輪詢 URL。但問題來了——我人在耍廢,沒人盯著螢幕,我要怎麼知道這些動作「真的發生了」,而不是腳本「以為」它們發生了?d17 收尾埋的伏筆今天兌現:把零星使用的 screenshot 升級成整條管線的標準配備。核心觀念一句話:log 告訴你腳本「認為」發生了什麼,截圖告訴你畫面上「實際」發生了什麼。無人值守的自動化系統,存證就是你的眼睛。
讀完這篇你會學到:
ab() 綁定(session 綁 profile,iThelp 登入狀態常駐)/Users/benben/ai/automations/ironman/screenshots/
# 本篇沿用的綁定函式(d16)
ab() { agent-browser --session ithelp --profile "$HOME/.agent-browser-profiles/ithelp" "$@"; }
# 證據集中營:一個只放截圖的資料夾
mkdir -p /Users/benben/ai/automations/ironman/screenshots
隨手拍隨手丟,等於沒拍。排程系統的截圖必須能回答三個問題:**哪一天?哪個流程?幾點幾分拍的?**本系列發文腳本的命名公式:
# publish.sh 的截圖路徑:天數 + 時分秒,同一天跑好幾輪也不會互相覆蓋
SHOT="$ROOT/screenshots/publish-d${DD}-$(date +%H%M%S).png"
"${AB[@]}" screenshot "$SHOT"
跑了一陣子之後,存證資料夾會長成這樣(節錄):
screenshots/
├── publish-d01-200330.png # 20:03:30 的發文現場
├── publish-d01-200330-turnstile-timeout.png # token 逾時當下的失敗現場
├── publish-d01-manual-retry-success.png # 人工搶救成功後補拍
└── publish-d02-200005.png
兩個好處。第一,ls 一眼看完時間軸,出事時間點直接對得上 log;第二,失敗變體用後綴(-turnstile-timeout)接在主檔名後面,同一輪的成功與失敗現場不會散落兩處。
再送一個冷知識:檔案大小是免費的健康檢查。正常頁面的截圖動輒數百 KB 起跳,哪天資料夾裡冒出一張個位數 KB 的,八成拍到的是錯誤頁或空白頁——先看圖再說話,別急著相信 log。
小小小測驗:你知道 log 上寫「發佈成功」,其實只代表腳本自己這樣認為嗎?
答案:log 是單方面的敘事,exit 0 只證明腳本自己沒炸,不證明外部世界真的改變了。驗收要三層交叉:log 記錄腳本做了什麼、URL/eval 讀出頁面的結構事實、截圖保存畫面的視覺事實。三層對得起來,才叫眼見為憑。
以發佈驗收為例,三層長這樣:
# 第一層:log——腳本的敘事(何時點了什麼)
log "點擊發佈(第 ${attempt}/3 次)"
# 第二層:URL——頁面的結構事實(成功特徵:/articles/10xxxx 且沒有 /draft)
AFTER=$("${AB[@]}" get url 2>/dev/null)
[[ "$AFTER" =~ /articles/10[0-9]+$ ]] && PUBLISHED=1
# 第三層:screenshot——視覺事實,成功失敗都拍
"${AB[@]}" screenshot "$SHOT"
還記得 d17 的測驗嗎?「按下去的瞬間,資料還沒離開瀏覽器」。所以第二層的 URL 不是點完馬上讀,而是輪詢到伺服器回話為止:
# 送出後每 5 秒看一次 URL,最多等 30 秒(節錄自 publish.sh)
for i in $(seq 1 6); do
sleep 5
AFTER=$("${AB[@]}" get url 2>/dev/null)
[[ "$AFTER" =~ /articles/10[0-9]+$ ]] && { PUBLISHED=1; break; }
done
三層的分工故意不重疊:log 給時間軸、URL 給機器可判讀的成功訊號(if 判斷用)、截圖給人眼複核(爭議時的仲裁者)。機器自動判斷靠第二層,人類事後驗屍靠第三層,誰也取代不了誰。
成功截圖是放彩帶,失敗截圖是救命繩。原則只有一條:每個 die 之前先拍照。失敗當下的頁面狀態是唯一現場,晚個幾秒 SPA 一跳版,什麼都不剩:
# publish.sh 的失敗分支:先存證,再喊救命(die 會附帶 Discord 告警)
if [[ -n "$PUBLISHED" ]]; then
"${AB[@]}" screenshot "$SHOT"
# …寫 flag、發成功通知…
else
"${AB[@]}" screenshot "$SHOT" # 失敗也要留遺照
die "發佈重試 x3 後 URL 仍異常(${AFTER:-unknown}),請人工確認(截圖:${SHOT})"
fi
# Turnstile token 等不到,放棄前也補拍一張現場,後綴標記失敗原因
"${AB[@]}" screenshot "${SHOT%.png}-turnstile-timeout.png"
實際戰績分享一下:第一天晚上,iThelp 尖峰時段的發佈鈕按下去「靜默無反應」,log 停在「點擊發佈」就沒了下文。隔天早上對著存證資料夾的截圖和 log 交叉比對,確認頁面從頭到尾停在原地——「點擊後輪詢 URL、失敗自動重點」就是那晚之後補上的。d12 講的重試設計,靈感正是來自這張遺照。截圖存證不只是驗收工具,更是系統演化的養分:每張失敗現場照,都是下一版腳本的需求單。
wait 目標元素再拍;導航之後想拍全貌,先 wait --load networkidle 等請求潮退掉。# 只留最近 7 天的例行存證;失敗變體(-timeout、manual-retry)不在比對範圍,人工決定去留
find "$ROOT/screenshots" -name "publish-d*-2*.png" -mtime +7 -delete
ls 就是時間軸下一篇我們要介紹「iT 邦幫忙發文實戰(上):編輯器解析」,終於要開箱本系列的最終戰場——拆解 iThelp 發文頁的結構、markdown 模式與分類選擇,把今天學的驗收招式帶進真實戰場,敬請期待!
參考資料:
有任何疑問但沒有 iT 邦幫忙帳號,或是想匿名提問?
歡迎到 https://dev.benben.me/q/Z5442T 提問或加油打氣,沒意外的話會在完賽之後一起回答 :D