‹ 首页

playwright-cli-cloakbrowser

@tenequm · 收录于 1 周前

Drive CloakBrowser Manager stealth profiles with @playwright/cli over CDP. Use for browser automation that needs a persistent logged-in session, anti-detect fingerprints, or to pass Cloudflare - attach reuses the profile's cookies and stealth where a fresh browser does not.

适合你,如果需要在自动化中绕过反爬并保持登录会话

/ 下载安装
playwright-cli-cloakbrowser.skill双击,或拖进 Claude 桌面版 / Cowork,即完成安装↓ .skill↓ .zip
用别的 agent?下载 .zip 解压,把文件夹放进它的技能目录
Claude Code~/.claude/skills/(项目级 .claude/skills/)
Codex CLI~/.codex/skills/
Cursor自动读取上面两处目录
其他工具见其文档的「skills」目录;两个下载是同一份文件,只是名字不同
/ 通过 npx 安装 校验哈希
npx oh-my-skill add tenequm/skills/playwright-cli-cloakbrowser
/ 通过 bash 安装
curl -fsSL https://oh-my-skill.com/install.sh | bash -s -- tenequm/skills/playwright-cli-cloakbrowser
/ 已经装过?验证本机副本,不用重装
npx oh-my-skill verify tenequm/skills/playwright-cli-cloakbrowser
安装目标可用 --agent / --scope 或 --to 明确指定;省略时只会在唯一已存在的 agent 目录上自动选择,零命中或多命中会停止并提示。content_hash 缺失或不一致均拒装。
29GitHub stars
~2.9K最小装载
~2.9K含声明引用
~5.5K文本包总量
镜像托管

怎么用

技能原文 SKILL.md作者撰写 · Apache-2.0 · ecb77f8

playwright-cli on CloakBrowser stealth profiles

CloakBrowser Manager runs isolated stealth Chromium profiles - unique fingerprint, optional proxy, persistent cookies, built-in noVNC live view - in a single Docker container. Every running profile exposes a CDP endpoint. playwright-cli attach connects to the profile's persistent context (contexts[0]), so automation inherits the profile's logins and stealth fingerprint; playwright-cli open would launch a plain local browser with neither. Always attach for this setup.

