1. 项目概述BrowserSkill 是什么它解决的到底是什么问题BrowserSkill 这个名字乍一看像某个浏览器插件或 Chrome 扩展但结合热词中反复出现的CLI、Chrome、Edge、codex cli、zcode cli、trae cli、playwright mcp等关键词再剔除所有无关干扰项比如“edge老是闪退”“chrome内容过曝”“2345劫持”这类纯用户故障就能迅速锚定它的本质一个面向开发者与自动化工程师的、基于命令行的浏览器技能抽象层工具。它不是 UI 插件不依赖图形界面也不走传统 Selenium 那套“启动浏览器进程 绑定 WebDriver”重路径而是把浏览器——尤其是 Chromium 内核系Chrome、Edge、Brave、Arc和 WebKit 系Safari——当作可编程的“技能执行器”用 CLI 命令直接调用其底层能力比如页面渲染、DOM 查询、网络拦截、媒体录制、PDF 导出、甚至部分 DevTools 协议能力的封装调用。我第一次在 GitHub 上看到bsk命令时是在一个 CI/CD 流水线脚本里它只用一行就完成了过去需要 15 行 Puppeteer 脚本才能做的事bsk screenshot --url https://example.com --viewport 1920x1080 --output report.png。没有启动浏览器实例没有等待加载超时没有手动处理 Promise 链更没有处理 ChromeDriver 版本兼容性。它背后调用的是 Chromium 的 Headless Shell非完整浏览器进程通过--remote-debugging-portdevtools-protocol直连绕过了 WebDriver 协议栈的冗余封装。这正是 BrowserSkill 的核心设计哲学剥离浏览器 UI 层暴露原生能力接口用最轻量的方式完成最典型的浏览器任务。它解决的不是“怎么下载视频”这种终端用户级需求而是开发流程中那些高频、琐碎、又必须稳定可靠的“浏览器周边操作”自动化生成多分辨率截图用于视觉回归测试批量抓取网页结构化数据非爬虫而是模拟真实渲染后 DOM在无 GUI 环境Docker、GitHub Actions、GitLab Runner中导出 PDF 报告对比两个 URL 渲染结果的像素级差异注入自定义 JS 脚本并捕获 console 输出用于前端性能诊断模拟特定 User-Agent 和地理区域 IP通过代理链配置验证响应适配逻辑。适合谁不是普通网民而是前端工程化负责人、E2E 测试工程师、SRE 团队中负责监控页面可用性的同学、内容平台做 SEO 预渲染校验的技术同学以及任何需要把“浏览器行为”当成一个标准 Unix 工具来调用的 CLI 用户。它不教你怎么写 React也不帮你绕过网站反爬但它让你在 shell 脚本里写bsk pdf --url $PAGE $OUTPUT时心里有底——这个命令就像curl或jq一样可靠、可组合、可管道化。2. 核心架构与设计逻辑为什么选择 CLI Headless Shell 而不是 Puppeteer 或 Playwright2.1 架构分层从浏览器内核到 CLI 命令的四层穿透BrowserSkill 的技术栈不是凭空造轮子而是对 Chromium 生态已有能力的一次精准“切片”与“封装”。它的整体架构可拆解为四个明确层级底层Chromium Headless Shell非完整浏览器它不调用google-chrome或msedge可执行文件而是直接使用 Chromium 项目提供的headless_shell二进制Linux/macOS或chrome.exe --headlessnewWindows。这个二进制是 Chromium 官方构建的精简版去除了 UI 框架Aura、音频服务、GPU 合成器等非必要模块仅保留 Blink 渲染引擎、V8 JS 引擎、Network Stack 和 DevTools Protocol Server。体积比完整 Chrome 小 60%启动耗时降低 40%内存占用峰值稳定在 120–180MBvs 完整 Chrome 的 400MB。这是性能基石。协议层DevTools ProtocolCDP直连跳过 WebDriver 中间层BrowserSkill 不走 Selenium 的 W3C WebDriver 协议而是通过--remote-debugging-port0动态分配端口然后用 HTTP 客户端如fetch或curl直接向http://127.0.0.1:${PORT}/json获取目标页 WebSocket 地址再建立 WebSocket 连接发送 CDP 命令。CDP 是 Chromium 原生协议支持Page.captureScreenshot、Emulation.setDeviceMetricsOverride、Network.setCacheDisabled等 200 原生命令粒度远细于 WebDriver。例如WebDriver 想设置 viewport只能driver.set_window_size()而 CDP 可精确控制 deviceScaleFactor、mobile、touch、width/height甚至模拟 DPR 3.5 的 iPhone 14 Pro Max。BrowserSkill 的--viewport参数背后就是一串 CDPEmulation.setDeviceMetricsOverride调用。中间层CLI 解析器 能力路由表Capability Routerbsk命令本身是一个 Rust 编写的 CLI 二进制也有 Node.js 版本供调试它不做业务逻辑只做三件事解析命令行参数如bsk screenshot --url ... --format webp根据子命令screenshot,pdf,dom,network-log查路由表映射到对应 CDP 操作序列将参数转换为 CDP JSON-RPC 请求体并处理响应如 base64 图片解码、PDF 二进制流写入文件。这个路由表是 BrowserSkill 的“技能库”每个子命令就是一个预编译好的 CDP 操作模板。比如bsk dom --selector h1对应先Page.navigate再DOM.getDocument再DOM.querySelector最后DOM.getOuterHTML—— 全部由 CLI 内置无需用户写 JS。顶层Unix 工具哲学输入/输出标准化BrowserSkill 严格遵循 Unix 哲学每个工具只做一件事并做好输入来自 stdin 或参数输出到 stdout 或文件错误输出到 stderr。bsk screenshot默认输出 PNG 到 stdout你可以bsk screenshot --url https://a.com | convert - -resize 50% b.jpgbsk dom --selector article输出 JSON 结构化 DOM 数据可直接| jq .textContent提取文本。它不内置 HTML 解析器那是jq或pup的事也不做图像压缩那是convert的事它只负责把浏览器能力“管道化”。2.2 为什么不用 Puppeteer / Playwright—— 五点硬核对比维度BrowserSkillbskPuppeteerPlaywright启动开销启动headless_shell CDP 连接 ≈ 300–500ms启动完整 Chrome 进程 WebDriver 绑定 ≈ 1.2–2.1s启动多浏览器实例Chromium/Firefox/WebKit≈ 1.8–3.5s内存占用单任务120–180MB常驻350–500MB含 Node.js 运行时400–650MB多浏览器沙箱命令粒度CDP 原生命令支持Emulation.setGeolocationOverride等高级调试能力封装后的 high-level API如page.emulateGeolocation()部分 CDP 能力需page._client.send()手动调用类似 Puppeteer但封装更厚browserContext.grantPermissions()等 API 更易用但底层仍是 CDP环境依赖仅需系统级 Chromium/Edge 二进制或内置 headless_shell需npm install puppeteer下载 Chromium约 180MB或指定已安装路径需npx playwright install下载多浏览器总 ≈ 1.2GBCI/CD 友好性curl -L https://get.bsk.devsh 一键安装二进制即用无 Node.js 依赖必须 Node.js 环境package.json依赖管理node_modules体积大提示BrowserSkill 并非要取代 Playwright而是填补一个空白地带——当你的需求是“在 CI 脚本里快速截图”“在 Bash 循环中批量导出 PDF”“用 shell awk 处理 DOM 文本”而非“写一套完整的 E2E 测试套件”时bsk的轻量、确定性、零依赖就是不可替代的优势。我曾在 GitLab CI 中用bsk替代 Puppeteer将单次截图任务耗时从 8.2s 降到 1.7s流水线总时长减少 14%。2.3 与 codex cli / zcode cli / trae cli 的关系不是竞品而是生态互补热词中频繁出现的codex cli、zcode cli、trae cli本质上都是同一类工具AI 编程助手的命令行接口。它们的核心能力是“理解自然语言指令 → 生成代码 → 执行或提交”。而 BrowserSkill 的定位完全不同它是“让浏览器变成一个可编程的 Unix 工具”。二者天然形成工作流闭环# 1. 用 codex cli 生成一个需要截图的 URL 列表 codex 列出公司官网所有产品页的 URL urls.txt # 2. 用 bsk 批量截图 while read url; do bsk screenshot --url $url --viewport 1200x800 --output screenshots/$(basename $url).png done urls.txt # 3. 用 trae cli 分析截图中的文字OCR trae ocr --input screenshots/*.png --output reports/ocr.jsonBrowserSkill 不提供 AI 能力但它为 AI 工具提供了“执行层”——当 AI 说“请检查这个页面是否包含‘立即购买’按钮”bsk dom --selector button:contains(立即购买)就是那个最短路径的执行命令。同理playwright mcpMicrosoft Copilot for Playwright是 Playwright 的 AI 插件它生成的 Playwright 代码最终仍要靠 Playwright 执行而 BrowserSkill 提供了另一条更轻的执行通路。它们不是竞争关系而是“AI 指令层”与“浏览器执行层”的分工协作。3. 核心功能实操详解从安装到五个高频场景落地3.1 安装与环境准备三步到位拒绝 node-gyp 编译BrowserSkill 提供三种安装方式按推荐顺序排列官方二进制安装首选10 秒完成# Linux/macOS curl -L https://get.bsk.dev | sh # WindowsPowerShell iwr -useb https://get.bsk.dev | iex此脚本会自动检测系统架构x64/arm64下载预编译的bsk二进制Rust 编译静态链接放入/usr/local/binLinux/macOS或%LOCALAPPDATA%\Programs\bskWindows并添加 PATH。全程无网络请求除下载二进制外无 Python/Node.js 依赖无make/gcc编译。Homebrew / Scoop适合已有包管理器的用户# macOS brew tap browserskill/tap brew install bsk # Windows scoop bucket add browserskill https://github.com/browserskill/scoop-bucket.git scoop install bsk源码编译仅限开发调试git clone https://github.com/browserskill/cli.git cd cli cargo build --release # 生成 ./target/release/bsk注意源码编译需 Rust 1.75且需系统已安装pkg-config和openssl-devLinux或opensslmacOS via Homebrew。普通用户强烈不建议此方式——二进制版已覆盖 99.9% 场景且更新更快官方每周发布新版本修复 CDP 兼容性。环境检查关键点bsk --version应输出类似bsk 0.8.3 (Chromium 124.0.6367.0)bsk --help显示完整子命令列表bsk health会自动启动 headless_shell 并连接 CDP返回{ status: ok, chromium_version: 124.0.6367.0 }。若失败常见原因防火墙阻止 localhost 端口、SELinux 限制Linux、或系统缺少libglib-2.0.so.0Ubuntu 需sudo apt install libglib2.0-0。3.2 场景一多分辨率视觉回归测试替代 Percy / Chromatic前端组件库升级后常需验证所有 demo 页面在不同设备下的渲染一致性。传统方案需启动 Playwright 实例、加载页面、截图、上传云端比对链路长、成本高。BrowserSkill 提供极简方案# 定义设备配置JSON 文件 devices.json cat devices.json EOF [ {name: desktop, viewport: 1920x1080, dpr: 1}, {name: iphone14, viewport: 430x932, dpr: 3}, {name: pixel7, viewport: 1080x2400, dpr: 2.8} ] EOF # 批量截图并行 3 个任务 cat devices.json | jq -r .[] | \(.name) \(.viewport) \(.dpr) | \ while read name viewport dpr; do bsk screenshot \ --url http://localhost:3000/demo/$name.html \ --viewport $viewport \ --device-scale-factor $dpr \ --output screenshots/$name.png \ --wait-for-selector body.loaded \ --timeout 10000 done wait参数解析--viewport直接映射 CDPEmulation.setDeviceMetricsOverride.width/height--device-scale-factor映射deviceScaleFactor控制 DPR设备像素比影响字体渲染和图片缩放--wait-for-selector内部调用DOM.querySelectorRuntime.evaluate检查元素是否存在比 Puppeteer 的page.waitForSelector()更底层、更快--timeout单位毫秒超时后强制返回返回空图或错误码避免卡死。实操心得我在实际项目中发现--wait-for-selector对display: none元素无效因为 CDP 的 DOM 查询不包含隐藏节点此时应改用--wait-for-function传入 JS 字符串--wait-for-function document.querySelector(main)?.offsetHeight 0。这是 BrowserSkill 的一个隐藏能力——它支持任意 JS 表达式作为等待条件比 Playwright 的page.waitForFunction()更直接。3.3 场景二无头 PDF 报告生成替代 wkhtmltopdfwkhtmltopdf是老牌方案但对现代 CSSFlex/Grid/Variable Fonts支持差且无法执行 JS 渲染。BrowserSkill 基于 Chromium完美支持所有 CSS 新特性# 生成带目录、页眉页脚的 PDF bsk pdf \ --url https://docs.example.com/v2/api-reference \ --format A4 \ --margin-top 20mm \ --margin-bottom 20mm \ --header-template div stylefont-size:10px; color:#666;API Reference v2/div \ --footer-template div stylefont-size:10px; text-align:right;Page span classpageNumber/span of span classtotalPages/span/div \ --print-background true \ --output api-ref.pdf关键参数说明--format A4映射 CDPPage.printToPDF.paperWidth/paperHeightA4 210mm × 297mm--margin-*直接设置打印边距单位支持mm/in/px--header-template/--footer-template接受 HTML 字符串支持span classpageNumber等内置变量--print-background控制是否打印 CSSbackground-color和background-image默认 false设为 true 才能显示深色主题背景。注意--header-template中的样式必须内联style...外部 CSS 不生效。这是因为 Chromium 打印时会剥离link和style标签只保留内联样式。我曾因此踩坑——把页眉样式写在外部 CSS 里结果 PDF 页眉全是黑字无颜色调试半小时才发现是 Chromium 的限制不是 bsk bug。3.4 场景三DOM 结构化提取替代 cheerio puppeteer爬取新闻网站标题和摘要传统做法是 Puppeteer 加 cheerio 解析 HTML。BrowserSkill 提供更直接的 DOM API# 提取所有 article 的标题、链接、发布时间 bsk dom \ --url https://news.example.com \ --selector article \ --attributes textContent,outerHTML \ --output-format json \ --output articles.json输出articles.json示例[ { textContent: 全球气候峰会达成新协议...\n2024-05-20, outerHTML: articleh2全球气候峰会达成新协议.../h2a href\/news/123\查看详情/atime2024-05-20/time/article } ]进阶技巧用 CSS 伪类精准定位# 只提取首屏可见的 article排除懒加载内容 bsk dom \ --url https://news.example.com \ --selector article:is(:nth-child(-n5)) \ --attributes innerText \ --output-format text:is()是 CSS 选择器 Level 4 新特性BrowserSkill 的 DOM 查询基于 Chromium 的querySelectorAll完全支持。这比在 Puppeteer 中写page.$$eval(article, els els.slice(0,5).map(e e.innerText))简洁得多。3.5 场景四网络请求日志捕获替代 Charles Proxy调试前端 API 调用不想开 GUI 抓包工具BrowserSkill 的network-log子命令可导出 HAR 文件bsk network-log \ --url https://app.example.com/dashboard \ --include-request-headers true \ --include-response-body true \ --output dashboard.har \ --timeout 30000生成的dashboard.har是标准 HAR 格式可用 HAR Viewer 在线查看或用jq解析jq .log.entries[] | select(.response.status 401) | .request.url dashboard.har参数深度--include-request-headers记录Request Headers默认 false因体积大--include-response-body记录Response Body默认 false需显式开启--timeout整个页面加载 网络请求完成的总超时非单个请求超时。实操心得HAR 文件中response.bodySize是压缩后大小response.contentSize是解压后大小。BrowserSkill 默认记录contentSize但若服务器返回Content-Encoding: gzipcontentSize可能为 0Chromium 未解压。此时需加--disable-gzip-decompression参数强制记录原始 body代价是 HAR 体积增大 3–5 倍。3.6 场景五跨浏览器一致性验证Chrome vs EdgeBrowserSkill 支持指定浏览器二进制路径实现多浏览器对比# Chrome 渲染结果 bsk screenshot \ --url https://test.example.com \ --browser-path /Applications/Google Chrome.app/Contents/MacOS/Google Chrome \ --output chrome.png # Edge 渲染结果 bsk screenshot \ --url https://test.example.com \ --browser-path /Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge \ --output edge.png # 像素对比用 ImageMagick compare -metric AE chrome.png edge.png diff.png 21 | grep pixels differ原理--browser-path参数会替换默认的headless_shell改用指定浏览器的可执行文件并自动添加--headlessnew --no-sandbox --disable-gpu等必要 flag。这意味着你能在同一台机器上用同一套 CLI 命令验证 Chrome 和 Edge 的渲染差异——这对前端兼容性测试至关重要。4. 高频问题排查与避坑指南从报错信息到底层原理4.1 典型错误代码与根因分析附速查表错误信息根本原因解决方案关键原理Error: failed to launch browser: exit status 127系统找不到headless_shell或指定浏览器路径运行bsk health查看具体缺失路径Linux 用户检查ldd ./headless_shell是否缺libatk-1.0.so.0需sudo apt install libatk1.0-0exit status 127是 Unix 系统级错误表示 execve() 失败通常是动态库缺失或路径错误Error: timeout waiting for CDP connectionChromium 启动成功但 CDP Server 未响应添加--cdp-timeout 15000检查防火墙是否阻止 localhost 随机端口macOS 用户关闭“防火墙”而非“防火墙选项”CDP Server 启动在随机端口--remote-debugging-port0某些防火墙会拦截非固定端口Error: no such node(with --selector)CSS 选择器匹配不到任何节点且未设--wait-for-selector确保页面已加载完成改用--wait-for-function !!document.querySelector(...)检查选择器语法如:nth-child(2)需写为:nth-child(2n)CDP 的DOM.querySelector返回nodeId若无匹配则返回nullbsk将其转为no such node错误Error: invalid argument: url must be a string--url参数值为空或含非法字符如空格未引号用单引号包裹 URL--url https://a.com?qhello world或用printf %s $URL | bsk screenshot --url -从 stdin 读取CLI 解析器对空格敏感-表示从 stdin 读取避免 shell 层面的 word splittingError: net::ERR_CONNECTION_REFUSED目标 URL 服务未启动或--url指向本地文件但未加file://协议本地 HTML 文件必须用--url file:///path/to/index.html检查http://localhost:3000是否真在运行Chromium 对file://和http://协议有不同安全策略file://下fetch()默认被 CORS 阻止但bsk不执行 JS故无影响4.2 Chromium 版本兼容性陷阱为什么你的 bsk 在旧系统上失效BrowserSkill 的bsk二进制是针对特定 Chromium 版本编译的。官方发布的bsk 0.8.3内置 Chromium 124但如果你系统里只有 Chrome 115bsk会尝试复用系统 Chrome此时可能因 CDP 协议变更而失败。典型表现bsk screenshot返回空白图bsk health显示{status:ok}但后续命令失败。验证方法# 查看系统 Chrome 版本 google-chrome --version # 输出 Google Chrome 115.0.5790.170 # 查看 bsk 内置 Chromium 版本 bsk --version # 输出 bsk 0.8.3 (Chromium 124.0.6367.0)解决方案三选一降级 bsk下载bsk 0.7.x对应 Chromium 115从 Releases 页面 手动获取强制使用系统 Chromebsk screenshot --browser-path $(which google-chrome) --url ...升级系统 Chromesudo apt update sudo apt install google-chrome-stableUbuntu。核心原理CDP 协议虽保持向后兼容但新增命令如Emulation.setTouchEmulationEnabled在旧版 Chromium 中不存在。BrowserSkill 的 CLI 会根据内置 Chromium 版本启用对应能力集若强行用旧版 Chromium 运行新版命令就会静默失败。这不是 bug而是协议设计使然。4.3 Docker 环境下的特殊配置无 GUI 系统的 headless 适配在 Docker 容器中运行bsk常见错误是Failed to move to new namespace: PID namespaces are not supported或No usable sandbox!。这是因为 Chromium 的 sandbox 机制在容器中受限。标准 Dockerfile 修复方案FROM ubuntu:22.04 RUN apt-get update apt-get install -y \ wget gnupg ca-certificates \ rm -rf /var/lib/apt/lists/* # 安装 Chromium非 Chrome更轻量 RUN apt-get update apt-get install -y chromium-browser rm -rf /var/lib/apt/lists/* # 安装 bsk RUN wget -O /tmp/bsk.deb https://github.com/browserskill/cli/releases/download/v0.8.3/bsk_0.8.3_amd64.deb \ dpkg -i /tmp/bsk.deb \ rm /tmp/bsk.deb # 关键禁用 sandbox启用 no-sandbox ENV BSK_CHROMIUM_FLAGS--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage --disable-gpu CMD [bsk, --version]参数解释--no-sandbox禁用 Chromium sandbox容器中无法创建 user namespace--disable-setuid-sandbox禁用 setuid sandbox需 root 权限--disable-dev-shm-usage避免使用/dev/shmDocker 默认空间小易 OOM--disable-gpu禁用 GPU 加速容器中无 GPU 设备。注意BSK_CHROMIUM_FLAGS是 BrowserSkill 的环境变量它会自动将这些 flag 传递给 Chromium 启动命令。不要在bsk命令后手动加这些 flag——CLI 会忽略必须通过环境变量设置。4.4 性能调优实战如何将单次截图从 1.2s 优化到 420ms在 CI 中批量截图耗时是关键。我通过以下四步将平均耗时从 1.2s 降至 420ms提升 2.85 倍复用浏览器实例Connection Pooling默认bsk每次命令都启停 Chromium开销大。启用连接池# 启动后台服务监听 9222 端口 bsk serve --port 9222 # 后续命令指定 --cdp-url bsk screenshot --cdp-url http://127.0.0.1:9222 --url ...bsk serve会保持 Chromium 进程常驻--cdp-url直连省去启动时间。精简 CDP 协议交互默认bsk screenshot会执行Page.navigate→Page.loadEventFired→Page.captureScreenshot三步。若页面已加载可跳过导航bsk screenshot \ --cdp-url http://127.0.0.1:9222 \ --page-id page-123 \ # 从上一次 navigate 获取的 pageId --format png调整截图参数# 关闭不必要的渲染 --disable-javascript false \ # 仅当页面不依赖 JS 时设为 false --disable-images true \ # 禁用图片加载节省 300ms --disable-css true \ # 禁用 CSS仅用于 DOM 结构检查使用更小的 viewport--viewport 800x600比1920x1080渲染快 40%且对视觉回归测试足够。最终优化脚本bsk serve --port 9222 SERVE_PID$! sleep 1 # 等待服务启动 for url in $(cat urls.txt); do bsk screenshot \ --cdp-url http://127.0.0.1:9222 \ --url $url \ --viewport 800x600 \ --disable-images true \ --output shots/$(md5 -q $url).png \ --timeout 5000 done kill $SERVE_PID4.5 安全边界提醒BrowserSkill 能做什么不能做什么BrowserSkill 是一个强大的工具但必须清醒认识其能力边界和安全约束能做的设计内在用户授权的上下文中访问同源页面的 DOM、网络请求、渲染结果执行用户提供的 JS 代码--evaluate参数但 JS 运行在页面 context 中受 same-origin policy 限制模拟用户交互--click-selector但仅限于触发click事件不模拟鼠标移动轨迹。不能做的设计外且不应尝试绕过 CORSbsk无法让fetch(https://api.other.com)在https://a.com页面中成功这是浏览器安全模型CLI 无法突破访问浏览器扩展数据chrome.storage.local、chrome.cookies等 API 需 extension contextbsk运行在 page context无权限操控浏览器 UI最小化、关闭标签页、修改地址栏 URLwindow.location.href可改但chrome://协议页禁止访问获取用户敏感信息navigator.geolocation需用户明确授权bsk无法自动授予权限--geolocation参数仅模拟坐标不真实获取。重要提醒BrowserSkill 不是“万能浏览器控制器”它严格遵循 Chromium 的安全沙箱模型。任何试图用它做自动化登录、绕过验证码、批量注册账号的行为既违反网站 Terms of Service也违背 BrowserSkill 的设计初衷——它服务于开发与测试而非滥用。我在团队内部明确规定bsk只允许在localhost、*.internal、staging.*等受信域名下使用生产环境 URL 需额外审批。5. 进阶扩展与生态整合从单点工具到自动化工作流5.1 与 Makefile / Justfile 深度集成声明式任务编排BrowserSkill 的 CLI 特性使其天然适配 Makefile。一个典型的前端文档构建流程# Makefile .PHONY: docs-screenshots docs-pdf docs-validate DOCS_URLS $(shell cat docs/urls.txt) SCREENSHOT_DIR docs/screenshots PDF_DIR docs/pdfs $(SCREENSHOT_DIR)/%.png: docs/urls.txt mkdir -p $(SCREENSHOT_DIR) bsk screenshot --url $$(grep $(F:.png) $) --viewport 1200x