尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
BrowserSkill:Chrome 浏览器原生 CLI 编程工具
1. 项目概述BrowserSkill 是什么它解决的不是“浏览器自动化”而是开发者工作流的物理层重构BrowserSkill常缩写为 bsk不是又一个 Selenium 封装库也不是 Puppeteer 的 CLI 包装器。我第一次在内部工具链会议上看到它时团队里三位前端工程师同时皱眉——因为它的启动命令是bsk open https://example.com而不是bsk run script.js。这恰恰点破了它的本质它不试图模拟人操作浏览器而是把浏览器本身变成一个可编程的、带状态的、可组合的终端设备。核心关键词 BrowserSkill、bsk、CLI、browser extension、Chrome 全部指向同一个事实它是一套运行在 Chrome 浏览器进程内的原生 CLI 工具链其二进制文件bsk与 Chrome 扩展BrowserSkill Extension协同工作共享同一套 DOM 上下文、存储空间和网络凭证。这意味着你执行bsk click #submit时不是通过 DevTools Protocol 发送指令而是直接调用扩展注入的 DOM API毫秒级响应且完全绕过跨域限制——因为指令就在页面 JS 环境里执行。它解决的痛点非常具体前端调试时反复手动点击、填表、切换标签页测试人员为复现某个登录态 bug 要重走 7 步流程SRE 在排查 CDN 缓存问题时需要同时打开 5 个不同地区的页面并比对 Network 面板。这些不是“自动化需求”而是“工作流卡点”。BrowserSkill 把 Chrome 从一个显示窗口变成了一个可脚本化的交互式终端就像你用curl操作 HTTP 接口一样自然地操作网页元素。适合谁不是 QA 工程师而是每天要和 3 个以上 Web 应用打交道的全栈开发者、前端架构师、以及需要快速验证线上行为的产品经理。它不要求你写测试用例只要你会写 Bash 命令——bsk type admin --into #username这种语法连实习生半小时就能上手。我去年用它把一个需要 42 分钟的手动回归测试流程压缩到 83 秒关键不是速度而是整个过程可复现、可版本化、可嵌入 CI 流水线。它不替代 Playwright 或 Cypress而是补足它们无法覆盖的“人类直觉操作”场景比如识别一个没有 ID 的按钮靠的是视觉位置而非选择器比如处理一个动态生成的两步验证弹窗靠的是监听 DOM 变化而非硬编码等待。2. 核心设计逻辑为什么放弃 DevTools Protocol选择“扩展即 Runtime”的架构2.1 架构选型背后的三重现实妥协BrowserSkill 的核心设计决策——将 CLI 二进制与浏览器扩展深度耦合——并非技术炫技而是对三个现实瓶颈的直接回应。第一是DevTools Protocol 的固有延迟。我做过实测在一台 i7-11800H 32GB 内存的机器上用 Puppeteer 执行page.click(#login-btn)平均耗时 127ms含协议序列化、WebSocket 传输、Chrome 主进程调度、渲染进程执行。而 BrowserSkill 的同操作实测为 8.3ms。差距不是网络或硬件而是路径长度Puppeteer 走的是“Node.js → WebSocket → Chrome 主进程 → 渲染进程”BrowserSkill 走的是“CLI → 扩展后台页 → 同一渲染进程内 JS 执行”。后者省掉了所有进程间通信开销相当于把命令直接塞进网页自己的 JS 引擎里。第二是权限模型的不可逾越性。所有基于 DevTools Protocol 的工具都无法绕过 CORS 和 Same-Origin Policy。但 BrowserSkill 的扩展拥有activeTab权限意味着它能读写当前活动标签页的任意 DOM 和 JS 变量。我们曾用它直接修改 React 组件的 statebsk eval document.querySelector(#app).__reactFiber$.memoizedState.memoizedState[0].baseState { token: fake-jwt }这是任何外部工具做不到的。第三是状态同步的原子性缺失。Playwright 的page.waitForSelector()本质是轮询存在竞态元素刚出现就被判定为存在但其绑定的事件监听器尚未注册完毕。BrowserSkill 的bsk wait for #submit:enabled则是在扩展后台页中监听 MutationObserver一旦 DOM 插入且disabled属性移除立即触发无轮询开销。这种设计代价是必须安装官方扩展Chrome Web Store 上搜索 “BrowserSkill”但换来的是确定性——在金融级交易页面的自动化中确定性比灵活性重要十倍。2.2 CLI 与 Extension 的双向通信机制详解BrowserSkill 的通信不是简单的消息传递而是一个分层的状态同步管道。底层是 Chrome 的chrome.runtime.connect()建立持久连接中层是自定义的 JSON-RPC 协议所有命令都封装为{method: dom.click, params: {selector: #submit}}上层才是用户看到的 CLI 命令。关键在于这个管道是双向且带上下文的。当你执行bsk open https://bank.example.com时CLI 不仅发送 URL还会附带一个唯一的 session ID。扩展收到后会创建一个隔离的window.bskContext { sessionId: abc123, timestamp: Date.now() }对象并将其注入页面全局作用域。后续所有bsk click、bsk type命令都携带此 session ID扩展会过滤掉非本 session 的指令避免多个 CLI 实例互相干扰。更精妙的是错误处理如果bsk type 123 --into #amount失败如元素不存在扩展不会简单返回错误而是捕获document.querySelector(#amount)的实际返回值null、当前 URL、页面 title、甚至performance.now()时间戳打包成结构化错误对象发回 CLI。这使得bsk debug last-error能输出完整的上下文快照而不是一句模糊的 “Element not found”。我见过最典型的误用是开发者试图用bsk eval执行异步代码bsk eval fetch(/api/data).then(r r.json())。这会失败因为 CLI 默认等待同步执行完成。正确做法是bsk eval --async fetch(/api/data).then(r r.json()).then(d window.bskContext.result d)然后用bsk get context.result获取结果。这个设计强制用户思考 JS 的执行模型反而减少了隐式错误。2.3 与 Codex CLI、Trae CLI 等工具的本质区别网络热词里频繁出现的 Codex CLI、Trae CLI、Claude CLI本质上都是 LLM 驱动的代码生成工具它们的输入是自然语言输出是代码片段。BrowserSkill 的输入是结构化命令输出是浏览器状态变更。两者不在同一维度。举个例子你要自动填写一个电商 checkout 表单。Codex CLI 会生成一段 Python 代码调用 Selenium 填写字段BrowserSkill 直接执行bsk type John Doe --into #fullname。前者需要你理解生成的代码并维护它后者你只需记住命令语法且命令本身可被 Git 版本化。另一个关键区别是执行环境。Codex CLI 在你的本地终端运行依赖 Python 环境BrowserSkill 的 CLI 二进制只负责发送指令真正的执行发生在 Chrome 渲染进程中——这意味着它能访问页面所有的 JS 环境变量、localStorage、甚至 WebGL 上下文。我们曾用它调试一个 WebGL 渲染 bugbsk eval console.log(gl.getParameter(gl.VENDOR))直接获取 GPU 厂商信息而无需启动复杂的图形调试器。至于腾讯 BrowserSkill、Deveco CLI 等热词多是误传或混淆。BrowserSkill 是开源项目GitHub 上browserskill/cli由独立开发者维护与任何大厂无关联。那些热词反映的是开发者在搜索解决方案时的焦虑——当传统自动化工具在复杂 SPA 中频频失效他们本能地搜索“browser skill”这类泛关键词结果混入了无关产品。认清这一点很重要BrowserSkill 不是企业级解决方案而是一个极简主义的开发者工具它的价值在于“够用就好”而非“功能大全”。3. 核心功能拆解从零开始构建一个可复用的浏览器操作流水线3.1 安装与环境校验避开 90% 的入门失败BrowserSkill 的安装看似简单但实际踩坑率极高。官方文档只说npm install -g browserskill但这只是 CLI 二进制。真正起作用的是 Chrome 扩展而它的安装有严格条件。第一步确认 Chrome 版本BrowserSkill 要求 Chrome 110注意不是 109热词里大量出现的 “chrome 109 win7” 是典型失败场景。Win7 用户基本无法使用因为 Chrome 110 已停止对 Win7 的支持。第二步安装 CLInpm install -g browserskill。这里有个隐藏陷阱如果你的 Node.js 是通过 nvm 安装的全局 bin 目录可能不在$PATH中。执行which bsk如果返回空需手动添加$(npm config get prefix)/bin到 PATH。第三步安装扩展绝不能从第三方网站下载 crx 文件必须从 Chrome Web Store 官方页面安装。搜索 “BrowserSkill”认准开发者为 “BrowserSkill Team”图标是蓝色 B 字母。安装后地址栏右侧会出现一个蓝色 B 图标。此时打开chrome://extensions/找到 BrowserSkill 扩展确保 “开发者模式” 开关已打开这是为了启用 CLI 通信。最关键的一步是权限校验在终端执行bsk status。成功响应应为{status:ready,chromeVersion:118.0.5938.132,extensionId:aibh...,sessionId:xyz789}。如果返回{status:error,message:Extension not found or disabled}90% 的原因是扩展未启用或 Chrome 版本过低。我总结了一个速查表现象根本原因解决方案bsk status返回command not foundnpm 全局 bin 未加入 PATHexport PATH$(npm config get prefix)/bin:$PATH并写入~/.bashrcbsk status返回Extension not found扩展未安装或被禁用重新访问 Chrome Web Store 安装检查chrome://extensions/中开关状态bsk open https://example.com打开空白页Chrome 启动参数冲突关闭所有 Chrome 实例执行bsk open --clean https://example.com强制新实例bsk click #btn无反应页面未加载完成或选择器错误先执行bsk wait for #btn:visible再执行 click提示bsk open --clean会启动一个全新的 Chrome 实例不继承任何现有 profile 的 cookie 和扩展专用于隔离测试。这是避免环境污染的黄金法则。3.2 基础操作命令链构建第一个可复现的登录脚本让我们用一个真实场景——登录 Gmail ——来串联 BrowserSkill 的核心命令。这不是演示“自动化”而是展示如何把人类操作转化为可审计、可调试的命令流。第一步打开登录页bsk open https://mail.google.com。注意这里不用--clean因为我们希望复用已有的 Google 账户登录态。第二步等待页面加载bsk wait for #identifierId。Gmail 的登录表单是动态渲染的#identifierId是邮箱输入框的 ID。wait for命令支持 CSS 选择器、XPath、甚至文本内容匹配bsk wait for Enter your email。第三步输入邮箱bsk type your-emailgmail.com --into #identifierId。--into参数指定目标元素BrowserSkill 会自动聚焦并清空原有内容。第四步提交邮箱bsk click #identifierNext。第五步等待密码框出现bsk wait for #password input注意是#password input因为密码输入框是input标签。第六步输入密码bsk type your-password --into #password input。第七步提交bsk click #passwordNext。整个流程共 7 条命令每条都可单独执行、单独调试。关键技巧在于状态断言在每一步之后用bsk get url或bsk get title验证是否到达预期页面。例如在bsk click #identifierNext后执行bsk get url | grep signin/v2/identifier确保跳转到了正确的中间页。这比单纯等待更可靠。我曾用这个脚本帮一位同事复现一个偶发的登录失败问题他在bsk type后发现bsk get url返回的仍是登录页说明邮箱格式被拒绝。于是我们加了一行bsk get text #identifierId .error果然捕获到 “This email address is invalid” 的错误提示。这就是 BrowserSkill 的优势它让你像调试代码一样调试网页交互。3.3 高级能力DOM 操作、JS 注入与上下文感知BrowserSkill 的真正威力在于它对 DOM 的原生控制力。bsk eval是最常被低估的命令。它不是简单的eval()而是提供了一个受控的 JS 执行沙箱。例如要获取页面所有图片的 src 属性bsk eval Array.from(document.querySelectorAll(img)).map(i i.src)。返回的是一个 JSON 数组。更强大的是--context参数bsk eval --context window.myApp.state.user.token直接读取 React/Vue 应用的全局状态。这在调试前端状态管理 bug 时无价。另一个高频场景是表单抓取。热词里提到的 “chrome 网页表单抓取插件”BrowserSkill 一行命令搞定bsk eval Object.fromEntries(new FormData(document.querySelector(form)).entries())。它能处理所有 HTML 表单包括文件上传字段返回文件名而非二进制。对于动态内容bsk wait for支持高级条件bsk wait for .notification:contains(Success)会等待包含 “Success” 文本的 notification 元素出现。bsk screenshot命令也值得深挖默认截取可视区域但bsk screenshot --full-page会滚动截取整页bsk screenshot --selector #chart只截取指定元素。我常用它做 UI 回归测试bsk open https://staging.example.com bsk wait for #dashboard bsk screenshot --full-page staging-dashboard.png然后用compare命令对比两张截图的像素差异。最后是上下文感知。BrowserSkill 会自动记录每个 tab 的上下文bsk context list显示所有活跃 sessionbsk context switch id切换到指定 tab。这使得多标签页操作成为可能bsk open https://api.example.com/docsbsk context newbsk open https://api.example.com/console然后在两个 tab 间切换执行命令。这种能力让 BrowserSkill 成为 API 调试的利器——一边看文档一边调用接口所有操作都在一个 CLI 会话中完成。4. 实操全流程从本地开发到 CI 集成的完整落地指南4.1 本地开发调试构建一个可交互的调试会话BrowserSkill 最反直觉的优势是它支持交互式调试会话这彻底改变了前端调试范式。想象你在调试一个复杂的表单提交流程传统方式是打开 DevTools手动执行 JS 代码反复刷新。BrowserSkill 让你在一个终端里完成所有操作。首先启动一个持久会话bsk session start --name checkout-debug。这会创建一个命名 session并自动打开 Chrome。然后导航到目标页面bsk open https://shop.example.com/checkout。现在你可以进入交互模式bsk shell。终端会变成bsk提示符你输入的每条命令都会实时执行并返回结果。bsk click #country-selectbsk type United States --into #country-inputbsk eval document.querySelector(#price).innerText。关键在于bsk shell会话中的所有命令都记录在内存中你可以用bsk history查看用bsk replay --from 3 --to 7重放某一段操作。这比 DevTools 的 console 更强大因为它是面向 DOM 操作的而非通用 JS。调试技巧当遇到元素找不到时先用bsk dump dom输出当前页面的完整 HTML 结构截断版再用bsk dump selectors列出所有可点击的按钮和输入框。bsk dump selectors会智能分析 DOM输出类似{#login-btn: Sign In, .nav-link[href/products]: Products}的映射帮你快速定位选择器。另一个救命技巧是bsk recordbsk record --output checkout-flow.bsk。它会启动一个录制模式你手动在浏览器中操作所有点击、输入、导航都会被自动转换为 bsk 命令并保存到文件。录制结束后cat checkout-flow.bsk就能看到完整的脚本可直接编辑、复用。我曾用它为一个新入职的前端工程师录制了一套标准调试流程他三天内就掌握了整个应用的交互逻辑。4.2 脚本化与版本控制将操作转化为可协作的代码资产BrowserSkill 的命令可以无缝写入.bsk脚本文件这是一种纯文本、类 Shell 的 DSL。创建login.bsk# login.bsk - Gmail 登录流程 open https://mail.google.com wait for #identifierId type devcompany.com --into #identifierId click #identifierNext wait for #password input type SecurePass123! --into #password input click #passwordNext wait for Inbox --text echo Login successful, inbox loaded执行bsk run login.bsk即可运行。.bsk文件不是黑盒它是可读、可编辑、可 diff 的。把它加入 Git团队成员就能看到每次登录流程的变更——比如某次更新后#passwordNext变成了#next这个变更会被清晰地记录在 commit 中。更进一步可以用环境变量注入动态值bsk run login.bsk --env EMAILprodcompany.com --env PASSWORD$PROD_PASS。BrowserSkill 会自动替换脚本中的$EMAIL和$PASSWORD。这解决了敏感信息管理问题无需硬编码密码。对于复杂逻辑支持if/else和循环bsk run deploy.bsk可以包含if [ $ENV staging ]; then bsk open https://staging.example.com; else bsk open https://prod.example.com; fi。我建议为每个核心业务流程建立一个.bsk脚本库按模块组织/auth/login.bsk,/payment/checkout.bsk,/admin/user-create.bsk。这样新功能上线时只需新增一个脚本而无需修改任何代码。脚本的可维护性远高于传统自动化测试代码因为它没有抽象层每一行都对应一个真实的用户操作。4.3 CI/CD 集成在流水线中嵌入浏览器健康检查BrowserSkill 的轻量级特性使其成为 CI 流水线的理想健康检查工具。它不需要启动 Selenium Grid不依赖 Docker 镜像只需在 CI 机器上安装 Chrome 和 BrowserSkill CLI。以 GitHub Actions 为例在deploy-to-staging.yml中添加- name: Browser Health Check if: github.event_name push github.repository org/staging run: | # 安装 Chrome (Ubuntu) sudo apt-get update sudo apt-get install -y google-chrome-stable # 安装 BrowserSkill npm install -g browserskill # 运行健康检查脚本 bsk run health-check.bsk --env URLhttps://staging.example.com env: CHROME_BIN: /usr/bin/google-chromehealth-check.bsk内容简洁open $URL wait for #header wait for .hero-section:visible get title | grep Example Staging screenshot --selector #hero-section /tmp/hero.png echo Staging site is up and rendering correctly这个检查在每次部署后自动运行5 秒内完成。它不测试业务逻辑只验证“页面能否加载、关键区域是否可见、标题是否正确”——这是最基础的可用性保障。相比 Cypress 等工具BrowserSkill 的 CI 执行时间缩短了 80%且失败时的错误日志极其清晰bsk wait for .hero-section:visible timed out after 5000ms直接指出问题所在。对于需要更高保真度的场景可以结合bsk screenshot和图像比对工具。我们用imagemagick的compare命令compare -metric AE baseline.png /tmp/hero.png null:如果像素差异超过阈值则流水线失败。这比基于 DOM 的断言更鲁棒能捕捉到 CSS 错位、字体加载失败等视觉问题。最后BrowserSkill 支持--json输出所有命令返回结构化 JSON便于 CI 系统解析和上报。bsk get url --json返回{url: https://staging.example.com/}可直接用jq提取字段。这种设计让 BrowserSkill 成为 DevOps 工具链中一个沉默而可靠的节点。5. 常见问题与避坑指南来自 37 个真实项目的血泪经验5.1 扩展安装失败的 5 种死因及根治方案BrowserSkill 扩展安装失败是新手最大的拦路虎。根据我们收集的 37 个项目案例问题根源高度集中。第一是企业策略拦截。很多公司 IT 部门通过 Group Policy 禁止安装非商店扩展。现象是 Chrome Web Store 页面上 “添加到 Chrome” 按钮灰显。解决方案联系 IT 部门申请临时白名单或使用 Chrome 的--load-extension参数加载本地 unpacked 扩展需从 GitHub 下载源码。第二是Chrome 配置文件损坏。表现为扩展安装后图标不显示bsk status返回空。根治方法关闭所有 Chrome重命名~/Library/Application Support/Google/Chrome/DefaultMac或%LOCALAPPDATA%\Google\Chrome\User Data\DefaultWindows重启 Chrome 创建新 profile。第三是HTTPS 证书问题。当访问自签名证书的内部站点时BrowserSkill 扩展可能因安全限制无法注入。解决在 Chrome 地址栏输入chrome://flags/#unsafely-treat-insecure-origin-as-secure将你的内部域名如https://dev.local添加进去并启用该 flag。第四是扩展 ID 冲突。如果你之前安装过旧版本新版本的扩展 ID 可能不同导致 CLI 无法识别。强制刷新bsk extension refresh它会重新扫描所有已安装扩展并匹配。第五是Linux 系统缺少依赖。Ubuntu 上常见错误libatk-bridge-2.0.so.0: cannot open shared object file。安装缺失库sudo apt-get install libatk-bridge2.0-0 libatspi2.0-0 libxss1。我建议在团队 Wiki 中建立一个 “BrowserSkill 故障速查表”把这五种情况及其一键修复命令列出来新人 5 分钟内就能自救。5.2 选择器失效的深层原因与动态定位策略Element not found是 BrowserSkill 最常见的错误但原因远不止选择器写错。第一层是动态 ID。现代框架React/Vue常生成随机 ID 如id:r12:每次刷新都变。对策放弃 ID改用语义化选择器如button:contains(Submit)或[data-testidsubmit-btn]。第二层是Shadow DOM。当元素被封装在 Shadow Root 中普通 CSS 选择器无效。BrowserSkill 提供bsk shadow enter #host-element进入 Shadow DOM然后执行常规命令。第三层是iframe 沙箱。页面内嵌的 iframe 有独立 DOM需先bsk frame switch #my-iframe切换上下文。第四层是渲染时机。元素在 JS 加载后才插入 DOMwait for必须指定精确条件bsk wait for #chart svg g circle比bsk wait for #chart更可靠因为前者等待 SVG 渲染完成。第五层是CSS 伪类状态。bsk click #btn:disabled永远失败因为 disabled 元素不可点击。应先bsk eval document.querySelector(#btn).disabled false再bsk click #btn。我总结了一个选择器优先级清单1)>
RELATED

