first commit
This commit is contained in:
172
devops/playwright-browser-install/SKILL.md
Normal file
172
devops/playwright-browser-install/SKILL.md
Normal file
@@ -0,0 +1,172 @@
|
||||
---
|
||||
name: playwright-browser-install
|
||||
description: Install, diagnose, and recover Playwright browser binaries (Chromium, Firefox, WebKit) — partial downloads, resume, cache management, and sandbox issues.
|
||||
triggers:
|
||||
- "playwright install chromium"
|
||||
- "playwright install firefox"
|
||||
- "playwright install webkit"
|
||||
- "playwright browser download failed"
|
||||
- "playwright chromium not found"
|
||||
- "chrome binary missing"
|
||||
- "playwright download interrupted"
|
||||
---
|
||||
|
||||
# Playwright Browser Install — Diagnosis & Recovery
|
||||
|
||||
## Pitfalls
|
||||
|
||||
### Chrome sandbox 在容器/VM 中失败
|
||||
**Symptom**: `browser_navigate` 报错 "No usable sandbox! If you are running on Ubuntu 23.10+ or another Linux distro that has disabled unprivileged user namespaces with AppArmor"
|
||||
|
||||
**Root cause**: 容器或 VM 环境中 Chrome 的 sandbox 机制不可用。
|
||||
|
||||
**Workaround**:
|
||||
```bash
|
||||
# 在 ~/.bashrc 中添加
|
||||
echo 'export PLAYWRIGHT_CHROMIUM_ARGS="--no-sandbox --disable-setuid-sandbox"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
# 或直接用 playwright-core 调用
|
||||
cd ~/.hermes/hermes-agent && node -e "
|
||||
const { chromium } = require('playwright-core');
|
||||
(async () => {
|
||||
const browser = await chromium.launch({
|
||||
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
await page.goto('https://example.com');
|
||||
const text = await page.textContent('body');
|
||||
console.log(text);
|
||||
await browser.close();
|
||||
})().catch(e => console.error(e.message));
|
||||
"
|
||||
```
|
||||
|
||||
**注意**: `browser_navigate` 工具可能不支持自定义 Chrome 参数,此时需要用上述 playwright-core 直接调用。
|
||||
|
||||
## Quick Diagnosis
|
||||
|
||||
```bash
|
||||
# Check which browsers are installed
|
||||
ls ~/.cache/ms-playwright/
|
||||
|
||||
# Check if a specific browser process is running
|
||||
ps aux | grep playwright | grep -v grep
|
||||
|
||||
# Check download temp dirs (partial downloads accumulate here)
|
||||
ls -la /tmp/playwright-download-*/
|
||||
|
||||
# Find largest partial zip (likely the interrupted download)
|
||||
for d in /tmp/playwright-download-*; do
|
||||
f="$d/playwright-download-chromium-"*.zip
|
||||
test -f "$f" && echo "$(du -sh "$f" | cut -f1) $d"
|
||||
done | sort -rh | head
|
||||
```
|
||||
|
||||
## Finding the Actual CDN Download URL
|
||||
|
||||
Playwright CDN redirects through several hosts. The final destination (which supports Range/resume) is **storage.googleapis.com**.
|
||||
|
||||
```bash
|
||||
# Method: use the playwright CLI with verbose to see the URL
|
||||
# Or extract from browsers.json
|
||||
node -e "const b=require('$HOME/.hermes/hermes-agent/node_modules/playwright-core/browsers.json'); const c=b.find(x=>x.name==='chromium'); console.log(c.browserVersion, c.revision)"
|
||||
|
||||
# Then construct the URL:
|
||||
# https://storage.googleapis.com/chrome-for-testing-public/{browserVersion}/linux64/chrome-linux64.zip
|
||||
```
|
||||
|
||||
For Chromium revision 1217 → browserVersion **147.0.7727.15**
|
||||
|
||||
## Resume a Partial Download (curl)
|
||||
|
||||
1. Identify the largest partial zip in `/tmp/playwright-download-*/`
|
||||
2. Copy it to a safe location
|
||||
3. Use `curl -C -` for automatic resume (reads existing file size and sends `Range` header):
|
||||
|
||||
```bash
|
||||
PARTIAL_ZIP="/tmp/playwright-download-XRveVR/playwright-download-chromium-ubuntu24.04-x64-1217.zip"
|
||||
OUTPUT="/tmp/playwright-chromium-resume.zip"
|
||||
URL="https://storage.googleapis.com/chrome-for-testing-public/147.0.7727.15/linux64/chrome-linux64.zip"
|
||||
|
||||
cp "$PARTIAL_ZIP" "$OUTPUT"
|
||||
nohup curl -L -C - -o "$OUTPUT" "$URL" &
|
||||
```
|
||||
|
||||
**Important:** The `-o` flag in `curl` truncates the output file on start. `curl -C -` auto-detects existing file size and resumes from that position, but only if the file already exists. The `-L` follows redirects (needed because the CDN URL 307-redirects to storage.googleapis.com).
|
||||
|
||||
## Manual Installation from Downloaded Zip
|
||||
|
||||
If Playwright's install process keeps overwriting your manual extraction:
|
||||
|
||||
```bash
|
||||
BROWSER_DIR="$HOME/.cache/ms-playwright/chromium-1217"
|
||||
mkdir -p "$BROWSER_DIR"
|
||||
unzip -q /path/to/downloaded.zip -d "$BROWSER_DIR"
|
||||
touch "$BROWSER_DIR/.ready"
|
||||
ln -sf chrome-linux64 "$BROWSER_DIR/chrome"
|
||||
```
|
||||
|
||||
# The `.ready` marker file tells Playwright the browser is already installed.
|
||||
|
||||
## Headless Shell — Separate Installation
|
||||
|
||||
Playwright needs **both** `chromium-1217/` (chrome binary) and `chromium_headless_shell-1217/` (headless shell). The headless shell is a separate ~112MB download:
|
||||
|
||||
```bash
|
||||
# URL format (same browserVersion as chromium):
|
||||
# https://storage.googleapis.com/chrome-for-testing-public/{browserVersion}/linux64/chrome-headless-shell-linux64.zip
|
||||
|
||||
BROWSER_VER="147.0.7727.15" # from browsers.json
|
||||
HEADLESS_ZIP="/tmp/chrome-headless-shell.zip"
|
||||
HEADLESS_DIR="$HOME/.cache/ms-playwright/chromium_headless_shell-1217"
|
||||
|
||||
curl -L -o "$HEADLESS_ZIP" "https://storage.googleapis.com/chrome-for-testing-public/${BROWSER_VER}/linux64/chrome-headless-shell-linux64.zip"
|
||||
mkdir -p "$HEADLESS_DIR"
|
||||
unzip -q "$HEADLESS_ZIP" -d "$HEADLESS_DIR"
|
||||
touch "$HEADLESS_DIR/.ready"
|
||||
ln -sf chrome-headless-shell-linux64 "$HEADLESS_DIR/chrome-headless-shell"
|
||||
```
|
||||
|
||||
## Playwright Overwrites Cache Directory
|
||||
|
||||
⚠️ **Critical:** When you run `playwright install chromium`, it creates a **fresh temp directory** each time (using `mkdtemp`), downloads there, then moves to the cache. If you manually extracted to `~/.cache/ms-playwright/chromium-1217/` and then run `playwright install`, it will **delete and recreate that directory** — wiping your manual extraction.
|
||||
|
||||
**Workaround:** Run `playwright install` first and let it complete. If interrupted, re-extract after each `playwright install` run.
|
||||
|
||||
## Verify Installation
|
||||
|
||||
```bash
|
||||
# Via Playwright API
|
||||
node -e "const {chromium}=require('playwright-core'); console.log(chromium.executablePath())"
|
||||
|
||||
# Direct binary test
|
||||
"$HOME/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome" --version
|
||||
```
|
||||
|
||||
## Common Failure Modes
|
||||
|
||||
| Symptom | Cause | Fix |
|
||||
|---------|-------|-----|
|
||||
| `playwright install` hangs at 0% | Network/DNS issue, bad CDN mirror | Set `PLAYWRIGHT_DOWNLOAD_HOST` env var |
|
||||
| Download starts but never completes | Server-side timeout, partial file left in `/tmp/` | Resume from partial using `curl -C -` |
|
||||
| "Chrome binary not found" after install | `.ready` marker missing or wrong dir name | Create marker, check `chromium-{revision}` dir name |
|
||||
| `chrome: command not found` | Sandbox/suffix issues | Check `chrome-linux64/chrome` exists and is executable |
|
||||
| Playwright reinstalls even though browser exists | `.ready` marker missing | `touch "$BROWSER_DIR/.ready"` |
|
||||
| Headless shell not found | Headless shell is a **separate install** from chromium — both are needed | Install headless shell manually from `chrome-headless-shell-linux64.zip` (same browserVersion as chromium) |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST # Override CDN for Chromium
|
||||
PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST # Override CDN for Firefox
|
||||
PLAYWRIGHT_DOWNLOAD_HOST # Override CDN for all browsers
|
||||
PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT # Socket timeout in ms
|
||||
```
|
||||
|
||||
## Key Paths
|
||||
|
||||
- Browser cache: `~/.cache/ms-playwright/`
|
||||
- Temp downloads: `/tmp/playwright-download-*/` (deleted on system reboot)
|
||||
- Playwright node_modules: `$HOME/.hermes/hermes-agent/node_modules/playwright-core/`
|
||||
- browsers.json: `$HOME/.hermes/hermes-agent/node_modules/playwright-core/browsers.json`
|
||||
Reference in New Issue
Block a user