资讯动态

油猴脚本入门到实战:原理、元数据配置与调试全解析

发布时间:2026/10/17 6:20:53 来源:尧图企业网站定制
如果你经常泡在浏览器里处理各种琐碎的事情应该多少听说过油猴脚本这个词。说直白一点油猴Tampermonkey就是一个浏览器扩展它允许你在任意网页上自行注入JavaScript代码把网页改造成你想要的样子。不用等网站开发者更新功能不用装一堆臃肿的插件只靠一段几十行的脚本就能实现页面自动刷新一键复制全文屏蔽干扰元素这些操作。这篇文章我把油猴脚本从安装、原理到实战调试的完整路径梳理一遍适合从零开始接触脚本、也想自己动手写一段的人参考。我用这个思路做了很多小工具最大的感受是油猴脚本的价值不在于代码多复杂而在于它精准解决了网站没提供但你又很需要的那一类需求。这篇文章不会有太艰深的内容我会把匹配规则、权限系统、调试技巧这些真正的门槛讲清楚再直接给你几个能改改就用的例子。跟着操作一遍你基本就能自己写脚本了。1. 先搞清楚油猴脚本的定位它在浏览器里的哪一层很多人第一次接触油猴脚本是在某个论坛看到装个脚本就能自动签到的帖子。装上之后确实有效但完全不知道它为什么有效。这里我先把原理层面的事情说透。1.1 油猴脚本到底解决什么问题浏览器的运行机制是这样的网页从服务器拉下来HTML、CSS、JavaScript然后在你的浏览器里渲染执行。作为普通用户你只能看到最终的结果很难在原始文件层面做修改。油猴脚本做的事情就是在网页加载完成前后往页面里再插入一段你自己的JavaScript这段代码拥有操作当前页面DOM、监听事件、发起请求的权限。打个不太精确但很好懂的比方网页是一栋精装交付的房子开发商网站方把墙面、家具、水电都定好了。油猴脚本相当于允许你住进去之后自己动手——把沙发换个朝向、把墙刷成别的颜色、甚至在阳台上加个晾衣架。只要你的改造不违反物业浏览器安全策略的规定基本都能实现。基于这个机制油猴脚本能覆盖的场景很广自动填充重复表单、自动刷新页面、自动点击按钮读取页面上已有的信息做二次加工提取正文、统计价格、生成列表修改页面样式隐藏广告位、调整字体大小、强制暗色模式给页面扩展交互加一个复制全文按钮、加一个回到顶部悬停块调用浏览器提供的跨页面存储能力保存你自己的草稿、配置等简单数据。所以它不是一个单一功能工具而是一个在浏览器里运行你自己的代码的通用载体。这也意味着它和学习JS本身关系很大不会编程也能装别人写好的脚本用但想写得顺手JavaScript基础是绕不开的。1.2 为什么选Tampermonkey来管理脚本虽然油猴脚本里带了油猴两个字但实际上能运行用户脚本的扩展有好几个比如Tampermonkey、Violentmonkey、Greasemonkey。其中Tampermonkey中文习惯叫油猴是兼容性最好、功能最全的一个支持Chrome、Firefox、Edge、Safari等主流浏览器大多数用户脚本也都是按它的规范来写的。我个人的选择经验是Tampermonkey提供的脚本页管理、云同步、定时更新、跨浏览器导出导入这些功能非常成熟对新手友好对进阶用户也够用。本文后面的示例和API说明都以Tampermonkey为准。如果你用的是其他脚本管理器大部分代码可以直接跑少数细节比如存储函数的行为会有差异但整体思路是一样的。如果你只是想用现成脚本那到这一步其实就够了。但我建议你不要满足于此因为看懂油猴脚本的写法和调试过程不仅能让你安全地判断一个脚本是否靠谱还能在脚本失效时自己修复这是很实用的技能。2. 跑通第一个脚本从安装扩展到页面出现变化这个部分我直接带你走一遍完整流程。你不需要有编程基础只要按步骤操作几分钟就能看到效果。我这里用一个把页面背景改成护眼绿色的最小脚本做示例因为它的代码足够短效果又立竿见影。2.1 安装Tampermonkey和找到脚本管理入口第一步打开浏览器的扩展商店搜索Tampermonkey并安装。安装完成后浏览器工具栏会出现一个灰色或者红色的图标点开图标就能进入Tampermonkey的管理界面。在管理界面里你会看到已安装脚本列表点击旁边的添加新脚本按钮在英文界面里是Create a new script会进入一个内置的代码编辑器。Tampermonkey的编辑器在你新建脚本时会自动生成一个模板里面包含了元数据块和一段空的立即执行函数你只需要在这个基础上改就行。这里有一点我要提醒Tampermonkey本身只是容器它不产生任何脚本。所有你看到的自动签到去广告等效果都是脚本加载进页面后产生的。所以在安装了扩展之后你还需要真正创建一个脚本或者安装别人写好的脚本。2.2 你的第一段脚本修改页面背景色新建脚本后把内容替换成下面这段注意把匹配地址改成你自己的目标网站// UserScript // name 护眼背景色 // namespace http://my-scripts.local/ // version 0.0.1 // description 把指定网站的背景色改成豆沙绿 // author your-name // match https://example.com/* // grant none // /UserScript (function () { use strict; document.body.style.backgroundColor #cce8cf; })();保存之后打开你设置的match对应的网站刷新一下页面如果背景变成了豆沙绿说明这段脚本成功跑起来了。可能有人会问为什么脚本要在外面包一层立即执行函数这是为了避免脚本里的变量污染页面的全局作用域也避免和网站已有的JavaScript变量名冲突。use strict是JavaScript的严格模式声明能帮你规避一些不严谨的写法带来的隐患。这两行属于刻进DNA的习惯建议新写的每个脚本都带上。这段代码的意义不在于它有多强的功能而在于它帮助你验证了整个运行链路扩展安装是否正确、脚本是否被创建、匹配规则是否生效、脚本内的代码是否被执行。任何一个环节断了效果都出不来。这也是往后写任何脚本的基础。3. 比写代码更难的是三件套match、grant和run-at等到你开始写第二个脚本就会发现自己被困住的地方往往不是JavaScript本身而是油猴脚本的元数据配置。元数据块是脚本开头的注释段落Tampermonkey靠它决定脚本在什么页面运行、拥有哪些权限、什么时候执行。这一部分我讲仔细一点因为它是新手最容易栽跟头的地方。3.1 match的匹配逻辑脚本到底在哪些页面运行match是脚本的准入名单。它定义了这个脚本哪些网址生效。写错match最常见的两种表现一种是脚本在目标页面完全不生效另一种是脚本在无关页面里疯狂报错。match的完整格式是协议://域名/路径其中最灵活的是通配符*。举个例子https://example.com/*匹配example.com域名下所有路径包括https://example.com/和https://example.com/a/b?q1https://*.example.com/*匹配example.com的所有子域名比如mail.example.com但需要注意它不一定匹配裸域名本身*://example.com/*不限制协议http和https都匹配https://example.com/article/*只匹配以/article/开头的路径。我自己写脚本时通常会先写一个尽可能严格的匹配规则等测试通过再决定要不要放宽。因为匹配范围越小脚本影响面越小出错概率越低。如果需要在某些路径关闭脚本可以用exclude字段把特定地址排除掉。3.2 grant权限系统你能用哪些超能力grant是用来声明脚本所需权限的字段这也是油猴脚本安全和普通页面JS差异最大的地方。普通页面里的JavaScript能力有限跨域请求、跨页面存储、剪贴板操作这些都被浏览器限制了。而用户脚本通过Tampermonkey提供的GM_开头的API函数可以突破一部分限制前提是你需要在grant里显式声明。常见的GM API包括GM_setValue / GM_getValue跨页面保存和读取数据相当于脚本的本地存储GM_setClipboard向剪贴板写入内容GM_registerMenuCommand在Tampermonkey菜单里添加自定义命令GM_xmlhttpRequest发起跨域请求能力非常强也是被恶意脚本盯上的重点GM_log向控制台输出日志。需要注意如果grant写的是none那么所有GM函数都用不了脚本退化成普通页面JS。如果要用某个GM函数就必须在grant里写出完整的函数名。有些人在脚本开头看到了// grant GM_setValue但没用过GM_setValue就会在Tampermonkey菜单里看到一个报错提示。正确的习惯是只声明你用到的API不要为了省事全部授权。我见过不少翻车案例在grant none的情况下调用了GM_setClipboard结果浏览器直接抛GM_setClipboard is not defined。原因就是在元数据里漏写了这一行。这里教你一个排查思路报错信息里凡是GM_开头的函数名优先怀疑grant没配对。3.3 run-at在DOM生命周期的哪个点进场run-at决定脚本在页面加载过程中的执行时机。这个时机非常关键因为如果你在DOM节点还没生成的时候就尝试操作它自然什么都拿不到。Tampermonkey支持几个取值document-start页面任何资源加载前执行适合在页面构建早期做拦截、改写document-bodybody标签可用时执行document-endDOM解析完成后、图片等资源可能还在加载时执行document-idle页面加载完成后执行最常用也是默认值。我之前写一个自动填充表单的脚本最初用的document-idle但页面是异步渲染表单的等了半天都填充不进去。后来改成document-end并在代码里加了一个轮询等待问题才解决。这里需要明白一个道理run-at只定义你最早什么时候开始跑不等于那个时候页面元素一定都在。如果目标元素是页面加载后靠Ajax动态生成的你得在脚本里自行做等待或者监听而不是只改run-at就完事。关于动态内容我比较推荐的做法是写一个简单的定时检测函数每隔几百毫秒尝试找目标节点找到后执行操作再清除定时器。这种方法有效、直观适合大多数场景。4. 四个拿来就能改的实战脚本理论知识讲完了下面进入实操。我整理了四个我自己在日常中写过、也实际在用的脚本。每一个都尽量简短注释写清楚你可以直接复制到Tampermonkey里把匹配地址和选择器替换成自己的场景。4.1 定时自动刷新抢名额、盯状态的神器有一些页面需要盯着刷新才有机会比如预约剩余名额、商品库存状态、后台生成的任务进度。与其手动按F5不如写个脚本自动刷新。一个最简单的自动刷新脚本长这样// UserScript // name 定时自动刷新 // namespace http://my-scripts.local/ // version 0.0.1 // description 每30秒自动刷新一次当前页面 // author your-name // match https://example.com/status/* // grant none // /UserScript (function () { use strict; const interval 30; // 刷新间隔单位秒 setTimeout(() { location.reload(); }, interval * 1000); })();这个脚本有个问题哪怕某一次刷新后页面已经出现了你想要的可预约按钮脚本还是会继续刷新容易错过操作窗口。更稳妥的写法是在刷新前先检查页面状态如果目标内容出现了就取消刷新。我把这个判断逻辑加进去// UserScript // name 页面状态监控自动刷新 // namespace http://my-scripts.local/ // version 0.0.2 // description 监控页面是否出现目标文字未出现则自动刷新 // author your-name // match https://example.com/status/* // grant none // /UserScript (function () { use strict; const targetText 可预约; const checkInterval 5; // 每5秒检查一次 const maxRefreshCount 40; // 最多自动刷新40次防止无限循环 let refreshCount 0; function pageHasTarget() { return document.body document.body.innerText.includes(targetText); } function checkAndRefresh() { if (pageHasTarget()) { console.log(检测到目标内容停止刷新); return; } refreshCount; if (refreshCount maxRefreshCount) { console.log(达到最大刷新次数停止); return; } location.reload(); } setInterval(checkAndRefresh, checkInterval * 1000); })();这里说明一个细节document.body.innerText.includes(targetText)是最朴素的关键字判断方式适合页面是普通文本渲染的场景。如果目标页面是复杂的单页应用文字在canvas里或者被拆分到多个DOM节点这种方式会失效那就需要更精确的DOM选择器。4.2 一键复制页面正文把阅读资料搬回本地工作中我经常需要把某篇网页文章的内容复制到本地笔记里。手动选中全文再复制很麻烦且容易带上格式和广告。用脚本可以让复制正文变成点一下菜单的事// UserScript // name 一键复制正文 // namespace http://my-scripts.local/ // version 0.0.1 // description 点击油猴菜单复制文章标题和正文纯文本 // author your-name // match https://example.com/article/* // grant GM_setClipboard // grant GM_registerMenuCommand // /UserScript (function () { use strict; function getArticleText() { const title document.querySelector(h1); const article document.querySelector(article); let text ; if (title) { text title.innerText \n\n; } if (article) { text article.innerText; } return text.trim(); } function copyArticle() { const content getArticleText(); if (!content) { alert(没有找到正文内容请检查页面结构); return; } GM_setClipboard(content); } GM_registerMenuCommand(复制正文, copyArticle); })();这个脚本最需要改的地方是document.querySelector(h1)和document.querySelector(article)两个选择器。不同网站的文章页结构差异很大你需要自己打开开发者工具确认目标页面用的标签是什么。有的网站用div classpost-content有的用div idarticleBody反正以实际页面为准改对选择器脚本就能工作。这里我补充一个经验把选择器写得越靠近目标内容越准。比如你找一个article标签比找一个div.article-main .content p要抗变化得多。但任何选择器都有失效的一天所以代码里必须做好空值判断找不到内容时给用户一个提示而不是静默失败。4.3 文章阅读排版增强别让眼睛太累很多资讯类网站默认字体太小、行距太密阅读体验不佳。与其每次都手动调整浏览器缩放不如用脚本统一处理。排版增强脚本的核心逻辑是拿到文章容器然后覆盖它的样式// UserScript // name 文章阅读模式增强 // namespace http://my-scripts.local/ // version 0.0.1 // description 调整正文排版加宽、加大字号、增加行距 // author your-name // match https://example.com/article/* // grant none // /UserScript (function () { use strict; function enhanceLayout() { const article document.querySelector(article); if (!article) { return; } const style document.createElement(style); style.textContent article { max-width: 760px !important; margin: 0 auto !important; font-size: 18px !important; line-height: 1.8 !important; } article p { margin-bottom: 1.2em !important; } ; document.head.appendChild(style); } window.addEventListener(load, enhanceLayout); })();在修改样式这个场景里!important几乎是必须的因为原网站的样式表优先级可能比你高。没有!important你的样式可能会被覆盖改了跟没改一样。这里也顺带提一句如果只是临时看看用浏览器开发者工具手动调样式就够了但如果这个页面你每天都要看脚本就是一次投入、长期受益的选择。4.4 跨页面保存数据把草稿存在油猴的保险箱里有些网站的表单没有自动草稿功能写到一半关了页面内容就丢了。油猴的GM_setValue可以帮助你把输入内容保存在本地下次打开页面时自动回填。这个脚本稍微复杂一点但实用性很高也展示了数据持久化的思路// UserScript // name 表单草稿自动保存 // namespace http://my-scripts.local/ // version 0.0.1 // description 在指定页面自动保存和恢复表单草稿 // author your-name // match https://example.com/write/* // grant GM_setValue // grant GM_getValue // grant GM_registerMenuCommand // /UserScript (function () { use strict; const STORAGE_KEY draft_content; function saveDraft() { const textarea document.querySelector(textarea); if (textarea) { GM_setValue(STORAGE_KEY, textarea.value); console.log(草稿已保存); } } function restoreDraft() { const textarea document.querySelector(textarea); const saved GM_getValue(STORAGE_KEY, ); if (textarea saved) { textarea.value saved; console.log(草稿已恢复); } } GM_registerMenuCommand(保存草稿, saveDraft); GM_registerMenuCommand(清除草稿, () { GM_setValue(STORAGE_KEY, ); }); window.addEventListener(load, restoreDraft); })();这里有两个不太容易被发现的知识点。第一GM_getValue可以传第二个参数作为默认值比如上例中的这样即使之前没存过数据也不会报错。第二GM_setValue的数据是绑定在脚本上的不是绑定在页面上的。同一个脚本的所有匹配页面共享这份数据。如果你想区分不同页面、不同表单最简单的办法是给存储键加上页面特征比如draft_content_${location.pathname}这样才能避免两个页面互相覆盖。5. 开发调试中的五个经典翻车现场写油猴脚本的一大特点是反馈周期很长你以为自己写对了保存之后回目标页面一看什么都没发生。这在初期几乎每天都会遇到。我把这些年踩过的坑集中整理一下基本上你后面遇到的问题都会落在其中某一类里面。5.1 脚本不执行先查匹配规则和控制台脚本不执行通常是两类原因。第一类是match写错了这个排查起来很简单打开Tampermonkey图标看脚本旁边显示的数字或状态。如果脚本在当前页面没有生效图标上通常会显示一个灰色数字或者没有数字。点开图标也能看到脚本列表每个脚本后面会标注匹配到了还是未找到匹配项。第二类是匹配到了但脚本报错了。这种情况要打开浏览器的开发者工具F12切到Console控制台标签页把报错信息截图或抄下来。最常见的报错是XXX is not a function或者document is undefined前者多半是API名写错或grant漏配后者可能是因为你在document-start阶段就去访问了document.body。5.2 用了GM函数但提示未定义我已经在权限部分提过这个问题但因为它太典型值得再展开一次。GM_setValue、GM_xmlhttpRequest这些函数并不是页面的原生能力它们是由Tampermonkey注入的。只有你在元数据块里写明了grant GM_setValueTampermonkey才会把对应的函数注入给你。如果你声明的是grant none那这些GM_函数全部不存在。这里有个更隐蔽的坑某些版本的浏览器对命名空间有限制导致部分GM函数在特定页面注入失败。如果你确认grant写对了但函数还是undefined试着在Tampermonkey设置里切换一下兼容模式或者换个脚本管理器对比测试一般能定位是扩展的问题还是代码的问题。5.3 console.log的日志去哪了在油猴脚本里直接写console.log(hello)打开控制台有时候能看到日志有时候看不到。原因是Tampermonkey默认把脚本日志输出到了它自己的日志页面而不是浏览器控制台。如果你想在浏览器控制台里看到日志可以改用GM_log函数或者在脚本顶部设置// grant GM_log然后调用GM_log。这个细节看起来很小但在调试时非常耽误事。我自己的调试习惯是优先用GM_log输出核心变量配合浏览器的Sources断点调试只有在需要检查页面自身逻辑时才会混用console.log。油猴脚本的调试体验本身就不如正规前端工程所以日志函数越顺手越好。5.4 页面结构变了脚本就失效油猴脚本依赖选择器去定位DOM元素而网站改版是最常见的选择器失效原因。处理这个问题的思路不是祈祷网站别改版而是尽量选择稳定的选择器并做好容错。什么是稳定的选择器优先使用带有明确语义的HTML标签比如article、h1、main其次才考虑class再次是id。class虽然好用但前端框架生成的class经常是随机的常见像css-1a2b3c这种一眼就是构建工具生成的改版一次换一批。id通常是后端模板写死的相对稳定。实际项目里我还会加几层备选如果article找不到就退回去找.post-content再找不到就尝试div[class*content]三层兜底能大幅延长脚本的生存周期。5.5 脚本和页面代码、其他脚本打架油猴脚本运行在页面环境中虽然默认是隔离的但不代表绝对安全。脚本里定义的全局变量、修改的全局对象都可能和页面自己的代码冲突。为了减少这种风险一定要把代码放在立即执行函数里不要轻易往window对象上挂挂载东西。如果两个用户脚本同时操作同一个页面还可能出现互相覆盖的情况。比如一个脚本把页面背景改成绿色另一个脚本改成蓝色后执行的覆盖先执行的很难说谁对谁错。应对方式是用Tampermonkey的脚本顺序设置来调整执行优先级或者干脆只保留一个功能重叠的脚本。此外如果页面本身有严格的CSP内容安全策略设置Tampermonkey的脚本注入也可能受影响这时候通常需要按扩展提示放宽限制但我建议不要轻易关闭浏览器的安全特性尽量用脚本的run-at document-start提前执行来规避部分CSP限制。6. 脚本分享、安装和日常管理的一些建议写脚本只是起点日常使用和后续维护同样重要。最后这部分我把脚本的来源安全、备份管理、进阶发布这几个方向讲一讲都是过来人觉得值得注意的地方。6.1 安装别人的脚本前先看一眼源代码用现成脚本很方便但安全问题不能忽视。用户脚本拥有操作页面DOM和调用GM API的权限如果作者居心不良它完全可以在你登录的网站上读取表单内容、模拟点击按钮、甚至用GM_xmlhttpRequest把数据传到第三方接口。所以你安装任何来源的脚本之前至少要扫一眼它的源代码和权限声明。怎么快速判断一个脚本安不安全我的建议是看三处一看match是不是只匹配目标网站那些match *匹配所有网站的脚本要格外警惕二看grant有没有声明奇怪的权限如果服务器就一个成绩查询功能却要求GM_xmlhttpRequest多半有问题三看代码里有没有把数据发往不明域名的网络请求。如果以上都没问题再配合社区的评价和下载量做交叉参考基本能过滤掉九成以上有风险的脚本。这里顺便提一句合规意识你可以利用油猴脚本去增强自己的使用体验但不要用它去做破坏网站正常运营、绕过付费规则、抓取他人隐私数据之类的事情。玩脚本的边界在于不干扰他人、不破坏服务这是每个用户脚本作者都应该自觉遵守的底线。6.2 给脚本做备份和版本管理一个越用越顺手的脚本是需要长期迭代的。网站改版你会去改选择器浏览器升级你可能要调权限这些维护动作都需要你手里有清晰的版本记录。最简单的方式是在Tampermonkey设置里使用导出备份功能把所有脚本打包成一个文件保存到本地。这个文件包含了脚本代码和配置之后换电脑或者重装浏览器导入一下就能恢复。如果你想要更精细的管理可以在脚本注释里维护版本号每改一次就往上加并在description里简单写本次改了什么。听起来微不足道但等到几个月后你回来看一个脚本会发现版本号加上一行注释比面对一堆final_final_2.js式的文件名要舒服得多。另外Tampermonkey自带云同步功能可以把脚本同步到账号状态。如果你同时在多台设备上使用浏览器这个功能能省下不少事。但云同步只解决脚本文件本身不包含脚本里GM_setValue保存的数据所以对草稿这类业务数据还是要自己另做导出兜底。6.3 想把脚本发布给更多人发布前检查这几项当你积累了一些满意的脚本可能会想发布到脚本分享社区。发布之前我会过一遍下面这几个检查项既是对使用者负责也能减少后续差评和issue。第一最小权限原则。只保留实际用到的grant多余的全部删掉。第二匹配规则尽量收敛。如果脚本只针对具体网站就写具体网站的match不要写成通杀所有域名的*。第三代码可读性。发布前把注释补全把变量命名理顺不要用单字母变量名糊弄。第四做好异常提示。核心功能失败时要让用户知道为什么失败而不是默默吞掉异常。这四点做好了你的脚本在社区里的口碑基本不会差。发布之后也要做好被反馈的心理准备。用户会遇到各种你没有预料到的环境组合Windows系统的、macOS的、各种浏览器版本的一个脚本在不同环境下行为可能完全不同。收到反馈时别急着争辩先让对方提供浏览器版本、Tampermonkey版本和具体页面地址再配合控制台报错排查效率会高很多。最后说两句油猴脚本是一种典型的小工具解决大问题思路。它不追求复杂的架构不依赖后端服务就靠一段段独立的JavaScript代码精准地嵌入到你的日常浏览体验里。我从手忙脚乱地翻官方文档到现在能稳定维护十几个自用脚本中间最大的转变不是记住了多少API而是养成了任何重复操作都值得考虑用脚本自动化的意识。如果你刚开始接触建议不要贪多先把第一个能改变页面样式的脚本跑通然后逐步加入数据存储、菜单交互、消息提示这些能力。每往脚本里加一个功能你对浏览器运行机制的理解就会加深一层。等到某个晚上你突然发现自己写出了一个能坚持用半年也没坏的小工具那种满足感是单纯下载现成脚本给不了的。最后分享一个我在实际维护中常用的技巧定期打开Tampermonkey看一遍脚本列表凡是一个月以上没被触发过的脚本随手停用掉。这不是小题大做因为脚本越多你暴露给不信任代码的页面就越多浏览器负担也越大。保持脚本列表精简和保持代码简洁同样重要。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