油猴脚本入门实战:自动处理算术验证码的完整指南
1. 从零上手油猴脚本一个自动处理算术验证码的完整实践很多人第一次听到“油猴脚本”这个词脑子里浮现的可能是某种黑客工具或者觉得这玩意儿离自己特别远。其实说白了油猴脚本就是一段运行在浏览器里的 JavaScript 代码它能在你打开某个网页的时候自动帮你干一些事情——比如把页面上的广告藏起来、把按钮变大、自动填表单或者像我这次要聊的自动把算术验证码算出来填进去。我接触油猴脚本的契机很偶然。那阵子我经常需要在一个内部测试平台上反复提交数据每次提交前都要回答一道“3 7 ?”这样的算术题。题目本身不难但架不住次数多几十次下来人就烦了。于是我就想能不能让浏览器自己把这道题算出来填进去顺着这个思路摸索了一阵发现油猴脚本正好能干这事而且门槛比我想象的低得多——只要你会一点点 JavaScript 基础甚至只会复制粘贴加改数字就能跑起来。这篇文章就是把我从零开始折腾油猴脚本的整个过程整理出来。我会讲清楚油猴脚本到底是什么、怎么安装、怎么定位页面上的算术题、怎么把答案填回去以及中间踩过的那些坑。适合完全没有接触过油猴脚本、但想试着写一个自己用的小工具的人。不需要你有多深的编程功底能看懂基本的加减乘除和变量赋值就够了。2. 油猴脚本到底是什么先搞懂原理再动手2.1 油猴脚本的运行机制油猴脚本的正式名字叫 UserScript它本质上是一段 JavaScript 代码通过一个浏览器扩展最常见的是 Tampermonkey中文常叫“篡改猴”来管理和注入。这个扩展会在你访问网页的时候根据你设定的规则把对应的脚本代码“塞”进网页里执行。网页本身并不知道这段代码是外来的它就像网页自己的一部分一样运行。打个比方网页是一栋已经装修好的房子油猴脚本就是你偷偷带进去的一套智能家居设备。房子还是那栋房子但灯可以自动亮了、窗帘可以自动拉了。你不需要改动房子的结构只需要在门口扩展登记一下说“我进这栋房子的时候帮我把这套设备装上”。这个机制决定了油猴脚本的几个特点第一它运行在网页的上下文里能直接读取和修改页面上的元素第二它不需要你拥有网站的源代码也不需要网站提供任何接口第三它只在你自己的浏览器里生效不会影响别人。2.2 为什么选油猴脚本而不是别的方案面对“自动填算术题”这个需求其实有好几种技术路线可以选。我当初也对比过最后选油猴脚本是有原因的。方案优点缺点适用场景油猴脚本轻量、即写即用、不需要额外环境只在自己浏览器生效、依赖页面结构个人自动化、小工具浏览器控制台手敲零安装每次刷新都要重敲、无法持久一次性调试自动化测试框架功能强大、可跨页面环境配置复杂、学习曲线陡大规模自动化测试后端接口直接调用效率最高需要逆向接口、门槛高有开发能力的场景对于我这种“就想让自己浏览器自动填个答案”的需求油猴脚本是最合适的。它不需要我装 Python、不需要配驱动、不需要分析网络请求打开编辑器写几行代码保存刷新页面就能看到效果。这种即时反馈对新手特别友好。2.3 算术验证码的常见形态在动手写代码之前得先搞清楚要对付的算术题长什么样。我观察下来常见的算术验证码大概有这么几种形态纯文本形式页面上直接显示“5 3 ?”答案输入框就在旁边。这种最好处理直接读文本、解析数字、计算、填回去。图片形式算术题被渲染成一张图片比如“7 × 6 ?”画在 canvas 或 img 里。这种就麻烦一些要么做图像识别要么想办法拿到图片背后的原始数据。动态生成形式题目由 JavaScript 动态生成每次刷新数字都变但生成逻辑在页面代码里能找到。我遇到的是第一种纯文本形式这也是最适合新手练手的类型。后面我会重点讲这种同时也会提一下如果遇到图片形式该怎么考虑。3. 开发前的准备工作环境、工具与基础知识3.1 安装脚本管理器第一步是给浏览器装一个脚本管理器。市面上有好几个选择我用的是 Tampermonkey它在主流浏览器上都有对应的扩展。安装过程很简单打开浏览器的扩展商店搜索名字点安装就行。安装完成后浏览器工具栏上会出现一个小图标点开能看到管理面板。这里有个细节要注意不同浏览器对扩展的支持程度不一样。有些浏览器对扩展的审核比较严可能搜不到或者功能受限。如果遇到这种情况可以换一个对扩展支持更友好的浏览器来开发调试。我个人的习惯是开发阶段用一个浏览器日常使用用另一个避免脚本互相干扰。安装好之后建议先花几分钟熟悉一下管理面板。面板里能看到已安装的脚本列表、每个脚本的启用状态、以及一个代码编辑器。后面我们写的所有代码都在这个编辑器里完成。3.2 需要掌握的 JavaScript 基础油猴脚本用的是 JavaScript但你不需要成为 JS 高手。对于自动填算术题这个任务掌握下面这几个概念就够用了变量用来存东西的容器比如let answer 10;函数一段可以重复使用的代码块比如function add(a, b) { return a b; }DOM 操作读取和修改网页元素比如document.querySelector(.question)事件页面加载完成、按钮被点击等时机比如window.addEventListener(load, ...)字符串处理从一段文字里提取数字比如parseInt(5 3)如果你之前完全没接触过编程建议花一两个小时看一下 JavaScript 的基础语法。不用看太深把变量、函数、条件判断、循环这几个概念搞清楚就行。网上有很多免费的入门教程挑一个看得顺眼的跟着敲一遍。3.3 调试工具的准备写脚本免不了要调试浏览器自带的开发者工具就是最好的帮手。按 F12 或者右键选择“检查”就能打开。里面有几个面板特别有用Elements元素查看页面的 HTML 结构找到算术题对应的元素Console控制台运行 JavaScript 代码、查看输出和报错Sources源代码查看页面加载的脚本文件我调试的时候最常用的流程是先在 Elements 面板里找到算术题的元素看看它的标签名、class、id 是什么然后在 Console 里试着用document.querySelector把它选出来确认选择器写对了最后再把这些选择器用到油猴脚本里。提示在 Console 里测试选择器的时候如果返回null说明选择器没匹配到元素。这时候要检查是不是 class 名字写错了或者元素在 iframe 里、在 shadow DOM 里这些情况需要特殊处理。4. 核心实操一步步写出自动答题脚本4.1 新建脚本与元数据块打开 Tampermonkey 的管理面板点击“添加新脚本”会看到一个默认的模板。模板最上面是一段以// UserScript开头、// /UserScript结尾的注释块这叫元数据块。它告诉管理器这个脚本叫什么名字、在哪些网站上运行、什么时候运行。// UserScript // name 自动处理算术验证码 // namespace http://tampermonkey.net/ // version 1.0 // description 自动读取页面上的算术题并填写答案 // match *://*/* // grant none // /UserScript这里重点说一下match这一行。它决定了脚本在哪些网址上生效。*://*/*表示在所有网站上运行这样写方便测试但实际用的时候最好改成具体的网址避免在不相关的页面上瞎跑。比如你的目标页面是https://example.com/form那就写成match https://example.com/form*。grant none表示脚本不需要特殊的权限直接在当前页面环境里运行。对于读写页面元素这种操作none就够了。4.2 定位算术题元素脚本要做的第一件事是找到页面上的算术题。假设页面结构是这样的div classcaptcha span classquestion5 3 ?/span input typetext idanswer / button idsubmit提交/button /div那么用document.querySelector就能把题目文字取出来const questionEl document.querySelector(.captcha .question); const questionText questionEl.textContent; // 5 3 ?但实际页面往往没这么规整。可能 class 名字是随机生成的可能题目和输入框不在同一个父元素下可能页面上有多个类似的元素。这时候就需要多试几种选择器或者用更宽泛的匹配方式。我遇到的一个情况是题目文字和输入框之间隔了好几层 div而且 class 名字每次刷新都会变。后来我发现题目文字总是包含“ ?”这个特征于是改用遍历的方式const allSpans document.querySelectorAll(span); let questionText ; for (const span of allSpans) { if (span.textContent.includes( ?)) { questionText span.textContent; break; } }这种“按内容特征找元素”的思路在页面结构不稳定的时候特别管用。4.3 解析算术表达式并计算拿到题目文字之后下一步是把里面的数字和运算符提取出来。题目格式是“5 3 ?”我们需要得到 5、、3 这三个信息。最简单的方法是用正则表达式const match questionText.match(/(\d)\s*([\-×*])\s*(\d)/); if (match) { const num1 parseInt(match[1]); const operator match[2]; const num2 parseInt(match[3]); let answer; switch (operator) { case : answer num1 num2; break; case -: answer num1 - num2; break; case ×: case *: answer num1 * num2; break; } }这里有几个细节要注意。第一乘号可能是×也可能是*甚至可能是x正则里要把常见写法都覆盖到。第二减号的结果可能是负数要确认输入框是否接受负号。第三有些题目的数字可能是多位数\d能匹配一位或多位数字。如果题目里包含除法还要考虑除不尽的情况。不过大多数算术验证码为了简单一般只用加减乘除法出现得比较少。4.4 把答案填回输入框算出答案之后要把它填到输入框里。这里有个坑直接设置input.value有时候不生效因为有些页面会监听输入事件只有通过模拟用户输入才能触发页面的校验逻辑。const inputEl document.querySelector(#answer); inputEl.value answer; inputEl.dispatchEvent(new Event(input, { bubbles: true })); inputEl.dispatchEvent(new Event(change, { bubbles: true }));dispatchEvent这两行就是手动触发 input 和 change 事件让页面以为用户真的输入了内容。如果不加这两行有些页面提交的时候会提示“请输入答案”即使输入框里明明有值。4.5 处理页面加载时机油猴脚本默认在页面加载的早期就执行了这时候算术题的元素可能还没渲染出来。如果直接去查元素会得到null。解决办法是等页面加载完成再执行window.addEventListener(load, function() { // 这里放主要逻辑 });但load事件要等所有资源图片、样式表等都加载完才触发有时候太慢了。更精细的做法是用DOMContentLoaded或者用MutationObserver监听元素出现。我实际用下来最省事的方案是加一个轮询每隔几百毫秒检查一次元素是否存在存在就执行执行完就停止轮询。const timer setInterval(function() { const questionEl document.querySelector(.captcha .question); if (questionEl) { clearInterval(timer); // 执行主要逻辑 } }, 300);这个方案的好处是不依赖特定的事件不管页面是同步渲染还是异步加载只要元素最终会出现就能被捕获到。5. 进阶话题当算术题变成图片怎么办5.1 图片验证码的难点前面讲的都是纯文本算术题但现实中很多网站会把算术题渲染成图片。这时候textContent拿到的是空字符串因为图片里没有文字节点。面对图片验证码有几条路可以走图像识别用 OCR 技术把图片里的文字识别出来。这需要额外的库而且识别率受图片质量影响。找图片背后的数据有些网站生成图片的时候答案其实藏在页面的 JavaScript 变量里或者藏在图片的 alt 属性、data 属性里。模拟请求分析页面获取验证码的请求直接拿到题目数据。这需要一定的网络分析能力。对于新手来说我建议先看看图片元素有没有携带额外信息。比如img src/captcha.png alt7 2 ?>const img document.querySelector(.captcha img); img.style.transform scale(2); img.style.border 2px solid red;这种方案适合那些“题目本身不难就是找起来费劲”的场景。6. 常见问题与排查技巧实录6.1 脚本不生效的排查顺序脚本写完保存了刷新页面却没反应这是最常见的情况。我总结了一个排查顺序基本能覆盖大部分问题确认脚本已启用打开 Tampermonkey 面板看看脚本前面的开关是不是绿色的。确认 match 匹配当前网址如果 match 写的是特定网址而你测试的页面不在这个范围内脚本不会运行。打开控制台看报错按 F12 看 Console 面板如果有红色报错说明代码有问题。检查选择器是否匹配到元素在 Console 里手动运行document.querySelector(你的选择器)看返回什么。检查执行时机如果元素是异步加载的脚本可能在元素出现之前就执行完了。6.2 常见问题速查表问题现象可能原因解决办法脚本完全不运行match 不匹配、脚本未启用检查 match 和启用状态报错 querySelector 返回 null选择器写错、元素未加载在 Console 验证选择器、加轮询答案填了但提交失败未触发 input 事件手动 dispatchEvent答案算错正则没匹配对、运算符判断遗漏打印中间变量调试刷新后失效页面结构变化、class 随机改用内容特征匹配脚本影响其他页面match 范围太宽缩小 match 范围6.3 几个实用的调试技巧第一个技巧是善用console.log。在脚本的关键位置打印变量比如题目文字、解析出的数字、算出的答案这样能快速定位是哪一步出了问题。第二个技巧是在 Console 里直接测试代码片段。不用每次都改脚本、保存、刷新直接在 Console 里敲几行验证思路确认没问题再写进脚本。第三个技巧是给脚本加一个显眼的标记。比如在页面角落加一个红色小方块脚本运行了就显示没显示就说明脚本没跑起来。这比翻控制台快多了。const marker document.createElement(div); marker.textContent 脚本已运行; marker.style.cssText position:fixed;top:0;right:0;background:red;color:white;padding:4px;z-index:9999;; document.body.appendChild(marker);6.4 避坑经验页面结构变化与脚本维护油猴脚本有一个天然的脆弱性它依赖页面的结构。网站一改版class 名字一换脚本可能就失效了。我踩过几次坑之后总结了几条经验尽量用稳定的特征做选择器id 通常比 class 稳定语义化的属性比随机生成的 class 稳定。加容错处理如果找不到元素不要让脚本报错崩溃而是安静地退出或者重试。写注释过几个月回头看自己的脚本没有注释的话很可能看不懂当初为什么这么写。版本管理每次修改在元数据块里更新 version方便回溯。注意油猴脚本只应该用于你自己有权限操作的页面。不要用它去干扰别人的正常使用也不要用它绕过任何合理的访问控制。技术是用来提高效率的不是用来搞破坏的。7. 从这个小项目能延伸出什么自动处理算术验证码只是一个切入点油猴脚本能做的事情远不止这些。把这次学到的技能拆开来看其实包含了几个通用的能力定位页面元素、读取和修改内容、处理异步加载、调试和排错。这些能力组合起来可以做出很多实用的小工具。比如你可以写一个脚本把某个经常访问的页面上的关键信息提取出来整理成更易读的格式或者写一个脚本自动展开那些默认折叠的内容再或者写一个脚本给页面上的表格加上排序和筛选功能。思路都是一样的观察页面、找到规律、用代码把重复劳动自动化。我个人的体会是油猴脚本最大的价值不在于它能做多复杂的事情而在于它的门槛足够低低到你可以为了省几分钟的重复操作就去写一个。这种“随手造工具”的习惯一旦养成你会发现很多日常的电脑操作都可以被优化。刚开始可能只是自动填个验证码慢慢地你会开始想这个流程能不能自动化那个重复点击能不能省掉这种思维方式的转变比学会某个具体的 API 更有价值。最后分享一个小技巧如果你写了一个脚本觉得好用可以把它导出成.user.js文件备份起来。Tampermonkey 的面板里有导出功能导出的文件可以在其他浏览器或电脑上导入换设备的时候特别方便。另外元数据块里的description和name写清楚一点脚本多了之后才好找。