! 本篇文章將會介紹 網頁填表實戰:教 Agent 填表格,期望大家都能讓 Agent 在慢網路下也把表格填得又穩又準 :D
d16 收工時,Agent 已經能以「老熟人」的身分喚起瀏覽器——登入這關過了,但登入只是起點,真正的戰場是表格本身。本系列每天 20:00 的發文管線,核心動作說穿了就是「填兩個欄位、按一次送出」,聽起來小學生等級,實際踩下去才發現坑全集中在兩件事上:定址(元素到底怎麼指認)跟時序(什麼時候可以動手)。d15 的測驗埋過一句伏筆:「W3 會花一整天教 selector 跟等待策略」——就是今天。我們拿一張公開的練習表單把招式全部跑過一遍,d19、d20 拆 iThelp 編輯器時直接見真章。
讀完這篇你會學到:
ab() 函式:session 與 profile 綁定。練習頁雖然不用登入,紀律照走# d16 的綁定函式,本篇沿用
ab() { agent-browser --session ithelp --profile "$HOME/.agent-browser-profiles/ithelp" "$@"; }
指認元素有兩種模式:
input[name='custname'] 這種地址。寫進腳本可以重跑一百次都不必先看頁面;代價是你得先知道地址長怎樣,而且地址本身可能隨時搬家。選用心法一句話:探索用 @ref,腳本錨點用 selector。先用 snapshot 看清地形,找到真正穩定的元素後(id、name、data-testid 這類語意屬性),寫死進腳本;@ref 留給臨場反應。實際看一下練習頁的地形:
ab open https://httpbin.org/forms/post
ab snapshot -i -s "form" # 只看表單範圍,輸出精簡(簡化示意)
# @e1 [textbox] "Customer name"
# @e7 [radio] "Large"
# @e10 [checkbox] "Bacon"
# @e14 [button] "Order Pizza"
# 兩種寫法等價;寫進排程腳本建議用第二種,跨 snapshot 穩定
ab fill "@e1" "鐵人 Agent"
ab fill "input[name='custname']" "鐵人 Agent"
那 class 呢?醒醒,現代前端框架的 class 是編譯產物(css-1x2y3z 這種雜湊),下次部署就換一批。拿 class 當腳本錨點,等於把排程腳本綁在流沙上。
定址搞定,各類欄位各有一套正確姿勢:
# 文字框:fill 會先清空再填入,重跑安全(d15 老朋友)
ab fill "input[name='custname']" "鐵人 Agent"
ab fill "input[name='custemail']" "agent@example.com"
# 單選/多選:沒有 fill 的份,就是 click
ab click "input[value='large']" # 大披薩
ab click "input[value='bacon']" # 加培根
# 下拉選單:用 select 指定 option 的 value(value 以實際頁面為準)
ab select "select[name='delivery']" "18:00"
# 多行文字:textarea 一樣用 fill
ab fill "textarea[name='comments']" "請放門口,謝謝"
兩個細節。第一,fill 跟 type 的分工 d15 提過:fill 清空再填、適合表單;type 是疊打,留給 autocomplete 這種要逐字觸發聯想選單的欄位。第二,click 是切換不是設定——checkbox 已經被勾選時,再 click 一次是「取消勾選」。互動時這是 feature,在會重跑的排程腳本裡是炸彈:腳本重試第二次,培根就被退訂了。保險做法是出手前先驗狀態:
# 已勾選就跳過,讓每個動作可安全重跑(冪等)
ab eval "document.querySelector(\"input[value='bacon']\").checked ? 'CHECKED' : 'NOT_YET'"
小小小測驗:你知道按下送出鈕的那一瞬間,資料其實還沒離開瀏覽器嗎?
答案:click 只是請瀏覽器「開始」送出——表單驗證、JavaScript 前處理、HTTP 請求都還在跑。所以送出後的等待與驗證不可省,不然你驗收的是一個還在半路上的答案。這就帶到今天的第三招。
launchd 在 20:00 叫醒的 headless 瀏覽器,網路狀況沒人看得到。傻等固定秒數是最該淘汰的策略:等太短照樣搶拍、等太長天天浪費壽命。把等待分成三級,按需要取用:
# Level 0:固定傻等——只該出現在「就是想緩一下」的場合
ab wait 500
# Level 1:等元素——等「下一個要操作的那個」出現,日常主力
ab wait "textarea[name='comments']"
# Level 2:等網路——導航或送出之後,等請求潮退掉再動作
ab wait --load networkidle
原則:等你要操作的那個元素,而不是等整頁「感覺」載好了。整組串起來就是一輪完整實戰:
ab open https://httpbin.org/forms/post
ab wait "input[name='custname']" # 欄位長出來才動手
ab fill "input[name='custname']" "鐵人 Agent"
ab click "input[value='large']"
ab click "input[value='bacon']"
ab fill "textarea[name='comments']" "請放門口,謝謝"
ab snapshot -i -s "form" # 送出前最後一眼,順便領按鈕的 ref
ab click "@e14" # 點「Order Pizza」(ref 以實際 snapshot 為準)
ab wait --load networkidle # 等請求潮退
ab get text "pre" # httpbin 會回顯你送出的 JSON,肉眼可驗
最後那個回顯很重要:httpbin 會把你送出的表單內容原封不動印回來,一眼就能核對「培根有沒有上車」。「資料真的被收下」要有證據,這就是最樸素的證據——等 d18 講截圖驗證,會把存證這件事升級成標準配備。
下一篇我們要介紹「截圖驗證:眼見為憑的自動化驗收」,今天零星用的 screenshot 要升級成標準配備——每一步存證,讓自動化作業可稽核、可除錯,敬請期待!
參考資料:
有任何疑問但沒有 iT 邦幫忙帳號,或是想匿名提問?
歡迎到 https://dev.benben.me/q/Z5442T 提問或加油打氣,沒意外的話會在完賽之後一起回答 :D