! 本篇文章將會介紹 Persistent profile:登入一次,永久 headless,期望大家都能讓 Agent 每天醒來就已經是登入狀態,無人值守直接開工 :D
d15 結尾留了一道伏筆:headless 瀏覽器每次醒來都是全新的,登入狀態不會留下。這對互動式操作是小事,對本系列卻是生死題——這套「opencode 生成 + launchd 排程 + agent-browser 發文」的系統,每天 20:00 要自己醒來把文章發上 iT 邦幫忙,而發文需要登入。總不能請 launchd 彈一個登入視窗叫我輸密碼,那還叫耍廢自動化嗎(笑)。今天的主角是 agent-browser 的 --profile:人類只登入一次,之後永久 headless,機器每天以「老熟人」的身分開工。
讀完這篇你會學到:
--profile 建立持久化使用者資料檔,走完「一次手動登入 → 之後永遠 headless」的完整流程# 確認 d15 的安裝還在
agent-browser --version
先親眼確認一次問題。不帶任何參數開 iT 邦首頁:
# 不帶 --profile:每次都是一顆全新的瀏覽器
agent-browser open https://ithelp.ithome.com.tw
agent-browser snapshot -i # 頁面上看得到「登入/註冊」→ 在機器眼裡你是陌生人
agent-browser close # 收工,cookie 跟著蒸發
原因在 d15 其實已經埋好了:agent-browser 的 daemon 閒置約一小時會自動收工,下次有指令再叫起新的瀏覽器。cookie 和網站寫進來的各種狀態都活在那顆瀏覽器的記憶體裡,daemon 一收工就歸零——所以排程腳本每次醒來,都是一個網站不認識的陌生人。互動時沒差(反正你人在),無人值守時就是死刑:20:00 醒來的 Agent 對著發文頁,只會被導去登入頁,然後卡死在那裡。
解法很直觀:給瀏覽器一個固定的「家」。--profile 後面接一個目錄路徑(也可以用 AGENT_BROWSER_PROFILE 環境變數指定),agent-browser 會把它當成 Chrome 的使用者資料檔來用——cookie、localStorage、網站塞進瀏覽器的各種登入狀態,全部持續寫進這個目錄。下次任何指令帶上同一個路徑,喚醒的就是「上次那個人」。
實戰分兩幕。第一幕是一次性的手動登入:
mkdir -p ~/.agent-browser-profiles
# 第一幕(只做一次):--headed 開出視窗,手動登入
# 2FA、圖形驗證都自己在這一步過掉
agent-browser --session ithelp \
--profile "$HOME/.agent-browser-profiles/ithelp" \
--headed open https://ithelp.ithome.com.tw
# 登入完成、看到自己的暱稱後收工,狀態已寫進 profile 目錄
agent-browser --session ithelp close
第二幕是之後的每一天:
# 第二幕(每天 20:00 的現實):不開視窗,headless 直接開工
agent-browser --session ithelp \
--profile "$HOME/.agent-browser-profiles/ithelp" \
open https://ithelp.ithome.com.tw
agent-browser snapshot -i # 「登入」按鈕消失、看得到暱稱 → 已登入
agent-browser --session ithelp close
魔法就這麼樸素。不過要把這套用進無人值守腳本,先立一條紀律:session 和 profile 成對出現、路徑寫死。本系列的做法是包成一個小函式,之後所有指令都走它:
# ab = agent-browser + 固定的 session/profile 綁定,杜絕手殘打錯路徑
ab() { agent-browser --session ithelp --profile "$HOME/.agent-browser-profiles/ithelp" "$@"; }
ab open https://ithelp.ithome.com.tw # 之後都用 ab 開工
小小小測驗:你知道
--profile存起來的不只是 cookie 嗎?
答案:它保存的是一整份 Chrome 使用者資料檔——cookie、localStorage、還有網站寫進瀏覽器的各種狀態。所以現在流行的 SPA 就算把 token 放在 localStorage 而不是 cookie,也一樣罩得住。反過來說,這個目錄等於「你在該網站的數位分身」,要當機敏檔案看待:路徑固定、權限鎖好,絕對別把它 commit 進 git。
「永久」要打引號:網站的 session 有自己的壽命,幾週後掉出登入是正常例行公事,不是系統壞掉。重點是讓機器在做事之前先發現,而不是填表填到一半才炸——這正是 d12 錯誤處理與 d13 告警的延長線:
# Preflight:開頁後先問一句「我還登入著嗎?」
ab open https://ithelp.ithome.com.tw && sleep 3
ab eval "document.body.innerText.includes('登入') ? 'EXPIRED' : 'OK'"
判斷條件每家網站不同,這裡用「頁面上還找不找得到登入入口」當通用訊號;iThelp 的精準判斷式等 d19 拆完編輯器再定案。原則是寧可誤報也不要漏報:腳本裡只要驗到 EXPIRED 就走 d13 的 Discord webhook 叫人回來,人工補登入就是把第一幕 --headed 那組指令重跑一次,兩分鐘結束,系統又能安靜跑好幾週。這是本系列全自動設計裡少數合法的人工介入點。
順帶一提,如果只是想記住狀態、不需要完整的使用者資料檔,agent-browser 還有個輕量替代方案 --restore:自動把 cookies 和 localStorage 存檔,下次以 session 名稱為鑰匙自動回放。本系列選 --profile,因為它保存得最完整,行為最接近一顆從來沒關過的瀏覽器。
--profile,開起來卻還是沒登入?--profile 認的是「目錄」,路徑差一個字就是另一個平行宇宙的瀏覽器,各自有各自的記憶。解法就是上面的紀律:路徑寫死、包成 ab() 函式,或用 AGENT_BROWSER_PROFILE 環境變數固定下來,讓手殘物理上不可能發生。--profile 也接受 Chrome 既有 profile 名稱(如 Default),但 Chrome 的使用者資料目錄同時只能被一顆瀏覽器鎖定——你正開著 Chrome,自動化再去開同一個目錄就會打架。給機器人專用的獨立目錄,跟人類的瀏覽器完全隔離,才是無人值守的正解。--allowed-domains 限縮 profile 的活動範圍,結果起不來?--allowed-domains 的說明寫明會拒絕 profiles、restore 這類「狀態重放」機制,兩者不能同時用。想兩全,得在腳本層自己管 URL 白名單——這筆帳 d27 講安全煞車時會回來算。--profile 把使用者資料檔釘在磁碟:一次 --headed 手動登入,之後永久 headless 直接開工ab() 函式綁定 session/profile、preflight 健檢接 d13 告警;輕量需求可改用 --restore
下一篇我們要介紹「網頁填表實戰:教 Agent 填表格」,登入只是起點,真正的戰場是表格本身——selector、snapshot ref、等待策略,讓填表又穩又準,敬請期待!
參考資料:
有任何疑問但沒有 iT 邦幫忙帳號,或是想匿名提問?
歡迎到 https://dev.benben.me/q/Z5442T 提問或加油打氣,沒意外的話會在完賽之後一起回答 :D