sandbox_shot

截箱子的畫面、最前面的視窗、用新開的瀏覽器打開的網址,或箱子裡瀏覽器已經開著的分頁;也能一次截好幾頁,或把畫面錄成 mp4。

輸入 輸出
id、target(screen、window、url 或 tab)、url、urls、width、height、deviceScaleFactor、mobile、fullPage、tab、port、reset、waitFor、stableMs、record(start 或 stop) 截圖直接附在結果裡,另有 url(1 小時有效;https://api.parallelsandbox.com/v1/files/…,打開時會轉址到儲存空間)、bytes、expiresAt、capturedAt、path,有的時候才有 window、windows、clipped、viewport、tab、waitFor、stable、loadError、pageErrors、takeover;urls 時不附圖,回 files[](每頁的 url、path、bytes、capturedAt,頁面報了錯再加 pageErrors);record: "stop" 回 mp4 的 url(同一種,1 小時有效)
  • 不帶 record:截圖,直接附在結果裡,另給一小時有效的網址,附 capturedAt,也就是拍下的時間。path 是這張圖在箱子裡的副本,放在 /work/.sbx/shots/(相對 /work;留最新的 100 張):要留下圖檔本身或轉給別人時,用 sandbox_pull 或 sandbox_get 拿它。
  • 有人接手箱子時,target: "screen"、"window" 與 "url" 照樣拍,結果帶 takeover: true:拍到的就是人眼前的畫面。target: "tab" 跟 sandbox_exec 一樣要等人交還,因為它會改到人可能正在用的分頁。
  • target: "screen"(預設)截虛擬螢幕,螢幕是 390 × 844 直向,箱子用 orientation: "landscape" 開的才是 1280 × 800。target: "window" 只截最上層的視窗(不含桌面),結果多一個 window,是視窗在螢幕上的 x,y,寬,高(例如 "100,80,900,600"):要照圖上的座標點擊,先加上 x 與 y;比螢幕大的視窗只截螢幕上那一塊,clipped 會註明。windows 列出螢幕上所有看得見的視窗,拍的那個排第一,每個有 id、name、x、y、width、height,程式有報的話還有開它的 pid:程式不結束視窗就一直在,收尾前用它確認自己開的都關了(用 background: true 開的,sandbox_procs 的 stop 收掉;任何一個都能用 xdotool windowkill <id> 關)。這兩種都能給 stableMs(100 到 10000):畫面這麼久沒變才拍,換頁或動畫就不會拍到一半;最多等 20 秒,等不到就回最後一格,stable.settled 是 false。
  • target: "url" 開一個新的、沒登入的 headless Chromium 打開 url 再截。width 與 height 以 CSS 像素設 viewport(預設是箱子的螢幕大小:直向 390 × 844、橫向 1280 × 800;只給 width 時高度照螢幕),頁面就照這個寬度排,比 Chromium 視窗最窄的 500 像素還窄也行:看手機或平板版面就用它(width: 390, height: 844)。deviceScaleFactor(0.5 到 4,iPhone 例如 3)讓圖是 viewport 的那麼多倍,mobile: true 模擬有觸控的手機,所以不會有 hover,沒有 <meta name=viewport> 的頁面會像真的手機一樣排成 980 像素寬。fullPage: true 截整頁,不只視窗(height 就不管了)。打不開的頁面回 loadError。給 urls(網址清單)就一次拍好幾頁(同樣大小的共用一個瀏覽器):圖不附在結果裡,寫在箱子的 /work/.sbx/shots/,結果的 files[] 列出每一頁的 url、path(相對於 /work)、bytes 與 capturedAt,要看哪張就用 sandbox_get 拿(paths 一次拿好幾張)。這種一次拍好幾頁的只記成一步(summary 像 2 urls),沒有圖:人在 app 裡看不到那些圖,/media 也沒有,它們跟 /work 一起在箱子停掉時消失。
  • target: "tab" 照原樣截箱子裡瀏覽器已經開著、還登入著的分頁:不捲動、不動滑鼠,所以 hover 的狀態會留在圖裡。那個瀏覽器要帶 --remote-debugging-port=9222 開(Electron 用同一個參數);箱子裡有好幾個瀏覽器開了除錯埠時用 port 指定,還在開的瀏覽器最多等 45 秒,開完不用 sleep。tab 用分頁的 id 或網址、標題的一部分挑分頁(預設:viewport 被撐住的那個分頁,否則最近用過的那個),結果的 tab 說拍了哪一個。width 讓那個分頁的 viewport 變成這麼寬,height(預設:視窗本身的高度)、deviceScaleFactor 與 mobile 同上,箱子會一直撐住,直到 reset: true、分頁關掉或瀏覽器結束,所以你繼續在分頁裡點、打字,手機版面都不會變回去(你自己的 CDP 腳本下的 Emulation.setDeviceMetricsOverride,連線一關就失效)。每次帶 width、height、deviceScaleFactor 或 mobile 的呼叫都會換掉整組模擬的 viewport,一次只撐住一個分頁;結果的 viewport 是頁面實際看到的大小。
  • waitFor,搭配 target: "url" 或 "tab":等這個 CSS 選擇器對到看得見的元素才拍,或加 js: 前綴,等這段 JavaScript 運算式為真才拍(可以 await)。最多等 30 秒;一直不成立也照樣回截圖,waitFor.met 是 false;條件本身寫錯會回錯。
  • pageErrors,搭配 target: "url" 或 "tab":頁面自己報的錯。console 是 console.error、沒通過的 console.assert、沒接住的例外(附腳本與行號),以及瀏覽器擋下的事(例如違反 Content Security Policy);failedRequests 是沒載入成功的資源,網址後面接原因(net::ERR_NAME_NOT_RESOLVED、the server responded with a status of 404 (Not Found))。每類列最先的 10 筆、每筆最多 300 字,more 是其餘的筆數;頁面什麼都沒報就沒有 pageErrors。範圍是現在這一頁、從它最後一次換頁算起:target: "tab" 也包括呼叫之前發生的,卡在載入畫面的頁面看得出原因。
sandbox_exec { "id": "<id>", "cmd": "chromium --no-sandbox --remote-debugging-port=9222 --user-data-dir=/tmp/chrome http://localhost:5173/", "background": true, "note": "在箱子的瀏覽器打開 app" }
sandbox_shot { "id": "<id>", "target": "tab", "width": 390, "height": 844, "mobile": true, "deviceScaleFactor": 3, "waitFor": "nav [aria-label='Menu']" }
sandbox_shot { "id": "<id>", "target": "tab", "waitFor": "js:document.querySelectorAll('.order').length > 0" }
sandbox_shot { "id": "<id>", "target": "tab", "reset": true }
  • 要自己把頁面留在箱子螢幕上(一個你要繼續操作的 Chromium),照螢幕方向帶對參數開 Chromium;見 sandbox_exec 的「箱子螢幕上的瀏覽器」。
  • record: "start" 開始把螢幕錄成 mp4;record: "stop" 結束並回它的下載網址,一小時有效。錄影會讓箱子不凍結,但只撐到箱子最後一次使用(會動到箱子的工具呼叫結束或喚醒,見箱子狀態)起算滿 1 小時為止,背景命令也是撐到同一個時間;最後一次使用是前景命令的話,這 1 小時從那個命令跑完的那一刻算起。錄影本身錄了多久不影響。過了之後,等到沒有別的東西讓箱子醒著(前景命令、有人接手等,見箱子狀態),ParallelSandbox 會停掉錄影、不上傳,箱子照常凍結;mp4 留在箱子的 /work/.sbx/rec/rec-<unix 時間>.mp4,用 sandbox_get 拿(箱子凍結著也沒關係,這個呼叫本身就會把它喚醒)。被自動停掉的錄影不會成為一步:app 與 /media 都看不到,沒取出的話,箱子停掉時跟 /work 一起消失。用 sandbox_get 取出的副本是暫存檔,約一天後自動刪除、不計檔案保存量(見點數)。要留下來,請在停箱前下載;停箱後不能重取網址。
  • 從錄影抽一張畫面存成單一圖檔:ffmpeg -ss 5 -i in.mp4 -frames:v 1 -update 1 out.png(-update 1 讓它寫成一個檔,而不是要 out%03d.png 這種編號樣式)。箱子裡有 ffmpeg。
  • 每張截圖、每段用 record: "stop" 停掉的錄影也會記成箱子的一步,人在 app 裡這個箱子的「截圖與錄影」看得到(箱子停掉後仍可在「已停止(7 天內)」查看,見 sandbox_exec);檔案 7 天後刪除。用 urls 一次拍好幾頁的是例外:整批只記成一步、沒有圖,見上面。網址過了一小時要重拿(再叫一次 sandbox_shot 拍的是新的畫面,拿不回舊的):帶 API key(Authorization: Bearer <key>)呼叫 GET https://api.parallelsandbox.com/v1/boxes/{id}/media(只有 REST,沒有對應的 MCP 工具),它回這個箱子最近 7 天內拍下、有畫面的步驟,最多最新的 200 步、舊的在前,箱子停掉了也一樣:{"keepDays": 7, "steps": [...]}。每一步的欄位跟 sandbox_status 的 steps[] 一樣,另有 media[]:每一個有 kind(video 或 image)、url、bytes,影片還有 durationSec;url 每次呼叫都重簽,至少一小時有效(見 REST)。各種畫面留多久、箱子停掉之後誰還看得到,總表在收尾。

所有工具與主題都列在工具參考。