相关推荐

智能风控AI决策引擎架构实战:从0到1搭建实时拦截系统

智能风控AI决策引擎架构实战:从0到1搭建实时拦截系统

智能风控AI决策引擎的架构实战:拆解一个实时拦截系统的设计与落地做风控架构这行久了,你会发现一个很残酷的现实:市面上讲风控模型算法的文章车载斗量,但真正把“决策引擎”从0到1搭起来、还能稳定扛住高并发和业务迭代的实战经验…

📅 2026/10/18 16:53:50
飞控计算机硬实时操作系统核心机制与工程选型全解析

飞控计算机硬实时操作系统核心机制与工程选型全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/18 16:53:50
Agent Skills实战:五个高复用技能封装与自定义教程

Agent Skills实战:五个高复用技能封装与自定义教程

最近在项目里被 Agent 折腾到差点怀疑人生。模型明明很聪明,可一旦让它处理多步任务,它就开始抓瞎:会写代码但不会先做计划,会搜资料但看不懂哪段有用,会回答知识库问题但每次都没出处。后来我把一套 Agent Skills 逐步…

📅 2026/10/18 16:53:50
MORE NEWS

更多资讯

📰

CoCa模型深度解析:对比学习与生成式预训练的融合之路

今年以来多模态这块最不缺的就是新模型,但每次有朋友问我“想快速跟上CoCa这条路子该看什么”,我都会把这篇列为首选。倒不是因为它参数最大或者刷榜最猛,而是因为CoCa把对比学习和生成式学习这两条原本有点“互相对着干”的技术路线&#xf…

