
1. 暴力猴到底是个什么东西第一次听到“暴力猴”这个名字很多人会以为是什么游戏外挂或者黑客工具。其实它就是一个浏览器扩展核心功能只有一件事让你在别人的网页上运行自己写的或者别人写好的JavaScript脚本。你可以把它理解成一个“网页改造器”——网页原本长什么样、有什么功能是网站开发者决定的装上暴力猴之后你就有了一支笔可以在网页加载完成后往上面涂改、添加、删除任何东西。我用了大概三年多的暴力猴从最开始只会装现成脚本到后来自己写脚本解决工作中的重复操作再到现在团队里十几个人的浏览器标配。这篇文章我会把暴力猴的完整使用链路讲清楚它解决什么问题、脚本从哪来、怎么装、怎么写、怎么调试、怎么管理、有哪些坑。不管你是完全没接触过的新手还是已经装过几个脚本但想深入的人应该都能找到有用的东西。暴力猴本身不提供任何脚本它只是一个运行环境。真正干活的是“用户脚本”——一段段JavaScript代码通过暴力猴注入到指定网页中执行。这些脚本能做的事情包括但不限于去掉网页广告、解锁复制限制、批量下载文件、自动填写表单、修改页面样式、抓取数据导出表格、给网页添加快捷键、跳过视频片头等等。只要你能想到的网页操作基本都能通过用户脚本实现。适合读这篇文章的人大概有三类一是每天要在网页上做大量重复操作的人比如运营、数据分析、行政二是对前端有一点了解、想通过脚本提升效率的开发者三是纯粹对浏览器自动化感兴趣、想找个切入点上手的人。下面我按实际使用的流程来展开每一步都会说清楚为什么这么做、怎么做、做了之后会怎样。2. 用户脚本的获取渠道与筛选方法2.1 脚本来源的几种类型用户脚本的获取渠道主要有这么几个第一类是脚本托管平台最知名的是Greasy Fork上面有海量的用户脚本按功能分类支持搜索和评分第二类是GitHub很多脚本作者会把源码放在仓库里适合想看代码或者自己改的人第三类是论坛和社区比如一些垂直领域的讨论区会有人分享针对特定网站的脚本第四类就是自己写这个后面会详细讲。Greasy Fork是我最常用的来源。它的脚本页面会显示脚本名称、作者、适用网站、安装量、评分、最近更新时间、代码行数等信息。这些信息非常关键因为用户脚本有一个天然的风险它运行在你的浏览器里能读取和修改你访问的网页内容。如果一个脚本作者写了恶意代码理论上可以窃取你在该网站上的数据。所以筛选脚本的时候安装量和评分是第一个参考维度最近更新时间是第二个——如果一个脚本两年没更新了大概率已经失效了。2.2 判断一个脚本是否值得安装我总结了一个简单的判断流程每次装新脚本之前都会过一遍看适用网站脚本页面上会写明它匹配哪些网址。如果匹配范围是*://*/*所有网站就要多留个心眼除非是那种通用工具类脚本比如网页暗色模式否则一个针对特定网站的脚本不应该匹配所有网址。看代码行数和权限Greasy Fork上可以直接看代码。如果脚本很短几十行基本能快速扫一眼它在干什么。如果很长几千行至少看看开头有没有GM_xmlhttpRequest这种跨域请求的权限申请以及有没有往陌生服务器发送数据的操作。看更新时间和反馈最近更新在半年内的比较可靠。评论区如果有大量“失效了”“报错了”的反馈说明脚本可能已经跟不上网站改版了。看作者的其他脚本如果同一个作者发布了很多脚本而且都有不错的安装量可信度会高一些。注意不要安装来源不明的脚本。尤其是那种通过私聊、群聊发过来的.user.js文件没有经过平台审核风险很高。尽量从Greasy Fork或GitHub这类可以查看源码和社区反馈的地方获取。2.3 脚本安装的实际操作安装脚本的流程很简单但有几个细节值得说清楚。当你在Greasy Fork上点击“安装此脚本”按钮时浏览器会跳转到一个.user.js文件地址暴力猴会拦截这个请求并弹出安装确认页面。页面上会显示脚本的名称、版本、作者、匹配的网址范围、以及它申请的特殊权限比如跨域请求、访问本地存储等。这里有一个很多人忽略的点安装确认页面上的“匹配网址”是可以手动修改的。比如一个脚本原本只匹配https://example.com/*你可以改成https://example.com/specific-page/*来缩小生效范围避免在不必要的页面上运行。反过来也可以扩大范围但一般不建议这么做。安装完成后脚本会出现在暴力猴的管理面板里。面板里可以看到所有已安装的脚本每个脚本可以单独开启或关闭、编辑代码、检查更新、删除。我习惯把脚本按用途分组比如“工作效率”“网页净化”“数据抓取”三类虽然暴力猴本身没有分组功能但可以通过命名前缀来实现比如[效率] 自动填写周报。3. 暴力猴的核心功能与配置详解3.1 管理面板的各个模块暴力猴的管理面板是日常使用中最常打交道的地方。面板顶部有几个标签页已安装脚本、实用工具、设置、关于。已安装脚本页面是主界面列出了所有脚本每个脚本右侧有开关按钮和操作菜单。操作菜单里包含编辑、更新、导出、删除等选项。“实用工具”标签页里有两个很实用的功能一个是“检查脚本更新”可以一键检查所有已安装脚本是否有新版本另一个是“导入/导出”可以把所有脚本打包成一个压缩文件方便换电脑或者重装浏览器时迁移。我每次换工作环境第一件事就是导出脚本包到新环境导入省去一个个重装的麻烦。设置页面里值得关注的选项包括脚本更新频率默认每周检查一次可以改成每天、编辑器主题写脚本时用深色还是浅色、以及“配置模式”的高级选项。配置模式里可以设置脚本运行的默认行为比如是否允许脚本在iframe中运行、是否启用同步功能等。3.2 脚本的匹配规则与运行时机用户脚本的元数据块就是脚本开头那段注释里有几个关键指令决定了脚本在什么页面、什么时机运行match指定脚本生效的网址模式。支持通配符比如*://*.example.com/*匹配example.com的所有子域名和路径。include和exclude和match类似但语法更灵活可以用正则表达式。run-at决定脚本在页面加载的哪个阶段执行。可选值有document-start页面开始加载时、document-endDOM加载完成时、document-idle页面完全加载后。默认是document-end。grant声明脚本需要使用的特殊API权限。比如GM_setValue和GM_getValue用于跨页面存储数据GM_xmlhttpRequest用于发起跨域请求。run-at的选择很关键。如果你要修改页面上的某个元素但那个元素是异步加载的用document-end可能拿不到这时候要么用document-idle要么在脚本里自己写一个轮询等待元素出现。我一般先用document-end如果发现元素找不到再改成document-idle或者加一个MutationObserver来监听DOM变化。3.3 数据存储与跨域请求暴力猴提供了几个专用的API让脚本可以做一些普通网页脚本做不到的事情。最常用的两个是存储和跨域请求。存储方面GM_setValue(key, value)和GM_getValue(key, defaultValue)可以在浏览器的本地存储里读写数据这些数据在脚本的所有匹配页面上都能访问。比如你写了一个脚本记录某个网站上的操作历史就可以用这两个API来存。数据是持久化的关掉浏览器再打开还在。跨域请求方面GM_xmlhttpRequest允许脚本向任意服务器发起HTTP请求不受同源策略限制。这个功能非常强大比如你可以写一个脚本在网页上添加一个按钮点击后把当前页面的数据发送到自己的服务器或者从别的API拉取数据展示在页面上。但这也意味着脚本有能力把你的数据发到外部所以安装脚本时看到这个权限要格外注意。提示如果你自己写脚本GM_xmlhttpRequest需要先在元数据块里声明grant GM_xmlhttpRequest否则调用会失败。另外这个API的用法和普通的fetch或XMLHttpRequest略有不同它是回调式的不是Promise式的写的时候要注意。4. 从零写一个用户脚本的完整流程4.1 确定需求与拆解步骤写脚本的第一步不是打开编辑器而是把需求想清楚。我一般会问自己三个问题这个操作我每天要做多少次每次花多长时间能不能用代码自动化举个例子我之前每天要在公司内部系统里导出前一天的订单数据流程是打开系统→登录→进入订单页面→选择日期→点击导出→等待文件下载→把文件移动到指定文件夹。整个流程大概两分钟每天做一次。虽然时间不长但很枯燥而且容易忘。于是我决定写一个脚本来自动化这个流程。拆解下来就是几个步骤页面加载后自动点击“订单”菜单→在日期选择器里填入昨天的日期→点击“导出”按钮→监听下载事件。每一步都需要在页面上找到对应的元素然后模拟点击或输入。4.2 编写脚本的基本结构一个用户脚本的基本结构包括元数据块和代码主体。元数据块用注释的形式写在最上面告诉暴力猴这个脚本叫什么、匹配什么网址、需要什么权限。代码主体就是普通的JavaScript可以用浏览器支持的任何API。下面是一个最简单的脚本模板功能是在页面加载完成后弹出一个提示// UserScript // name 我的第一个脚本 // namespace http://tampermonkey.net/ // version 1.0 // description 在页面加载后弹出提示 // author 我 // match https://example.com/* // grant none // /UserScript (function() { use strict; alert(页面加载完成); })();这个模板里match指定了脚本只在https://example.com下运行grant none表示不需要特殊权限。代码主体用了一个立即执行函数把逻辑包起来避免变量污染全局作用域。use strict开启严格模式能帮你避免一些常见的编码错误。4.3 元素定位与事件模拟写脚本最核心的技能是找到页面上的元素并操作它。浏览器开发者工具F12是必备的。你可以用“选择元素”工具点击页面上的任意元素然后在Elements面板里看到它的HTML结构。找到元素的id、class、或者独特的属性就可以用document.querySelector或document.querySelectorAll来定位。比如要点击一个按钮按钮的HTML是button idexport-btn classbtn primary导出/button那么代码就是const btn document.querySelector(#export-btn); if (btn) { btn.click(); }这里加了一个if (btn)的判断是因为页面元素可能还没加载出来。如果脚本在document-end阶段运行而按钮是异步加载的querySelector会返回null直接调用.click()就会报错。所以每次操作元素之前都要判空。对于输入框不能直接改value属性因为很多框架比如React、Vue会监听input事件来更新内部状态。正确的做法是模拟用户输入const input document.querySelector(#date-input); if (input) { input.value 2024-01-01; input.dispatchEvent(new Event(input, { bubbles: true })); input.dispatchEvent(new Event(change, { bubbles: true })); }bubbles: true让事件冒泡到父元素这样框架的监听器才能捕获到。4.4 等待异步元素出现的几种方案异步加载是写用户脚本时最常见的难题。页面上很多元素不是一开始就有的而是通过AJAX请求或者前端框架动态渲染出来的。这时候有几种应对方案第一种是轮询。写一个setInterval每隔几百毫秒检查一次元素是否存在存在了就执行操作并清除定时器。简单粗暴但不够优雅。const timer setInterval(() { const el document.querySelector(#target); if (el) { clearInterval(timer); // 执行操作 } }, 500);第二种是MutationObserver。监听DOM变化当目标元素被添加到页面时触发回调。这种方式更精确不会做无用的轮询。const observer new MutationObserver((mutations, obs) { const el document.querySelector(#target); if (el) { obs.disconnect(); // 执行操作 } }); observer.observe(document.body, { childList: true, subtree: true });第三种是等待某个特定请求完成。如果元素是在某个AJAX请求返回后才出现的可以拦截XMLHttpRequest或fetch在请求完成后执行操作。这种方式最精确但实现起来也最复杂。我一般优先用MutationObserver因为它兼顾了精确性和简洁性。只有在目标元素的位置不固定、或者需要等待多个元素时才会用轮询。5. 脚本调试与问题排查实战5.1 调试工具与断点设置暴力猴的脚本编辑器自带一个简单的代码编辑界面但真正调试还是要在浏览器的开发者工具里。打开F12切换到Sources面板在左侧的文件树里找到“Tampermonkey”或“Violentmonkey”分组里面会列出所有正在运行的脚本。点击脚本文件就可以像调试普通JavaScript一样设置断点、查看变量、单步执行。我常用的调试流程是先在脚本的关键位置加console.log输出变量值看看执行到哪一步出了问题。如果逻辑比较复杂就在Sources面板里设断点一步步跟。断点调试的好处是可以看到调用栈和当前作用域里的所有变量比console.log高效得多。还有一个技巧是在脚本里加debugger;语句。当开发者工具打开时执行到这一行会自动暂停相当于一个临时的断点。调试完成后记得删掉否则每次都会暂停。5.2 常见报错与修复方法写脚本过程中遇到的报错大概有这么几类Cannot read property click of null说明querySelector没找到元素。原因可能是选择器写错了、元素还没加载出来、或者元素在iframe里面。检查选择器是否正确确认元素是否在iframe中如果在需要先获取iframe的contentDocument。GM_xmlhttpRequest is not defined忘了在元数据块里声明grant GM_xmlhttpRequest。加上重新安装即可。脚本不生效检查match是否匹配当前网址。可以在暴力猴面板里看脚本的开关是否打开以及当前页面是否在脚本的匹配范围内。有时候网址带了参数或者用了不同的域名match没覆盖到。脚本执行了但没效果可能是操作的元素不对或者事件没有正确触发。用开发者工具检查元素的实际状态确认操作是否生效。5.3 脚本冲突与性能问题当你装了很多脚本时可能会出现脚本之间互相干扰的情况。比如两个脚本都修改了同一个元素的样式或者都监听了同一个事件。排查方法是逐个禁用脚本看问题是否消失然后定位到具体的冲突脚本。性能问题也值得注意。如果一个脚本在document-start阶段运行并且做了大量DOM操作会明显拖慢页面加载速度。我一般会把不必要的操作延迟到document-idle或者用requestIdleCallback在浏览器空闲时执行。另外MutationObserver如果监听范围太大比如监听整个document的subtree也会影响性能尽量缩小监听范围。提示定期清理不再使用的脚本。每个脚本都会占用一点内存和CPU装了几十个脚本之后浏览器会明显变慢。我一般每个月检查一次把失效的、不再需要的脚本删掉。6. 浏览器自动化的进阶玩法6.1 批量操作与循环处理用户脚本最强大的地方在于可以批量处理重复操作。比如你有一个列表页面每行都有一个“审核”按钮你需要逐个点击。手动点几十次很累用脚本就可以自动遍历所有行依次点击。const buttons document.querySelectorAll(.audit-btn); buttons.forEach((btn, index) { setTimeout(() { btn.click(); }, index * 1000); // 每隔1秒点一个避免请求过快 });这里用setTimeout做了延迟是因为很多系统对请求频率有限制点太快会被拦截或者导致数据错乱。延迟的时间根据实际情况调整一般500毫秒到2秒之间。6.2 数据抓取与导出另一个常见需求是把网页上的数据抓下来整理成表格。比如商品列表页有几十个商品每个商品有名称、价格、销量你想导出成Excel。用脚本可以自动遍历页面提取数据然后生成CSV文件下载。const rows document.querySelectorAll(.product-row); const data []; rows.forEach(row { const name row.querySelector(.name)?.textContent.trim(); const price row.querySelector(.price)?.textContent.trim(); const sales row.querySelector(.sales)?.textContent.trim(); data.push([name, price, sales]); }); // 生成CSV const csv data.map(row row.join(,)).join(\n); const blob new Blob([\ufeff csv], { type: text/csv;charsetutf-8 }); const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download data.csv; a.click(); URL.revokeObjectURL(url);注意\ufeff是BOM头加上之后Excel打开CSV不会乱码。?.是可选链操作符如果元素不存在会返回undefined而不是报错。6.3 页面样式改造与广告净化除了功能自动化用户脚本还可以用来改造页面样式。比如把某个网站的背景改成暗色、把字体调大、隐藏侧边栏广告等。这类脚本的原理就是往页面里注入CSS。const style document.createElement(style); style.textContent .ad-banner { display: none !important; } body { background: #1a1a1a; color: #e0e0e0; } .content { max-width: 900px; margin: 0 auto; } ; document.head.appendChild(style);!important用来覆盖原有的样式。这种脚本写起来简单效果立竿见影适合对CSS有基本了解的人。6.4 快捷键与自定义交互给网页添加快捷键也是常见需求。比如按CtrlS保存当前页面数据、按Alt1切换到某个标签页等。实现方式是监听keydown事件document.addEventListener(keydown, (e) { if (e.ctrlKey e.key s) { e.preventDefault(); // 阻止浏览器默认的保存行为 // 执行自定义保存逻辑 saveData(); } });e.preventDefault()用来阻止浏览器的默认行为比如CtrlS默认是保存网页CtrlP默认是打印。如果不阻止你的自定义逻辑和默认行为会同时触发。7. 脚本管理与长期维护经验7.1 版本管理与备份策略用户脚本虽然不像正式项目那样需要严格的版本管理但养成好习惯能省很多事。我每个脚本的元数据块里都会写清楚version和description每次修改后递增版本号。这样在暴力猴面板里能一眼看出哪个脚本最近更新过。备份方面我每周会把所有脚本导出一次存到云盘里。导出的文件是一个压缩包里面包含所有脚本的.user.js文件和暴力猴的配置文件。换电脑或者重装系统时导入这个压缩包就能恢复所有脚本和设置。如果脚本比较复杂我还会在GitHub上建一个私有仓库把脚本源码放进去。这样不仅有版本历史还能在不同设备之间同步。暴力猴本身也支持通过云存储同步脚本但需要配置我嫌麻烦就没用手动导出导入也够用了。7.2 脚本失效的应对流程网站改版是用户脚本最大的敌人。一个脚本可能今天还好好的明天网站一更新就失效了。遇到这种情况我的处理流程是先确认是不是脚本的问题。禁用脚本手动操作一遍看网站本身是否正常。打开开发者工具检查脚本操作的元素是否还存在。如果元素的id或class变了更新选择器即可。如果页面结构变化很大可能需要重写部分逻辑。如果脚本是从Greasy Fork装的去看看评论区有没有人反馈同样的问题或者作者有没有发布更新。如果作者长期不更新可以考虑自己接手维护或者找替代脚本。我一般会在脚本里加一些容错逻辑比如元素找不到时输出一条警告日志而不是直接报错。这样即使网站小改版脚本也不会完全崩溃只是部分功能失效方便定位问题。7.3 安全使用的基本原则最后再强调一下安全问题。用户脚本运行在你的浏览器里拥有和你相同的权限。一个恶意脚本可以读取你在任何匹配网站上的数据包括登录凭证、聊天记录、支付信息等。所以只从可信来源安装脚本优先选择开源、有社区反馈的脚本。安装前看一眼代码特别是match的范围和grant的权限。定期检查已安装的脚本删除不再使用的。不要在涉及敏感信息的网站上随意安装脚本。如果自己写脚本不要把敏感数据硬编码在代码里也不要把数据发送到不可信的服务器。注意暴力猴本身是一个工具工具没有好坏关键在于怎么用。用它来提升效率、简化操作它就是好帮手用来做违规的事情后果自负。8. 我个人的一些实操体会写了这么多最后分享几个我在实际使用中总结的小经验。第一个是关于脚本的命名我习惯用[场景] 功能描述的格式比如[内部系统] 自动导出订单、[论坛] 屏蔽特定用户这样在面板里一眼就能找到想要的脚本。第二个是关于代码复用很多脚本里都有“等待元素出现”“模拟输入”这类通用逻辑我会把这些抽成一个公共函数库每个脚本通过require引入避免重复写。第三个是关于调试效率我发现在脚本里加一个简单的日志面板比console.log更直观。就是在页面角落创建一个固定定位的div把日志输出到里面这样不用开开发者工具就能看到脚本的运行状态。代码大概是这样const logPanel document.createElement(div); logPanel.style.cssText position:fixed;bottom:10px;right:10px;background:rgba(0,0,0,0.8);color:#0f0;padding:8px;font-size:12px;max-height:200px;overflow:auto;z-index:99999;; document.body.appendChild(logPanel); function log(msg) { const line document.createElement(div); line.textContent [${new Date().toLocaleTimeString()}] ${msg}; logPanel.appendChild(line); logPanel.scrollTop logPanel.scrollHeight; }这个面板在调试复杂脚本时特别有用能实时看到每一步的执行情况。调试完成后把相关代码删掉或者注释掉就行。第四个体会是关于心态。写用户脚本这件事入门很容易写一个能用的脚本可能只需要十几行代码。但要做到稳定、健壮、能长期使用需要不断迭代。网站会改版需求会变化脚本也要跟着更新。把它当成一个持续维护的小项目而不是一次性的工具这样才能真正发挥它的价值。