Midscene.js自然语言驱动的网页自动化全指南
一、概述
网页自动化在数据抓取、UI 测试和业务流程优化中发挥着重要作用。然而,传统工具如 Selenium 和 Puppeteer 要求用户具备编程技能,编写复杂的选择器和脚本维护成本高昂。Midscene.js 通过自然语言接口革新了这一领域,用户只需描述任务(如“点击登录按钮”或“提取产品价格”),AI 即可自动执行,大幅降低技术门槛。
Midscene.js 由 web-infra-dev 团队开发,开源于 GitHub(GitHub - web-infra-dev/midscene),采用 MIT 许可。它支持多种 AI 模型,集成 Puppeteer 和 Playwright,提供丰富的功能。本文基于官网(Midscene.js)内容,全面解析其功能、模型、案例、技术细节和优化建议,为开发者提供详尽指南。
二、安装与配置
2.1. npm 安装
Midscene.js 提供两个包:
@midscene/web:支持浏览器自动化,集成 Puppeteer/Playwright。@midscene/core:核心功能,适合轻量级场景。
npm install @midscene/web
配置 GPT-4o:
import { overrideAIConfig } from '@midscene/web';
// 配置 AI 模型和密钥
overrideAIConfig({OPENAI_API_KEY: '你的密钥', // OpenAI API 密钥,用于访问 GPT-4omodel: 'gpt-4o' // 默认使用 GPT-4o 模型
});
本地模型(如 UI-TARS):
// 配置本地运行的 UI-TARS 模型
overrideAIConfig({model: 'ui-tars', // 开源 UI 自动化模型endpoint: 'http://localhost:5000' // 本地服务地址
});
2.1.1.环境要求
建议 Node.js 18+,安装时确保网络畅通以拉取依赖。
2.2. Chrome 扩展
通过 Chrome Web Store 安装,提供无代码体验,直接在网页输入指令即可运行。
2.2.1. 使用步骤
- 访问 Chrome Web Store,点击“添加至 Chrome”。
- 在浏览器右上角扩展图标中输入指令,如“提取页面标题”。
2.3.环境变量与高级配置
支持环境变量:
MIDSCENE_OPENAI_API_KEY:密钥。MIDSCENE_LANGSMITH_DEBUG:调试模式(1)。MIDSCENE_CACHE:启用缓存(1)。
运行时配置:
// 高级配置示例
overrideAIConfig({OPENAI_API_KEY: '你的密钥', // 设置 API 密钥model: 'gpt-4o', // 指定模型cache: true, // 启用缓存以提升性能timeout: 20000, // 设置超时时间为 20 秒logLevel: 'verbose' // 设置详细日志级别
});
2.2.1. 本地部署
运行 UI-TARS:
docker run -p 5000:5000 ui-tars:latest # 启动 Docker 容器运行 UI-TARS 服务
配置:
// 配置本地模型连接
overrideAIConfig({model: 'ui-tars',endpoint: 'http://localhost:5000'
});
三、核心功能详解
3.1. 自然语言交互(aiAction)
通过自然语言执行操作:
// 在搜索框输入并点击搜索按钮
await agent.aiAction('在页面顶部的搜索框中输入 "JavaScript",然后点击旁边的搜索按钮');
使用技巧
- 具体性:指令越详细越好,如“点击右上角的红色按钮”。
- 多步骤:支持连续操作:
// 完整登录流程
await agent.aiAction('前往 https://example.com/login'); // 访问登录页面
await agent.aiAction('在用户名输入框中输入 "user123"'); // 输入用户名
await agent.aiAction('在密码输入框中输入 "pass123"'); // 输入密码
await agent.aiAction('点击 "登录" 按钮'); // 点击登录按钮
3.2. 数据提取(aiQuery)
提取结构化数据:
// 提取页面时间
const data = await agent.aiQuery({time: '页面左上角显示的日期和时间,格式为字符串' // 定义提取目标
});
console.log(data); // 输出:{ time: "2025-03-22 10:00 AM" }
复杂提取:
// 提取产品信息
const product = await agent.aiQuery({name: '产品名称,字符串格式', // 商品名称price: '产品价格,数字格式', // 商品价格stock: '库存状态,布尔值' // 是否有货
});
console.log(product); // 输出:{ name: "iPhone 15", price: 999, stock: true }
动态提取
const item = 'Sauce Labs Onesie'; // 定义商品名称变量
// 根据变量提取价格
const price = await agent.aiQuery({price: `"${item}" 的价格,数字格式` // 动态生成查询条件
});
console.log(price); // 输出:{ price: 7.99 }
3.3. 条件断言(aiAssert)
验证页面状态:
// 验证价格是否正确
await agent.aiAssert('"Sauce Labs Onesie" 的价格是 7.99');
复杂条件:
// 检查购物车状态
await agent.aiAssert('购物车中的商品数量大于 3'); // 验证数量
await agent.aiAssert('"结账" 按钮可见且可用'); // 验证按钮状态
错误处理
try {// 执行断言await agent.aiAssert('页面显示 "登录成功"');
} catch (e) {console.error('断言失败:', e.message); // 输出错误信息
}
3.4. 等待条件(aiWaitFor)
等待特定状态:
// 等待加载完成
await agent.aiWaitFor('加载动画不再可见', {timeout: 30000, // 设置超时为 30 秒interval: 5000 // 每 5 秒检查一次
});
结合操作
// 等待并执行
await agent.aiWaitFor('搜索结果已加载'); // 确保结果加载完成
await agent.aiAction('点击第一个搜索结果'); // 点击第一个结果
3.5. YAML 脚本(runYaml)
批量任务:
steps:- action: '点击登录按钮' # 点击登录按钮- action: '在用户名输入框中输入 "user123"' # 输入用户名- action: '在密码输入框中输入 "pass123"' # 输入密码- action: '点击提交按钮' # 提交表单
执行:
// 运行 YAML 脚本
await agent.runYaml('path/to/script.yaml');
复杂脚本
steps:- action: '前往 https://shop.com' # 访问电商网站- waitFor: '产品列表已加载' # 等待产品加载- query:products: '页面所有产品名称和价格,格式为数组 {name: string, price: number}' # 提取产品数据- assert: '"iPhone 15" 的价格低于 1000' # 验证价格
3.6. 可视化调试
生成动画和报告:
// 启用 LangSmith 调试模式
process.env.MIDSCENE_LANGSMITH_DEBUG = '1'; // 设置环境变量以输出详细日志
await agent.aiAction('点击 "注册" 按钮'); // 执行操作并生成调试报告
调试输出
报告示例:
- “定位到 ID 为 signup 的按钮”
- “点击坐标 (x: 100, y: 50),耗时 300ms”
四、支持的 AI 模型
4.1. GPT-4o
- 特点:OpenAI 多模态模型,支持文本和图像处理。
- 适用:通用自动化任务。
- 配置:
// 配置 GPT-4o 模型
overrideAIConfig({model: 'gpt-4o', // 模型名称OPENAI_API_KEY: '你的密钥' // OpenAI API 密钥
});
- 限制:无法操作跨域 iframe 或 canvas。
4.2. UI-TARS
- 特点:开源,支持图像识别和拖拽。
- 适用:复杂 UI 交互。
- 配置:
// 配置本地 UI-TARS 模型
overrideAIConfig({model: 'ui-tars', // 模型名称endpoint: 'http://localhost:5000' // 本地服务地址
});
4.3. Qwen2.5-VL
- 特点:阿里云视觉语言模型,擅长图像和文本混合处理。
- 适用:图像相关任务。
- 配置:
// 配置本地 Qwen2.5-VL 模型
overrideAIConfig({model: 'qwen2.5-vl', // 模型名称endpoint: 'http://localhost:6000' // 本地服务地址
});
模型对比
| 模型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| GPT-4o | 易用、多模态、性能稳定 | 云依赖、跨域限制 | 快速原型、通用任务 |
| UI-TARS | 本地部署、支持拖拽、隐私友好 | 配置复杂 | 企业应用、复杂 UI |
| Qwen2.5-VL | 视觉能力强、无跨域限制 | 部署需技术支持 | 图像处理、隐私敏感任务 |
五、实际应用案例
5.1. 社交媒体自动化
自动发布 X 帖子:
// 自动发帖流程
await agent.aiAction('点击 "发帖" 按钮'); // 打开发帖框
await agent.aiAction('在文本框中输入 "Midscene.js 真好用!"'); // 输入内容
await agent.aiAction('点击 "发布" 按钮'); // 提交帖子
定时发帖:
const cron = require('node-cron');
// 每天凌晨定时发帖
cron.schedule('0 0 * * *', async () => {await agent.aiAction('发布一条帖子,内容为 "每日更新 by Midscene.js"'); // 定时发布
});
5.2. 数据收集
收集音乐会信息:
// 访问网站并提取数据
await agent.aiAction('前往 https://concert-site.com'); // 打开音乐会网站
const concertData = await agent.aiQuery({event: '音乐会名称', // 提取活动名称date: '音乐会日期', // 提取活动日期location: '举办地点' // 提取活动地点
});
console.log(concertData); // 输出结果
5.3. 测试与验证
验证电商价格:
// 检查价格和按钮状态
await agent.aiAssert('"iPhone 15" 的价格低于 1000 美元'); // 验证价格
await agent.aiAssert('"加入购物车" 按钮可见且可用'); // 验证按钮状态
5.4. 电商价格监控
监控产品价格:
async function monitorPrice() {// 访问产品页面await agent.aiAction('前往 https://shop.com/product/123');// 提取当前价格const priceData = await agent.aiQuery({price: '当前产品价格,数字格式' // 获取价格});console.log(`当前价格: ${priceData.price}`);// 检查价格是否低于阈值if (priceData.price < 800) {console.log('价格低于 800,发送通知!');// 可集成邮件通知}
}
// 每小时检查一次
setInterval(monitorPrice, 60 * 60 * 1000);
保存历史价格
const fs = require('fs');
// 保存价格历史到 CSV 文件
async function savePriceHistory() {const priceData = await agent.aiQuery({price: '当前产品价格,数字格式' // 提取价格});const record = `${new Date().toISOString()},${priceData.price}\n`; // 格式化记录fs.appendFileSync('price_history.csv', record); // 追加到文件
}
setInterval(savePriceHistory, 60 * 60 * 1000); // 每小时执行
5.5. 表单自动填写
自动填写注册表单:
async function autoFillForm() {// 访问注册页面await agent.aiAction('前往 https://example.com/register');// 等待表单加载await agent.aiWaitFor('注册表单已加载'); // 确保表单可见// 填写表单字段await agent.aiAction('在用户名输入框中输入 "testuser"'); // 输入用户名await agent.aiAction('在邮箱输入框中输入 "test@example.com"'); // 输入邮箱await agent.aiAction('在密码输入框中输入 "Password123"'); // 输入密码// 提交表单await agent.aiAction('点击 "提交" 按钮'); // 提交表单// 验证结果await agent.aiAssert('页面显示 "注册成功"'); // 检查注册是否成功
}
autoFillForm().catch(console.error);
批量填写
const users = [{ username: 'user1', email: 'user1@example.com', password: 'Pass1' },{ username: 'user2', email: 'user2@example.com', password: 'Pass2' }
];
// 批量注册多个用户
for (const user of users) {await agent.aiAction(`在用户名输入框中输入 "${user.username}"`); // 输入用户名await agent.aiAction(`在邮箱输入框中输入 "${user.email}"`); // 输入邮箱await agent.aiAction(`在密码输入框中输入 "${user.password}"`); // 输入密码await agent.aiAction('点击 "提交" 按钮'); // 提交表单
}
5.6. 动态网页抓取
抓取动态加载内容:
async function scrapeDynamicContent() {// 访问动态网页await agent.aiAction('前往 https://dynamic-site.com');// 等待内容加载await agent.aiWaitFor('动态内容已加载', { timeout: 60000 }); // 等待 60 秒// 提取文章标题和摘要const articles = await agent.aiQuery({articles: '页面所有文章标题和摘要,格式为数组 {title: string, summary: string}' // 提取动态数据});console.log(articles);// 保存到 JSON 文件fs.writeFileSync('articles.json', JSON.stringify(articles, null, 2)); // 写入文件
}
scrapeDynamicContent().catch(console.error);
处理分页
async function scrapeAllPages() {let page = 1;const allArticles = [];while (true) {// 等待当前页面加载await agent.aiWaitFor(`第 ${page} 页内容已加载`); // 确保页面加载完成// 提取数据const articles = await agent.aiQuery({articles: '当前页面所有文章标题,格式为数组 {title: string}' // 提取标题});allArticles.push(...articles.articles); // 追加到总数组// 检查是否有下一页const hasNext = await agent.aiQuery({hasNext: '是否存在 "下一页" 按钮,布尔值' // 检查分页按钮});if (!hasNext.hasNext) break; // 无下一页则退出// 点击下一页await agent.aiAction('点击 "下一页" 按钮'); // 翻页page++;}console.log(`共抓取 ${allArticles.length} 篇文章`); // 输出总数
}
scrapeAllPages();
5.7. 自动化客服
模拟客服回复:
async function autoReply() {// 访问客服页面await agent.aiAction('前往 https://support.com/chat');// 等待新消息await agent.aiWaitFor('新客户消息出现'); // 等待消息加载// 获取消息内容const message = await agent.aiQuery({message: '最新客户消息,字符串格式' // 提取最新消息});// 根据消息内容回复if (message.message.includes('价格')) {await agent.aiAction('在回复框中输入 "我们的价格请查看官网"'); // 回复价格问题} else {await agent.aiAction('在回复框中输入 "请稍等,我为您查询"'); // 默认回复}await agent.aiAction('点击 "发送" 按钮'); // 发送回复
}
// 每分钟检查一次
setInterval(autoReply, 60 * 1000);
多语言支持
async function replyInLanguage(lang) {const message = await agent.aiQuery({message: '最新客户消息,字符串格式' // 获取最新消息});// 根据语言回复if (lang === 'zh') {await agent.aiAction(`在回复框中输入 "感谢您的消息,请稍等"`);} else {await agent.aiAction(`在回复框中输入 "Thank you for your message, please wait"`);}await agent.aiAction('点击 "发送" 按钮'); // 发送回复
}
replyInLanguage('zh'); // 中文回复
六、技术细节与集成
Puppeteer 集成
const puppeteer = require('puppeteer');
const { Midscene } = require('@midscene/web');
// 启动浏览器
const browser = await puppeteer.launch({ headless: true }); // 无头模式运行
const page = await browser.newPage();
const agent = new Midscene(page); // 创建 Midscene 实例
// 执行操作
await agent.aiAction('前往 https://example.com'); // 访问页面
await agent.aiAction('点击 "注册" 按钮'); // 点击注册按钮
自定义配置
// 配置代理和无头模式
const browser = await puppeteer.launch({headless: true, // 无头模式args: ['--proxy-server=http://proxy:8080'] // 设置代理
});
缓存机制
提升性能:
// 启用默认内存缓存
overrideAIConfig({ cache: true });
// 自定义文件缓存
const fs = require('fs');
overrideAIConfig({cache: {get: (key) => fs.readFileSync(`cache/${key}.json`, 'utf8'), // 从文件读取缓存set: (key, value) => fs.writeFileSync(`cache/${key}.json`, value) // 保存到文件}
});
缓存清理
// 每天清理缓存
setInterval(() => {fs.rmSync('cache', { recursive: true, force: true }); // 删除缓存目录console.log('缓存已清理');
}, 24 * 60 * 60 * 1000); // 每天执行一次
数据隐私
本地部署 Qwen2.5-VL:
docker run -p 6000:6000 qwen2.5-vl:latest # 启动 Qwen2.5-VL 服务
配置:
// 使用本地模型保护隐私
overrideAIConfig({model: 'qwen2.5-vl',endpoint: 'http://localhost:6000'
});
隐私验证
// 测试数据是否外泄
await agent.aiAction('在输入框中输入 "敏感数据"');
console.log('检查本地服务日志,确保数据未上传云端');
七、限制与优化
限制
- 交互类型:仅支持点击、输入、滚动等,拖拽限于 UI-TARS。
- AI 稳定性:自然语言解析可能出错。
- 跨域限制:GPT-4o 无法操作跨域 iframe。
优化建议
- 提示优化:用“点击蓝色提交按钮”代替“点击按钮”。
- 重试机制:
async function retryAction(action, retries = 3) {for (let i = 0; i < retries; i++) {try {// 执行操作await agent.aiAction(action);return;} catch (e) {console.warn(`第 ${i + 1}/${retries} 次重试: ${e.message}`); // 输出重试信息await new Promise(resolve => setTimeout(resolve, 1000)); // 等待 1 秒}}throw new Error('操作失败'); // 重试失败抛出错误
}
// 重试点击操作
await retryAction('点击 "提交" 按钮');
性能监控
// 记录执行时间
const start = Date.now();
await agent.aiAction('点击 "搜索" 按钮');
console.log(`执行时间: ${Date.now() - start}ms`); // 输出耗时
并行处理
// 并行执行多个任务
const tasks = [agent.aiAction('点击 "产品" 菜单'),agent.aiAction('点击 "关于我们" 菜单')
];
await Promise.all(tasks); // 同时执行多个操作
八、社区生态与贡献
Midscene.js 的开源特性促成了活跃社区:
- 示例:X 发帖、数据收集(见 GitHub)。
- 问题跟踪:通过 GitHub Issues 提交 bug。
- 贡献:添加新模型或功能。
贡献步骤
- Fork 仓库。
- 修改代码,例如添加模型:
// 添加自定义模型
overrideAIConfig({model: 'my-model',endpoint: 'http://my-server:8000'
});
- 提交 Pull Request。
社区案例
用户贡献的 YAML 示例:
steps:- action: '前往 https://news.com' # 访问新闻网站- query:headlines: '头条新闻标题,格式为数组 {title: string}' # 提取头条
九、参考资料
- Midscene.js 官网
- GitHub 仓库
- API 文档
- 模型选择
相关文章:
Midscene.js自然语言驱动的网页自动化全指南
一、概述 网页自动化在数据抓取、UI 测试和业务流程优化中发挥着重要作用。然而,传统工具如 Selenium 和 Puppeteer 要求用户具备编程技能,编写复杂的选择器和脚本维护成本高昂。Midscene.js 通过自然语言接口革新了这一领域,用户只需描述任…...
同一个局域网的话 如何访问另一台电脑的ip
在局域网内访问另一台电脑,可以通过以下几种常见的方法来实现: 直接通过IP地址访问: 首先,确保两台电脑都连接在同一个局域网内。获取目标电脑的IP地址,这可以通过在目标电脑上打开命令提示符(Windows系…...
基于SpringBoot的名著阅读网站
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
Excel(实战):INDEX函数和MATCH函数、INDEX函数实战题
目录 经典用法两者嵌套查值题目解题分析 INDEX巧妙用法让数组公式,自动填充所有、有数据的行/列INDEX函数和SEQUENCE函数 经典用法两者嵌套查值 题目 根据左表查询这三个人的所有数据 解题分析 INDEX函数的参数:第1个参数是选定查找范围,…...
希尔排序中的Hibbard序列
一 定义 Hibbard序列的每个元素由以下公式生成: h_k = 2^k - 1 其中k从1开始递增,序列为:1, 3, 7, 15, 31, 63, … 二 生成方式 起始条件:k=1,对应h_1=2^1-1=1 递推公式:每次k增加1,计算 h_{k+1}=2^{k+1}-1 示例:前5项…...
uniapp超简单ios截屏和上传app store构建版本方法
假如使用windows开发ios的应用,上架的时候,你会发现,上架需要ios应用多种尺寸的ios设备的截图,和需要xcode等工具将打包好的ipa文件上传到app store的构建版本。 大部分情况下,我们的公司都没有这么多款ios设备来…...
Netty源码—5.Pipeline和Handler一
大纲 1.Pipeline和Handler的作用和构成 2.ChannelHandler的分类 3.几个特殊的ChannelHandler 4.ChannelHandler的生命周期 5.ChannelPipeline的事件处理 6.关于ChannelPipeline的问题整理 7.ChannelPipeline主要包括三部分内容 8.ChannelPipeline的初始化 9.ChannelPi…...
Netlify 的深度解析及使用指南
以下是关于 Netlify 的深度解析及使用指南,结合其核心功能与用户需求,提供一站式解决方案: 一、Netlify 核心优势 全托管静态网站服务Netlify 提供从代码托管、自动化构建到全球 CDN 加速的全流程服务,支持 HTML/CSS/JS 静态资源及…...
MySQL小练习
目录 一、单表查询 二、多表查询 一、单表查询 素材: 表名:worker-- 表中字段均为中文,比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float…...
Apache Hive:基于Hadoop的分布式数据仓库
Apache Hive 是一个基于 Apache Hadoop 构建的开源分布式数据仓库系统,支持使用 SQL 执行 PB 级大规模数据分析与查询。 主要功能 Apache Hive 提供的主要功能如下。 HiveServer2 HiveServer2 服务用于支持接收客户端连接和查询请求。 HiveServer2 支持多客户端…...
推荐算法分析
一、性能分析指标 1. 准确性指标(Accuracy Metrics) 衡量推荐系统预测评分的准确性,包括: ✅ RMSE(均方根误差, Root Mean Squared Error) 解释:衡量预测评分 (\hat{r}_i) 和真实评分 (r_i)…...
vllm 离线推理Qwen2.5-VL-Instruct,API部署,支持max_pixels
使用这里的最新镜像: https://www.dong-blog.fun/post/1799 启动环境 docker run -it --rm --gpus "device=1,2" \ --net host \ -v ./zizhi_merge_2025-1/:/Qwen2.5-VL-Instruct \ -v ./test:/test \...
检波、限幅、钳位电路
检波电路: 类似调制收音机信号:输入的基波和载波叠加成调制信号(信号需要长距离里传输,频率要高,M级别的频率,所以要把低频信号叠在高频信号,才能把低频信号长距离传输,最后到达接收…...
学习threejs,使用TextGeometry文本几何体
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.TextGeometry1.1.1 ☘…...
Go红队开发—CLI框架(一)
CLI开发框架 命令行工具开发,主要是介绍开发用到的包,集成了一个框架,只要学会了基本每个人都能开发安全工具了。 该文章先学flags包,是比较经典的一个包,相比后面要学习的集成框架这个比较自由比较细化点࿰…...
解决点击按钮页面自动刷新
在React中,当你点击按钮时,如果按钮的type属性没有明确指定,它的默认值是submit。这意味着如果这个按钮被放置在一个<form>表单中,点击它会触发表单的提交行为,导致页面刷新。 在你的代码中,展开/折叠…...
高效团队开发的工具与方法 引言
引言 在现代软件开发领域,团队协作的效率和质量直接决定了项目的成败。随着项目规模的扩大和技术复杂度的增加,如何实现高效团队开发成为每个开发团队必须面对的挑战。高效团队开发不仅仅是个人技术能力的简单叠加,更需要借助合适的工具和方…...
【Java全栈进阶架构师实战:从设计模式到SpringCloudAlibaba,打造高可用系统】
🌟 分享一个教程,助刚踏入IT行业、工作几年的老油条、或热爱学习的工作党们更上一层楼的! 🌟 适合人群:初中级Java开发者、求职面试备战者、技术提升党! 📚 内容亮点: 1️⃣ …...
[蓝桥杯 2023 省 A] 异或和之和
题目来自洛谷网站: 暴力思路: 先进性预处理,找到每个点位置的前缀异或和,在枚举区间。 暴力代码: #include<bits/stdc.h> #define int long long using namespace std; const int N 1e520;int n; int arr[N…...
TDengine 3.3.2.0 集群报错 Post “http://buildkitsandbox:6041/rest/sql“
修复: vi /etc/hosts将buildkitsandbox映射为本机节点...
vue数据重置
前言 大家在开发后台管理系统的过程中,一定会遇到一个表格的条件查询重置功能吧,如果说查询条件少,重置起来还算是比较简单,如果元素特别多呢,那玩意写起来可遭老罪喽,那今天就给大家整一个如何快速重置数…...
22、web前端开发之html5(三)
六. 离线存储与缓存 在网络环境不稳定或需要优化资源加载速度的场景下,离线存储与缓存技术显得尤为重要。HTML5引入了多种离线存储和缓存机制,帮助开发者提升用户体验。本节将详细介绍Application Cache、localStorage、sessionStorage以及IndexedDB等技…...
git revert 用法实战:撤销一个 commit 或 merge
git revert 1 区别 • 常规的 commit (使用 git commit 提交的 commit) • merge commit 2 首先构建场景 master上的代码 dev开发分支上,添加一个a标签,并commit这次提交 切到master上,再次进行改动和提交 将de…...
修形还是需要再研究一下
最近有不少小伙伴问到修形和蜗杆砂轮的问题,之前虽然研究过一段时间,但是由于时间问题放下了,最近想再捡起来。 之前计算的砂轮齿形是一整段的,但是似乎这种对于有些小伙伴来说不太容易接受,希望按照修形的区域进行分…...
AI本地部署之dify
快捷目录 Windows 系统一、环境准备:首先windows 需要准备docker 环1. 安装Docker desktop2. 安装Docker3. 配置Docker 镜像路径4. 配置Docker 下载镜像源5. 重启Docker服务二、Dify 下载和安装1. Dify下载2. Dify 配置3. Dify 安装附件知识:4. Dify创建账号三、下载Ollama d…...
安恒春招一面
《网安面试指南》https://mp.weixin.qq.com/s/RIVYDmxI9g_TgGrpbdDKtA?token1860256701&langzh_CN 5000篇网安资料库https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247486065&idx2&snb30ade8200e842743339d428f414475e&chksmc0e4732df793fa3bf39…...
GPIO八种模式的应用场景总结
以下是 GPIO不同模式及其适用应用场景的详细总结: GPIO模式分类及适用场景 GPIO模式电气特性典型应用场景关键注意事项浮空输入引脚电平由外部信号决定,无内部上拉/下拉电阻• 按键检测(外接物理上拉/下拉)• 数字信号输入&#…...
Python应用指南:利用高德地图API获取POI数据(关键词版)
都说“为一杯奶茶愿意赴一座城”,曾经不知有多少年轻人为了一口茶颜悦色不惜跨越千里来到长沙打卡,而如今也有不少年轻人被传说中的“奶茶界的海底捞”所吸引,千里迢迢来到安徽只为尝一口卡旺卡奶茶。要说起来这卡旺卡奶茶,尽管这…...
【零基础入门unity游戏开发——2D篇】2D物理系统 —— 2D刚体组件(Rigidbody 2d)
考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、流程控制、面向对象等,适合没有编程基础的…...
Linux网络相关概念和重要知识(2)(UDP套接字编程、聊天室的实现、观察者模式)
目录 1.UDP套接字编程 (1)socket编程 (2)UDP的使用 ①socket ②bind ③recvfrom ④sendto 2.聊天室的实现 (1)整体逻辑 (2)对sockaddr_in的封装 (3)…...