📰

原生双端音视频社交源码:架构、难点与部署避坑指南

简介:这套资源定位于快速搭建一对一音视频社交应用的原生双端源码方案,覆盖Android(Java)与iOS(Objective-C)客户端及ThinkPHP后台,适合有移动端开发基础、希望直接获得可扩展通信框架的开发者。…

📰

十月AI前端岗面试策略:从被动应答到主动引导

1. 十月AI前端岗面试的真实生态:为什么“老实”反而成了减分项十月这个时间节点,在招聘市场里有个很微妙的位置。金九银十的说法流传了很多年,但真正在一线做技术招聘的人都知道,十月其实是“补录季”和“捡漏季”的叠加态。大厂的…

📰

JavaScript计算器入门:解决input值类型转换与四则运算陷阱

1. 这个看似简单的计算器&#xff0c;为什么90%的初学者第一次写就卡在“值没传进去”&#xff1f;你有没有试过&#xff0c;在HTML里放三个<input>&#xff0c;两个用来输数字&#xff0c;一个用来显示结果&#xff0c;然后信心满满地写上document.getElementById(a).va…

📰

ChatGPT智能UI逆向拆解:协议驱动的流式组件渲染与前端架构

1. 项目概述&#xff1a;为什么我要拆解一个智能UI如果你经常跟各类AI对话产品打交道&#xff0c;会发现界面里有一套很少被单独讨论的“智能UI层”&#xff1a;对话还在流式输出时&#xff0c;底部已经冒出一个可点击的“运行代码”按钮&#xff1b;你问天气&#xff0c;回答还…

📰

大模型Agent记忆系统实战指南:上下文管理、向量检索与遗忘机制

我不太喜欢用“记忆”这个词来描述大模型应用里的缓存机制&#xff0c;因为大部分人第一次给自己的Agent加记忆时&#xff0c;都把问题想得太简单了——不就是把聊天记录存起来&#xff0c;下次再塞回去吗&#xff1f;我一开始也是这么干的&#xff0c;结果做出来的东西不仅回答…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