No Manager running yet? See [Setting up the Manager](#setting-up-the-manager-local-laptop) below.

For the full command reference, run playwright-cli --help and open the Agent skill: path it prints (the official skill bundled with @playwright/cli). This file only covers the CloakBrowser-specific setup and gotchas.

Connect
# generic: attach to any CDP endpoint
playwright-cli attach --cdp=<CDP_URL>

# CloakBrowser Manager: per-profile CDP endpoint (shown via the toolbar
# code icon while a profile is running)
playwright-cli attach --cdp=http://localhost:8080/api/profiles/<profile-id>/cdp

# then drive normally
playwright-cli goto https://example.com
playwright-cli snapshot                       # a11y tree with refs (e3, e15, ...)
playwright-cli snapshot --depth=6             # bound the tree on huge pages
playwright-cli click e15
playwright-cli --raw eval "document.title"    # --raw = return value only (JSON-serialized), no snapshot noise
playwright-cli detach                         # leave the browser running for next time
  • The profile must be running first - click Launch in the Manager GUI, or curl -X POST http://localhost:8080/api/profiles/<profile-id>/launch.
  • --cdp=<url> and --cdp <url> both work.
  • attach creates an implicit session named default and prints a --s=default hint - that flag is only needed when juggling multiple sessions; plain commands use the default session. -s=<name> opens a second isolated session on the same CDP (e.g. -s=probe for in-page fetch checks while default drives the page).
  • playwright-cli writes a .playwright-cli/ scratch dir (snapshot .yml files, console logs) into the cwd - run from a scratch directory or gitignore it.
  • Never close / close-all / kill-all on an attached stealth profile - that can stop the shared browser and its session. Use detach to leave it running.
Logging into a site

The profile persists cookies, localStorage, and cache across restarts. To establish a login: open the Manager GUI at http://localhost:8080, view the running profile in the built-in noVNC viewer, and sign in there once. playwright-cli then drives the same session logged-in - the VNC view and the CDP connection share one browser.

Importing an existing login (two limits worth knowing):

  • Anti-automation sites (Google, Facebook) may flag the CDP-driven login and not persist a durable session even though the form submits. Bypass: import a real-browser session as Playwright storage-state (playwright-cli state-save/state-load, or capture with npx playwright codegen --save-storage=auth.json <url>) instead of logging in through VNC.
  • A session is often IP-bound: a cookie/state minted at your real location, replayed from a profile whose proxy egress is a different geo, gets forced back to login + 2FA. Transfer only works when the profile's proxy geo matches where the session was created.
Gotchas (all observed in practice)
  1. attach hangs ~30 s, then times out - the profile has a stale or heavy pre-existing tab that never finishes Playwright's connectOverCDP page-init handshake. Fix: close extra tabs via the noVNC view (or stop/relaunch the profile), then re-attach - drops to under a second. A clean about:blank profile attaches instantly.
  2. New-tab creation can be rejected ("Failed to open a new tab") - the stealth browser may forbid Target.createTarget in some states. Prefer navigating the current tab (goto) over tab-new. If a page closes or replaces its own tab (challenge redirects, heavy detail pages), the driver desyncs - just re-attach and continue.
  3. JS-rendered content (prices, dynamic cards) often is not in the a11y snapshot - scrape the DOM with eval: playwright-cli --raw eval "[...document.querySelectorAll('[data-card]')].map(e=>e.innerText)".
  4. Heavy detail pages are slow through a profile proxy and can timeout or desync. Read what you need from the list/results page when possible; treat opening detail pages as best-effort.
  5. Cookie/consent overlays block clicks ("element covered"). Dismiss via JS: playwright-cli eval "document.querySelector('#onetrust-accept-btn-handler')?.click()".
  6. Use --raw whenever scraping or piping - without it output is wrapped in markdown header blocks (### Result, ### Page, ### Snapshot - varies by command), which mangles piping. Even with --raw, eval values come back JSON-serialized (strings quoted).
  7. "Logged in" can be false. A CDP-attached context may render a login form (geo often defaults to US). Verify auth with an eval render check - playwright-cli --raw eval "!!document.querySelector('[href*=logout], [aria-label*=account]')" - not cookie-get, which can read the automation's own blank page and false-negative.
  8. goto may throw TimeoutError on heavy JS sites (it waits on domcontentloaded) yet a follow-up snapshot/eval still returns usable content - a nav timeout is not fatal, retry the read. (Extends gotcha 4.)
  9. click "<CSS selector>" often fails to match even when the element exists. Prefer snapshot eN refs, or click via JS: playwright-cli eval "document.querySelector('...')?.click()".
  10. To wait, poll - do not sleep. Loop on in-page state via eval (document.readyState, element presence) with a bounded max; cap any Cloudflare "Just a moment..." wait explicitly, it is otherwise unbounded.
  11. Browsing a logged-in session can log you out mid-run - anti-automation defenses fire on real activity. Treat a mid-run logout as a site defense, not a tool bug; re-establish the session and slow down.
Patterns for logged-in & JS-heavy sites
  • Reverse-engineer the site's own API. From the logged-in context, call same-origin authenticated endpoints directly - far more robust than DOM scraping: ```bash playwright-cli -s=probe --raw eval "(async()=>await (await fetch('/api/whatever',{headers:{'X-Requested-With':'XMLHttpRequest'}})).json())()" ``` Discover the endpoints by monkeypatching fetch first: eval "window.__u=[];const f=fetch;window.fetch=(...a)=>{window.__u.push(a[0]?.toString?.()||a[0]);return f(...a)}", exercise the page, then read window.__u.
  • Use CDP-level network inspection when in-page hooks fall short. A page reload wipes an injected fetch/XHR hook, and service-worker / iframe traffic is invisible to a main-context hook. Use playwright-cli requests then playwright-cli --raw response-body <id> to capture what the page actually fetched.
  • Lazy-loaded lists: scroll-until-count, not fixed sleeps. Loop: scroll, poll the item count, stop on no-growth OR target OR max-rounds. For content inside a scrollable element, scroll that element's scrollHeight, not the window: ```bash playwright-cli --raw eval "(async()=>{let p=0;for(let i=0;i<30;i++){scrollTo(0,document.body.scrollHeight);await new Promise(r=>setTimeout(r,700));const n=document.querySelectorAll('[data-card]').length;if(n===p)break;p=n}return p})()" ```
  • Retry hard blocks with a fresh exit IP. On 403/429/503/empty content, retry once against a fresh context so a rotating proxy picks a new exit IP (only helps if the profile's proxy rotates).
Minimal working pattern
CDP=http://localhost:8080/api/profiles/<profile-id>/cdp
playwright-cli attach --cdp=$CDP
playwright-cli goto "https://www.amazon.com/s?k=iphone+16+pro+max"
playwright-cli --raw eval "[...document.querySelectorAll('[data-asin]')].slice(0,5).map(e=>e.innerText.split('\n')[0]).join(' | ')"
playwright-cli detach   # leave the stealth browser running
Setting up the Manager (local laptop)

Requirements: Docker 20.10+, ~2 GB disk (the image bundles the CloakBrowser binary; the Manager is ready seconds after start), ~512 MB RAM per running profile.

docker run -d -p 8080:8080 -v cloakprofiles:/data cloakhq/cloakbrowser-manager

Binds to localhost. If 8080 is taken, map another host port (-p 18080:8080) and adjust every URL in this file accordingly. Profiles, cookies, and session data live in the cloakprofiles volume and survive container updates (docker pull cloakhq/cloakbrowser-manager + recreate). By default there is no authentication - fine for local use; add -e AUTH_TOKEN=your-secret-token to protect it, and pass Authorization: Bearer <token> on API calls.

Open http://localhost:8080 - the Manager web GUI. Create a profile (set proxy, timezone, and locale together if you need specific geo) and click Launch. Or headless via API:

# create -> returns {"id": "<profile-id>", ...}
curl -s -X POST http://localhost:8080/api/profiles \
  -H 'Content-Type: application/json' \
  -d '{"name": "agent", "platform": "macos"}'

# launch
curl -s -X POST http://localhost:8080/api/profiles/<profile-id>/launch

# list profiles / find the id later
curl -s http://localhost:8080/api/profiles

The noVNC live view is built into the GUI: click the running profile to watch and interact with the browser in a tab. Use it to log into sites once, watch automation live (VNC and CDP share the same browser), and clear stuck tabs when attach hangs (gotcha 1).

Playwright/Puppeteer scripts work against the same CDP URL:

const { chromium } = require("playwright");
const browser = await chromium.connectOverCDP(
  "http://localhost:8080/api/profiles/<profile-id>/cdp"
);
const page = browser.contexts()[0].pages()[0];
await page.goto("https://example.com");
Remote Manager on a Linux VM over SSH

The same setup runs on any Linux VM you can SSH into - a VPS, home server, or cloud instance. Size it at ~512 MB RAM per running profile plus ~1 GB for the Manager itself.

On the VM:

# install Docker (Ubuntu/Debian; skip if present)
curl -fsSL https://get.docker.com | sh

# run the Manager, localhost-bound so nothing is exposed publicly
docker run -d --restart unless-stopped --name cloakbrowser \
  -p 127.0.0.1:8080:8080 -v cloakprofiles:/data cloakhq/cloakbrowser-manager

On your laptop:

ssh -L 8080:localhost:8080 user@vm

Everything above now works unchanged: the GUI, the noVNC login flow, and the CDP endpoint all ride the same tunneled port, so playwright-cli attach --cdp=http://localhost:8080/api/profiles/<id>/cdp is identical to the local case. Binding to 127.0.0.1 on the VM makes the SSH tunnel the auth boundary, so AUTH_TOKEN stays unnecessary.

If you must expose the Manager directly instead (no tunnel), set AUTH_TOKEN and put it behind an HTTPS reverse proxy - but note that playwright-cli attach cannot inject a Bearer header on the CDP WebSocket, so a token-protected Manager needs a small local proxy in front that injects the header. Prefer the tunnel.

Notes
  • Egress IP is whatever the profile's proxy is set to (or the Docker host's IP with no proxy). Sites see that location for geo, currency, and language - configure the profile's proxy, timezone, and locale together in the Manager. To force English on a geoip'd EU marketplace, a &language= URL param is not enough; override the header (route/run-code with Accept-Language: en-GB,en;q=0.9).
  • One profile = one persistent identity. Use separate profiles for separate accounts; that is the point of the Manager.
  • CloakBrowser is the stealth Chromium engine; cloakbrowser.dev is the project site. The Manager GUI is MIT; the CloakBrowser binary has its own license.
按 Apache-2.0 许可原样转载,未经改动 · 在 GitHub 查看 →

评论

登录即可评论;带「已验证安装」的,是发布者名下有本店的安装或持有记录。