让你的agent真的像你一样操控你的浏览器窗口
53.3/100
综合分
52
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/25 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查未通过:仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装。以下命令仍可尝试,但可能失败。
无法用 dsh 插件命令安装(仓库内无 dsh 插件清单)
git clone https://github.com/hanelalo/browser-bridge.git按该仓库 README 的原生方式安装;若作者另行发布了 DSH 插件包,请以其文档为准
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:需留意
是什么
dsh 原生插件 · browser
装得上吗
作者未把包发布到 npm,只能用源码安装
插件本身没问题,是分发方式不同
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 9 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包browser-bridge(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明
源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/2 04:33:18
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
扫描于 2026/11/3(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 操控浏览器窗口
README
由 DeepSeek 最新模型翻译生成Browser Bridge
用 WebSocket 把本地工具和真实浏览器连起来的桥,不需要 CDP。
扩展装在浏览器里,充当「手」;server 是本地 WebSocket 枢纽;client 是发指令的入口(Rust 命令行),也能通过 bridge-mcp 暴露给 Claude / Cursor 等智能体。
项目结构
| 目录 | 技术 | 职责 |
| extension/ | Vue 3 + TypeScript(WXT / Manifest V3) | 装在浏览器里,执行指令 |
| server/ | Rust(tokio + tokio-tungstenite) | WebSocket 枢纽,路由指令与响应 |
| client/ | Rust 命令行(clap) | 发指令、打印结果 |
| bridge-core/ | Rust 共享库 | 传输层(连接/自动拉起/重连)、元素定位、站点配方 |
| bridge-mcp/ | Rust(rmcp,MCP server) | 用 stdio 把全部指令暴露为 MCP 工具,供 Claude / Codex / Cursor 调用 |
快速开始
1. 启动 server
cd server
cargo run # 默认监听 ws://127.0.0.1:9225
展开完整文档(README 剩余 1 节)
Browser Bridge
用 WebSocket 把本地工具和真实浏览器连起来的桥,不需要 CDP。
扩展装在浏览器里,充当「手」;server 是本地 WebSocket 枢纽;client 是发指令的入口(Rust 命令行),也能通过 bridge-mcp 暴露给 Claude / Cursor 等智能体。
项目结构
| 目录 | 技术 | 职责 |
| extension/ | Vue 3 + TypeScript(WXT / Manifest V3) | 装在浏览器里,执行指令 |
| server/ | Rust(tokio + tokio-tungstenite) | WebSocket 枢纽,路由指令与响应 |
| client/ | Rust 命令行(clap) | 发指令、打印结果 |
| bridge-core/ | Rust 共享库 | 传输层(连接/自动拉起/重连)、元素定位、站点配方 |
| bridge-mcp/ | Rust(rmcp,MCP server) | 用 stdio 把全部指令暴露为 MCP 工具,供 Claude / Codex / Cursor 调用 |
快速开始
1. 启动 server
cd server
cargo run # 默认监听 ws://127.0.0.1:9225
换端口:BRIDGE_PORT=9226 cargo run
2. 加载插件
cd extension
pnpm install
pnpm dev # 会自动打开 Chrome 并加载开发版插件
也可以先 pnpm build,再到 chrome://extensions 打开「开发者模式」,加载 extension/dist/chrome-mv3 目录。
点击扩展弹窗里的「任务面板」,或从 Chrome 侧边栏打开 Browser Bridge,就能看到当前窗口里正在执行和排队的任务。排队数据存在 bridge-server 上,server 与扩展需要一起升级。
3. 使用 client
client 连接失败时会自动拉起 bridge-server(需要已构建的二进制,可用 BRIDGE_SERVER_BIN 指定路径),自动拉起的 server 空闲 120 秒后自动退出;插件断线后按 500ms→5s 退避自动重连。
cd client
cargo run -- list-tabs
cargo run -- --window 5 list-tabs
cargo run -- navigate https://example.com
cargo run -- click '#submit'
cargo run -- set_value '#username' alice
cargo run -- scrape 'div.card' --fields 'name:.name,price:.price,img:img@src'
cargo run -- querydomains 'browserbridge'
cargo run -- googlesearch 'Haze Seas'
cargo run -- redditsearch 'rust programming'
cargo run -- youtubesearch 'rust programming' --time week --sort popularity --max 10
cargo run -- youtubeinfo 'https://www.youtube.com/watch?v=rQ_J9WH6CGk'
cargo run -- youtuberinfo 'https://www.youtube.com/@xiaojunpodcast/videos'
cargo run -- youtuberinfo '@xiaojunpodcast' --max 20
cargo run -- googletrends 'ai image' --date 'today 1-m' --geo Worldwide
cargo run -- oldgoogletrends 'ai image detector' --date 'now 7-d' --geo Worldwide
cargo run -- googletrends-compare 'ai image' 'GPTs' --date 'today 1-m'
cargo run -- oldgoogletrends-compare 'coffee' 'tea' --date 'now 7-d'
cargo run -- get-page-markdown --url https://example.com
cargo run -- get-a11y-tree
cargo run -- screenshot --out shot.png
指令速查表
| 指令 | 作用 |
| list-tabs | 列出所有标签页 |
| new-tab [url] | 新建标签页(可指定 URL) |
| activate-tab --tab <id> | 切换标签页并聚焦窗口 |
| close-tab [--tab <id>] | 关闭标签页(默认当前激活页) |
| close-auto-tabs | 关闭 bridge 自动打开的全部标签页(不碰手动开的) |
| navigate <url> | 导航并等待页面加载完成 |
| click <target> [--new-tab] | 点击匹配定位的元素(锚点默认当前标签页打开) |
| click-at <x> <y> | 按坐标点击 |
| press-key <key> | 模拟按键(支持修饰键、--wait-load) |
| scroll --dx --dy | 滚动窗口或指定容器 |
| set-value <target> <value> | 设置 input/textarea/contenteditable 的值 |
| check <target> | 勾选/取消 checkbox、radio |
| select-option <target> --text/--value/--option-index | 选中下拉项 |
| clear <target> | 清空输入类元素 |
| get-value <target> | 读取元素当前值 |
| scrape <item> --fields '...' | 按选择器提取结构化数据 |
| run-script '<js>' | 在页面里执行任意 JS,返回 JSON |
| get-page-content | 读取页面标题/URL/文本 |
| get-page-markdown [--url <url>] [--selector <css>] [--full] | 把页面内容转换成标准 Markdown(默认自动提取正文,去掉导航/页脚等噪音) |
| get-a11y-tree [--include-hidden] [--max-nodes <n>] | 读取页面 a11y tree,可交互节点(按钮/链接/输入框等)带 target,可直接喂给 click / set_value |
| screenshot [--tab <id>] [--format png\|jpeg] [--quality <0-100>] [--out <file>] [--foreground] | 截取页面可见区域截图,返回 base64 data URL;--out 直接保存为文件 |
| googlesearch '<关键词>' | Google 搜索,输出 { tab_id, results } |
| redditsearch '<关键词>' | Reddit 搜索,输出 { tab_id, results } |
| youtubesearch '<关键词>' [--time] [--sort] [--max] | YouTube 搜索,支持上传日期 / 优先顺序筛选,最多返回 --max 条(默认 5),输出 { tab_id, results } |
| youtubeinfo '<视频URL或ID>' | 获取指定 YouTube 视频详情:字幕全文、URL、作者、时长、点赞/评论/订阅数,输出 { tab_id, video } |
| youtuberinfo '<频道URL或handle>' [--max] | 获取指定 YouTube 频道(youtuber)的视频列表:频道名、订阅数、视频名称/URL/观看数/时长/发布时间,最多返回 --max 条(默认 10),输出 { tab_id, channel, videos } |
| googletrends '<关键词>' [--date] [--geo] | Google Trends,输出 { tab_id, trend[], top[], rising[], regions[] } |
| oldgoogletrends '<关键词>' [--date] [--geo] | 经典版 Google Trends(legacy),读取页面趋势表格 + 完整热门/上升查询 + 地区热度 |
| googletrends-compare <词1> <词2>... [--date] [--geo] | Google Trends 多词对比,输出 { series[] } |
| oldgoogletrends-compare <词1> <词2>... [--date] [--geo] | 经典版 Google Trends(legacy)多词对比,共享 0-100 刻度,支持 now 7-d,输出 { series[] } |
| querydomains '<关键词>' [--tlds 'com,ai,xyz'] | Query.Domains 批量查域名注册情况与价格,输出 { results[] }(每项含 domain / tld / status / available / price / badges) |
多数指令支持 --tab <id> 指定标签页,默认操作当前激活页。
标签页管理:click 点击锚点链接默认在当前标签页打开(自动覆盖 target="_blank"),需要新开时用 --new-tab(由扩展创建标签页,响应会返回新标签页的 tab_id,便于链式操作)。new-tab 指令和 click --new-tab 打开的标签页都会被扩展记录,流程结束后可用 close-auto-tabs 一键清理,不会误关你手动打开的标签页。
close-auto-tabs
清理「自动打开的标签页」,需要单独执行(CLI 手动调用,或 MCP 流程在收尾时调用一次),不会误关手动打开的标签页。支持多 agent 隔离:
- MCP(close_auto_tabs 工具):每个 MCP 进程启动时生成独立身份(mcp-<pid>-<nanos>),只清理本进程创建的标签页,不会误关其他 agent 正在用的标签页;任务结束后可再调 close_agent_window 关闭自己的专用窗口(连同窗口内标签页一并释放)
- CLI(close-auto-tabs):作为人工管理入口,清理全部自动标签页(不管是谁创建的)
会被清理的:new-tab 指令和 click --new-tab 创建的标签页(扩展记录在 chrome.storage.session,service worker 重启不丢)。例如 googletrends 每次查询都会新开一个标签页,跑完后清理效果最明显:
cargo run -- googletrends 'ai image'
cargo run -- close-auto-tabs # 关闭刚才 googletrends 开的标签页
不会被清理的:手动开的标签页(如 Sitemap Monitor)、以及 navigate / googlesearch / redditsearch 复用的当前标签页(这些不新开 tab,属于「工作标签页」,留着是正常的)。
get-page-markdown
把页面内容转换成标准 Markdown,输出 { tab_id, title, url, markdown }。转换在页面内直接遍历渲染后的 DOM,SPA 动态渲染的内容也会包含;自动跳过脚本、隐藏元素与表单控件,链接/图片转成绝对 URL。转换核心基于开源 Turndown + @joplin/turndown-plugin-gfm(GFM 表格 / 删除线 / 任务列表),正文提取用 @mozilla/readability(Firefox 阅读模式同款)。
sh
cargo run -- get-page-markdown # 当前标签页(自动提取正文)
cargo run -- get-page-markdown --url https://example.com/docs # 先导航再转换
cargo run -- get-page-markdown --selector article # 只转换 article 容器
cargo run -- get-page-markdown --full # 跳过提取,转换整页
cargo run -- get-page-markdown --selector '#content' --tab 7 # 指定标签页 + 指定容器
- --url:可选,先导航到该 URL 并等待加载完成,再转换。
- 默认行为:用 Readability 自动提取主内容(去掉导航 / 页脚 / 相关文章等噪音),提取不到或内容过少时退回整页转换。
- --selector:可选,只转换匹配该 CSS 选择器的容器(如 article / #content),优先级最高。
- --full:可选,跳过正文自动提取,转换整个页面。
get-a11y-tree
读取页面 a11y tree(无障碍树),返回 { tab_id, title, url, count, nodes[] }。适合需要与页面交互(点击 / 填表 / 选择 / 勾选)前先了解页面结构、找出可交互元素的场景——比 get-page-content 的纯文本更能回答"页面上有什么按钮、输入框、下拉框": sh
cargo run -- get-a11y-tree
cargo run -- get-a11y-tree --max-nodes 1000 # 大页面放宽上限
cargo run -- get-a11y-tree --include-hidden # 连隐藏元素一起返回
nodes 是扁平节点列表,每项含 role(无障碍角色)/ name(可访问名称)/ value(当前值)/ states(enabled / disabled / checked / expanded 等)/ depth(DOM 深度)/ tag;可交互节点额外带 target,可直接喂给 click / set_value / check / select_option / clear / get_value: sh
cargo run -- click '#submit' # target 直接可用
- --include-hidden:可选,默认只返回可见元素;开启后包含 hidden / display:none / visibility:hidden / aria-hidden 的元素。
- --max-nodes:可选,最多返回节点数(默认 500,范围 10-5000),防止大页面输出过大。
- 角色与名称优先用 Chrome 的 computedRole / computedName(Chrome 135+),低版本自动回退到标签/属性推断;只遍历 light DOM,不穿透 iframe 与 shadow DOM(与元素定位行为一致)。
screenshot
截取页面可见区域截图,协议输出 { tab_id, url, title, mime, format, width, height, size, data },data 是完整 base64 data URL(data:image/png;base64,... / data:image/jpeg;base64,...)。MCP 的 screenshot 工具会把图片作为标准 MCP 图片块返回(另附文本元信息块),智能体可直接查看、无需自己解码:
sh
cargo run -- screenshot # 当前激活页,PNG
cargo run -- screenshot --format jpeg --quality 80 # JPEG,质量 80
cargo run -- screenshot --out shot.png # 解码保存为文件(--out 时打印摘要,不输出大段 base64)
cargo run -- screenshot --tab 7 --out shot.jpg # 指定标签页
cargo run -- screenshot --foreground --out shot.png # 先把目标窗口拉到前台再截(避免被遮挡时截到别的内容)
- 基于 chrome.tabs.captureVisibleTab,捕获的是目标标签页所在窗口的可见区域(viewport),不含视口外的内容——需要看页面其他部分时先 scroll 再截。
- 目标标签页若不是其窗口的激活页会先激活(不抢 OS 焦点,智能体专用窗口照常工作)。
- --format:png(默认)/ jpeg;--quality:JPEG 质量 0-100(默认 90,仅 jpeg 有效)。
- --foreground:默认关闭。窗口被其他应用完全遮挡时,captureVisibleTab 截到的可能是遮挡内容,加 --foreground 会把目标窗口拉到 OS 前台再截。
- --out:把 data URL 解码写入指定文件(自动创建父目录);省略时直接打印完整 data URL。
- 只截可见区域、不滚动拼接整页:这是 captureVisibleTab 的能力边界(本项目不依赖 CDP)。
googlesearch
Google 搜索专用快捷指令,输出 { "tab_id": ..., "results": [...] },tab_id 是搜索所在标签页(供后续指令链式操作),results 每项含 title / description / url / target: sh
cargo run -- googlesearch 'Haze Seas'
target 是可直接喂给 click 的元素定位({ by, value, index }),方便后续点击某个结果。实现放在 client 侧的「站点配方」里:用通用原语 navigate + scrape 编排,选择器作为常量集中在 client 里(#rso > div 容器、data-sncf='1' 描述等),扩展与协议保持通用。
querydomains
Query.Domains 域名批量查询,按关键词同时检查多个 TLD 的注册情况与注册价格,输出 { tab_id, query, tlds, complete, results[] }: sh
cargo run -- querydomains 'browserbridge'
cargo run -- querydomains 'browserbridge' --tlds 'dev,cloud,blog' # 自定义 TLD(默认 14 个,最多 20 个)
results 每项含 domain / tld / status(available / unavailable / uncertain)/ available(布尔)/ price(可用时的注册价,如 3 USD,不可用时为 null)/ badges(原始徽标:价格、注册年份、29 days ago 等)。实现是导航到首页 → 每次都打开 TLD 自定义模态框显式写入后缀(站点会持久化自定义列表,不重置就不是默认 14 个)→ 输入关键词回车 → 用 run_script 等到批量检查流(/api/upstream/check 的 resource entry 只在请求完成后出现)真正结束后逐行提取(圆点颜色判状态、徽标容器取价格),选择器集中在 bridge-core/src/recipes/querydomains.rs。个别 TLD 可能没有价格徽标(上游未返回定价),此时 price 为 null,属站点数据问题而非超时。
redditsearch
Reddit 搜索专用快捷指令,返回 { tab_id, results[] },每项含 title / description / published(相对时间,如 1mo ago)/ published_at(ISO 时间戳)/ votes(整数)/ comments(整数)/ url / target: sh
cargo run -- redditsearch 'rust programming'
结果页有两种渲染形态:search-post-with-content-preview(带正文预览)与 search-sdui-post(只有标题),配方同时收取;描述取自帖子正文预览,search-sdui-post 形态没有预览时为 null。Reddit 首页的搜索框藏在两层 shadow DOM 里,通用定位指令够不到,但配方直接导航到 /search/?q=,不依赖首页交互。
youtubesearch
YouTube 搜索专用快捷指令,返回 { tab_id, results[] },每项含 title / channel / views / published / duration / url / target(target 可直接喂给 click 打开视频): sh
cargo run -- youtubesearch 'rust programming'
cargo run -- youtubesearch 'rust programming' --time week # 本周上传
cargo run -- youtubesearch 'rust programming' --sort popularity # 热门程度优先
cargo run -- youtubesearch 'rust programming' --time month --sort popularity
cargo run -- youtubesearch 'rust programming' --time week --max 10 # 最多返回 10 条
- --time:上传日期筛选,any(默认)/ today / week / month / year
- --sort:优先顺序,relevance(默认)/ popularity(热门程度)
- --max:最多返回多少条结果(默认 5,至少 1)
- 日期与排序可组合(如 --time month --sort popularity)
筛选不是靠点击页面 UI,而是直接构造 YouTube 搜索 URL 的 sp 参数(今天 EgIIAg==、本周 EgIIAw==、本月 EgIIBA==、今年 EgIIBQ==;热门程度 CAM=;组合 token 实测自真实浏览器 2026 年的「过滤」面板)。不依赖页面渲染:导航返回的 HTML 里就内嵌了完整首屏数据(ytInitialData,约 20 条),配方直接解析它;不够 --max 时再取页面里的 InnerTube API key/context,用 continuation token 调 /youtubei/v1/search 续取(yt-dlp 同款数据源)。数据在 HTML 里就齐全,所以标签页在后台/被全屏应用遮挡也照常拿满,不弹窗、不抢焦点、不用切过去,实测 --max 40 约 3 秒返回。duration 直接取接口的 lengthText,不会缺失。若页面数据缺失(如验证墙/consent 页)会返回明确错误提示。
youtubeinfo
获取指定 YouTube 视频的详情,返回 { tab_id, video },video 含 url / title / author / author_url / duration(HH:MM:SS)/ duration_seconds / like_count / comment_count / subscriber_count(均为解析后的整数,万/亿/K/M 等缩写会换算)/ 对应的 *_text 原始文本 / captions[](每个字幕轨道含 language_code / name / kind / text 全文): sh
cargo run -- youtubeinfo 'https://www.youtube.com/watch?v=rQ_J9WH6CGk'
cargo run -- youtubeinfo 'rQ_J9WH6CGk' # 直接传 11 位视频 ID
cargo run -- youtubeinfo 'https://youtu.be/rQ_J9WH6CGk' # youtu.be 短链 / shorts / embed / live 均可
- 输入支持 11 位视频 ID、watch?v=、youtu.be/、/shorts/、/embed/、/live/ 链接
- 点赞数取自页面点赞按钮(LIKE 的 title,如 1.2万);评论数用 InnerTube next continuation 接口(yt-dlp 同款数据源,不依赖滚动评论区);订阅数取自 videoOwnerRenderer
- 字幕优先用页面内嵌的 captionTracks(timedtext json3);若返回空(YouTube 对 exp=xpe 的轨道要求 PO token,页面内无法生成),按 yt-dlp 的做法改用 android_vr 客户端调 player API 取无 pot 要求的轨道
- 同样不依赖页面渲染:数据来自 HTML 内嵌 JSON + InnerTube 接口,标签页在后台也能取到
youtuberinfo
获取指定 YouTube 频道(youtuber)的视频列表,返回 { tab_id, channel, videos[] }。channel 含 name / url / subscriber_count(解析后的整数,万/亿/K/M 缩写会换算)/ subscriber_count_text(原始文本);videos 每项含 title / url / views(原始文本)/ views_count(整数)/ duration / published / target(可直接喂给 click 打开视频):
cargo run -- youtuberinfo 'https://www.youtube.com/@xiaojunpodcast/videos'
cargo run -- youtuberinfo '@xiaojunpodcast' # 直接传 handle
cargo run -- youtuberinfo '@xiaojunpodcast' --max 20 # 最多返回 20 条
- 输入支持完整频道 URL(/@handle、/c/、/user/、/channel/UC... 均可,末尾带不带 /videos 都行)或 handle(@handle 或裸 handle)
- --max:最多返回多少条视频(默认 10,至少 1)
- 数据来自频道页 HTML 内嵌的 ytInitialData + InnerTube browse continuation(yt-dlp 同款数据源):首屏直接解析,不足 --max 条时自动续取;不依赖页面渲染、滚动或窗口可见性,标签页在后台也能拿满
- 订阅数同时兼容新旧版频道页结构(c4TabbedHeaderRenderer 与新版 contentMetadataViewModel)
- 视频条目同样兼容新旧版结构:旧版 videoRenderer / gridVideoRenderer 与 2026 年新版频道页的 lockupViewModel(richItemRenderer + lockupViewModel)都能解析,实测新版已全面切换
- 标题完整性兜底:频道页数据在部分会话/变体下会把超长标题截断(实测截到 100 字符甚至更短),配方会用 YouTube 官方 oEmbed 接口校验,发现疑似截断的标题自动替换成完整标题
googletrends
Google Trends 趋势查询,返回 { tab_id, trend[], top[], rising[] }: Google Trends 趋势查询,返回 { tab_id, trend[], top[], rising[], regions[] }:
cargo run -- googletrends 'ai image' --date 'today 1-m' --geo Worldwide
- trend:时间序列 [{ date, value }],value 为 0-100 相对热度(从图表 SVG 曲线坐标反解 + y 轴刻度校准)
- top / rising:热门查询与热度上升的查询(排名、关键词、热度、变化百分比),自动翻完所有分页
- regions:按地区显示的搜索热度 [{ rank, region, geo_code, interest }],geo_code 为 ISO 地区码,同样自动翻完分页(实测可达 66 个地区)
- --date 支持 today 1-m(默认)/ today 3-m / today 12-m / today 5-y / all,--geo 默认 Worldwide
- 关键词表是懒加载的,需要滚动到底部才渲染,配方会自动滚动内部容器等待表格数据
- 每次查询新开一个标签页(同标签页反复导航时图表偶发不加载,新标签页稳定),这些标签页会被扩展记录,可用 close-auto-tabs 清理
oldgoogletrends
针对 Gemini 改版前的经典 Explore 页面,自动打开 /trends/explore?...&legacy&hl=zh-CN。CLI 与 MCP 工具名均为 oldgoogletrends,读取页面已经渲染的趋势表格,并操作热门/上升切换控件及分页按钮,不主动请求 API。
在项目根目录运行:ai image detector,全球,过去 7 天
cargo run -p bridge-client -- oldgoogletrends 'ai image detector' --date 'now 7-d' --geo Worldwide
- --date 默认 today 1-m,支持 now 1-h / now 4-h / now 1-d / now 7-d、today N-d/N-m/N-y、all 或 YYYY-MM-DD YYYY-MM-DD。无效格式报错,不会静默改成一个月。
- --geo 默认 Worldwide;空字符串也表示全球,地区代码如 US / CN 会转为大写。经典版全球查询不发送 geo=Worldwide。
- trend:[{ date, value }];直接读取图表自带的无障碍数据表。date 保留页面时间标签(如 9月28日 14:00),不推算缺失年份或 UTC 时间;value 为页面热度值,非数值内容返回 null 并保留 value_text。
- top / rising:[{ rank, query, interest, change }],自动翻完页面榜单。热门查询有 interest、change: null;上升查询有增长百分比或 breakout,interest: null(经典版不提供上升查询的独立热度)。
- regions:[{ rank, region, geo_code, interest }],保留页面榜单顺序;页面未提供地区码时 geo_code 为 null。
- top_table_available / rising_table_available / tables_available / regions_available 表示对应数据读取成功;正常空榜单也为 true。加载、切换或分页失败会附 errors,保留已采集的部分行,对应 available 为 false;趋势表格未加载则整条指令报错。
- 每次新建标签页;成功后可用 close-auto-tabs 清理,失败时自动关闭本次标签页。原有 googletrends 继续用于新版页面。
配方验证:cargo test --workspace 和 node --test bridge-core/tests/oldgoogletrends.test.mjs。
googletrends-compare
多关键词走势对比,返回 { tab_id, terms[], date, geo, series[] },每个关键词一条趋势序列。共享 0-100 刻度(100 = 所有词中的最高峰值),便于直接比较;不返回热门/上升查询表:
cargo run -- googletrends-compare 'ai image' 'GPTs' --date 'today 1-m' --geo Worldwide
terms 也可用逗号分隔写成一个参数('ai image,GPTs')。--date / --geo 与 googletrends 一致。
oldgoogletrends-compare
经典版(legacy)多关键词走势对比,返回 { tab_id, terms[], date, geo, series[] },每个关键词一条趋势序列,共享 0-100 刻度,不返回热门/上升查询表:
cargo run -- oldgoogletrends-compare 'coffee' 'tea' --date 'now 7-d' --geo Worldwide
- 打开带 legacy 参数的 /trends/explore 对比页,读取趋势数据表(表头 x + y1..yN,词序与 terms 一致),页面上的均值摘要表不参与输出。
- --date 与 oldgoogletrends 一致(支持 now 7-d 等);--geo 默认 Worldwide,经典版全球查询不发送 geo=Worldwide。
- trend 每条 { date, value },date 保留页面时间标签(如 10月10日 13:00);无数据词整列为 0;页面提示数据不足时各词 trend 为空数组并附 note。
- 最多 5 个关键词,单个词内不能含逗号;CLI 的 terms 同样支持逗号分隔写法。
- 每次新建标签页;成功后可用 close-auto-tabs 清理,失败时自动关闭本次标签页。
配方验证:cargo test --workspace 和 node --test bridge-core/tests/oldgoogletrends_compare.test.mjs。
client 结构
bridge-core/ # 共享库(CLI 与 MCP 复用) ├── transport.rs # 连接 / 自动拉起 server / 请求 / 可重连 Bridge ├── target.rs # 元素定位参数(css / text / xpath) └── recipes/ # 站点配方 ├── googlesearch.rs # Google 搜索(选择器 + 编排) ├── redditsearch.rs # Reddit 搜索(选择器 + 编排) ├── youtubesearch.rs # YouTube 搜索(解析 ytInitialData + InnerTube 翻页 + sp 筛选) ├── youtubeinfo.rs # YouTube 视频详情(字幕全文 + 点赞/评论/订阅数,InnerTube 接口) ├── youtuberinfo.rs # YouTube 频道视频列表(频道名/订阅数/视频列表,InnerTube 翻页) ├── googletrends.rs # Google Trends(SVG 反解 + 表格解析 + 多词对比) ├── oldgoogletrends.rs # 经典版 Trends(参数校验 + 浏览器编排) ├── oldgoogletrends.js # 经典版 DOM 读取 + 切换/翻页 └── oldgoogletrends_compare.js # 经典版多词对比 DOM 读取 client/ # CLI(薄壳:子命令 + 分发) bridge-mcp/ # MCP server(stdio,每个指令一个 tool)
加新站点搜索只需在 recipes/ 里加一个文件,并在 main.rs 注册子命令,协议与扩展无需改动。
MCP
bridge-mcp 把全部浏览器指令暴露为 MCP tools(stdio 传输),供 Claude / Codex / Cursor 等客户端直接调用。运行:
从零构建、加载扩展、配置各客户端(Claude Desktop / Cursor / Claude Code)的完整步骤见 MCP.md。
./target/release/bridge-mcp # 或 cargo run -p bridge-mcp
- 默认连 ws://127.0.0.1:9225,可用 BRIDGE_SERVER 覆盖;
- 连接失败会自动拉起 bridge-server(空闲 120s 自动退出),断线自动重连;
- Chrome 没在运行会自动拉起默认 Chrome(共享 profile),等扩展连上后重试(最长约 30 秒);
- 每个智能体(mcp- 身份)默认拥有一个专用浏览器窗口:标签页默认开在那里,不占你正在看的窗口、不抢焦点;工具也可传 window_id 在多个窗口间调度。
- server 全局最多同时执行 3 个任务,同一个窗口同时只执行 1 个任务;站点配方会持有窗口任务租约直到流程结束。
- MCP 结束或断线不会退出共享 Chrome;窗口清理由显式工具调用发起,并经过 server 调度;
- 工具列表:list_tabs / close_tab / close_auto_tabs / close_agent_window / new_tab / activate_tab / navigate / click / click_at / press_key / scroll / set_value / check / select_option / clear / get_value / scrape / run_script / get_page_content / get_page_markdown / get_a11y_tree / screenshot / googlesearch / redditsearch / youtubesearch / youtubeinfo / youtuberinfo / googletrends / oldgoogletrends / googletrends_compare / oldgoogletrends_compare。
配置示例
先构建一次 ./scripts/build.sh,然后把 MCP 服务指向 target/release/bridge-mcp(绝对路径)。
Claude Desktop(claude_desktop_config.json):
{
"mcpServers": {
"browser-bridge": {
"command": "/绝对路径/browser-bridge/target/release/bridge-mcp",
"args": []
}
}
}
Cursor(.cursor/mcp.json):
{
"mcpServers": {
"browser-bridge": {
"command": "/绝对路径/browser-bridge/target/release/bridge-mcp",
"args": []
}
}
}
前提:Chrome 里已加载扩展(chrome://extensions 加载 extension/dist/chrome-mv3)。Chrome 没开也没关系——MCP 首次调用会自动拉起默认 Chrome 和 bridge-server,扩展会自动连上,无需手动启动任何进程。
构建产物(发布)
开发时用 cargo run / pnpm dev;正式使用前执行一键构建:
./scripts/build.sh
产物:
| 产物 | 路径 | 用途 |
| bridge-server | target/release/bridge-server | 常驻 WebSocket 枢纽,直接运行 |
| bridge-client | target/release/bridge-client | 发指令的命令行,直接运行 |
| bridge-mcp | target/release/bridge-mcp | MCP server,配给 Claude Desktop / Cursor 等 |
| 扩展 | extension/dist/chrome-mv3 | chrome://extensions 加载已解压目录 |
元素定位
统一支持三种方式,均可加 --index 指定第几个匹配:
| --by | 含义 | 示例 |
| css(默认) | CSS 选择器 | click '#submit' |
| text | 元素自身可见文本(精确优先,退化为包含) | click '登录' --by text |
| xpath | XPath 表达式 | click '//button[@id="x"]' --by xpath |
scrape 字段映射
scrape 按 CSS 选择器提取结构化数据(静态查询,CSP 安全)。字段语法:字段名:选择器[@属性],默认取文本,@属性 取属性值(如 a@href 对链接返回绝对 URL):
cargo run -- scrape 'div.card' --fields 'name:.name,price:.price,img:img@src'
兼容旧写法 --title h3 --link a --desc .VwiC3b(对应输出 title/url/description),同时传 --fields 时以 fields 为准。
run_script
在页面里执行任意 JS 表达式(可返回 Promise),结果 JSON 序列化返回,用于探索页面结构、复杂提取等场景。实现基于 chrome.userScripts(USER_SCRIPT 世界豁免页面 CSP):Chrome 135+ 走 userScripts.execute(当前页面即可用);低版本退回注册式 user script(Chrome 120+,首次使用后需刷新一次目标标签页)。
完整协议见 docs/protocol.md。
协议
见 docs/protocol.md。client 只要按协议走 WebSocket,语言不限(后续 TS / Python client 直接实现同一协议即可)。
配置
| 项 | 默认 | 说明 |
| server 端口 | 9225 | 环境变量 BRIDGE_PORT |
| server 空闲退出 | 0(不退出) | 环境变量 BRIDGE_IDLE_TIMEOUT(秒);客户端自动拉起时默认 120 |
| 插件连接地址 | ws://127.0.0.1:9225 | 构建时 WXT_PUBLIC_BRIDGE_URL=ws://... pnpm build |
| client 服务地址 | ws://127.0.0.1:9225 | --server 或环境变量 BRIDGE_SERVER |
| client 自动拉起 | 已构建的 bridge-server | BRIDGE_SERVER_BIN 指定路径,否则按同目录 / target / PATH 查找 |
| 空闲任务租约回收 | 60 秒 | 仅回收没有在途操作的空闲租约;执行结果未知时继续保留资源 |
| Chrome 版本 | 120+ | run_script 需要 chrome.userScripts(135+ 体验最佳) |
并发回归验证
升级时先构建 Rust 程序和扩展,再在浏览器扩展管理页重新加载新版本;server 与扩展须同时升级。
cargo test --workspace
pnpm --dir extension test
pnpm --dir extension exec tsc --noEmit
pnpm --dir extension build
cargo build --workspace
node scripts/test-concurrency.mjs
端到端脚本启动独立的真实 server / MCP 进程,执行实际 background 源码并用内存 Chrome API 验证并发、超时与断线;不访问用户浏览器。Node 测试需要支持 node:module.stripTypeScriptTypes 的版本(Node 22.13+ / 23.2+)。
安全说明
- server 只监听 127.0.0.1,不要让公网访问。
- 插件声明了 host_permissions: <all_urls> 才能操作任意页面——这是个人工具的便利;如果要对外分发,应改成按站点授权。
- 服务端目前接受任意角色的连接;如需更强隔离,可在握手阶段加 token。
- run_script / scrape 可以读写页面,属于强能力;不要把它暴露给不可信来源。
License
本项目使用 MIT License 开源。Copyright (c) 2026 hanelalo。
你可以自由使用、修改、分发本项目(含商用),但需保留版权声明和许可协议原文。本项目按 "AS IS" 提供,不附带任何明示或默示的担保。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
hanelalo/browser-bridge
让你的agent真的像你一样操控你的浏览器窗口
相关插件 · 浏览器
智能体插件框架deepseek-ai/deepseek-harness
DeepSeek Harnessdsh是由 DeepSeek AI 开发的开源 agent harness智能体框架。
★ 270,422已汉化DSH
71.9
多设备 Agent 看板YaoApp/yao
✨ 所有 Agent 和工作区集中管理,覆盖你的每一台设备。任务看板追踪进度,桌面端、移动端、浏览器、API…
★ 8,147已汉化DSH
71.2
可扩展侧边栏工作台omdsh-dev/DSH-better-sidebar
DSH 的双工作台:原生右侧栏 + 自绘底部面板,并把 ctx.betterSidebar 服务开放给所有插件
★ 4,761已汉化DSH
71.1
浏览器自动化桥Tencent/BrowserSkill
你的 Agent。你的浏览器。连接,就能协作。
★ 9,928已汉化DSH
71
AI 小说创作工作台EthanYoQ/AI-Novel-Writer
AI 小说作家 / AI Novel Writer
★ 1,591已汉化DSH
70.7
智能体浏览器引擎platonai/Browser4
DeepSeek Harness 集成
★ 1,175已汉化DSH
70.4