前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >油猴脚本入坑指南

油猴脚本入坑指南

作者头像
子润先生
修改于 2021-06-10 03:24:30
修改于 2021-06-10 03:24:30
4.5K00
代码可运行
举报
运行总次数:0
代码可运行

基础

这部分主要是开始写油猴脚本前应当有所了解的知识

常见的用户脚本管理器

  • Tampermonkey 应该是各位见得最多的也是最知名的,好用又稳定,多浏览器支持,我很喜欢
  • Greasemonkey 用户脚本始祖,我们现在一直习惯说的油猴脚本的“油猴”实际上就是 Greasemonkey,只支持 Firefox 由于与 Tampermonkey 等其它脚本管理器在 API 的使用上会有些区别,导致某些情况下你很难保持你的脚本同时对 Greasemonkey 兼容,我一般直接放弃兼容
  • Violentmonkey 由国人开发的一款脚本管理器,界面好看,我很喜欢

元数据

即每个油猴脚本都有的,脚本开头很多行注释的内容,这是油猴脚本关键的基础部分,刚开始接触可能会一头雾水,但你绝不能忽视这部分内容

建议:

  1. 多参考别人的脚本,能对各个字段的意义了解个大概
  2. 阅读官方 wiki,有每个字段详细的介绍 如果你觉得读鸟语实在是很头疼,你也可以阅读由他人维护的中文 GreaseMonkey 用户脚本开发手册
  3. 不同的用户脚本管理器可能会加入自己独有的 meta,开发时建议以你的脚本打算主要支持的脚本管理器为主,例如这是 Tampermonkey 的文档

GM API

油猴提供了很多强大的 API,它们可以使很操作变得相当简单

注意每个 API 在使用前需要在元数据中用 @grant 进行声明,若你不打算使用这些 API,应当声明 @grant none

以下是一个简单的表格,帮助你了解油猴的 API 大概能做哪些事情

旧 API

新 API

说明

GM_info

GM.info

返回当前脚本的元数据

GM_addStyle

为网页添加 CSS

GM_setValue

GM.setValue

在本地储存值(只能是字符串),你可以将这个储存看作是 localStorage 一样的东西

GM_getValue

GM.getValue

获取使用储存的值

GM_deleteValue

GM.deleteValue

删除储存的值

GM_listValues

GM.listValues

返回一个由所有储存值的键名组成的数组

GM_getResourceText

获取元数据中定义的 @resource 的资源内容

GM_getResourceURL

GM.getResourceUrl

获取元数据中定义的 @resource 资源的 URL(base64 编码后的data:协议地址)

GM_openInTab

GM.openInTab

新标签页打开指定地址(用来绕过 Chrome 会阻止所有非用户触发的window.open的限制)

GM_registerMenuCommand

向油猴插件菜单中添加脚本指令(通常用于打开自己写的设置界面或者执行代码之类的)

GM_setClipboard

GM.setClipboard

复制指定内容到剪贴板

GM_xmlhttpRequest

GM.xmlHttpRequest

发送网络请求,且允许跨域

GM.notification

浏览器通知

新旧 API 的区别

Greasemonkey 从版本 4 开始向性能更高的异步模型发展,旧的 API GM_* 通常是同步的,而新的 API GM.* 是异步的(采用 Promise),在使用时请参考官方 wiki 并多加留意

并且,有些 API 的名称拼写也发生了变化,在上面的表格中已经用粗体标识

想了解更多信息可以阅读官方说明文章 Greasemonkey 4 For Script Authors

unsafeWindow

如果你在写脚本的时候有尝试直接通过 window 添加或访问网页全局变量,你会发现这是没有效果的

这是因为油猴的沙箱机制,任何人都无法从 window 直接访问到油猴的 API 或脚本内的变量,保证了安全

如果你确实需要访问 window,可以使用 unsafeWindow,但在正式发布的脚本中你不应该将任何油猴 API 或者脚本中的变量通过它暴露到 window 中

unsafeWindow 在不同脚本管理器中的表现可能会有所不同,特别是 Violentmonkey,如需考虑兼容性还需要多加测试

跨域请求

在油猴脚本中你可以引用网络脚本来使用 axios 之类的网络请求模块,这很方便,但同样也产生了局限性,例如由于浏览器机制的限制,你无法直接在网页上进行没有被事先允许的跨域请求

这时建议使用 GM.xmlHttpRequest,同时你应当在元数据用// @connect <value>声明允许被 GM.xmlHttpRequest 访问的域名

<value>可以是:

  • 域名,例如example.com,这也将允许所有子域
  • 子域,例如abc.example.com
  • self,即脚本运行的网址
  • localhost
  • IP 地址
  • *

如果你习惯用 axios 之类的用 Promise 封装的请求模块,你同样可以将 GM.xmlHttpRequest 封装成 Promise 形式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 复制1
2
3
4
5
6
7const xhr = option => new Promise((resolve, reject) => {
    GM.xmlHttpRequest({
        ...option,
        onerror: reject,
        onload: resolve,
    });
});

使用自己的 IDE 编写油猴脚本

一般脚本管理器自带的编辑器功能十分单一,全程在里面写代码肯定十分不爽,那么如何使用自己的 IDE 编写脚本并随时保存随时生效呢

答案是利用元数据的 @require,它不仅能引用网络脚本,还可以引用本地脚本,所以我们只要 require 用 IDE 编辑的本地脚本就行了

在这之前我们需要允许油猴插件访问本地文件,以 Chrome 为例,在扩展程序列表chrome://extensions/进入插件的详细信息,开启“允许访问文件网址”即可,接着就可以// @require file://<本地路径>的文件网址方式引用本地脚本了

引用 CSS

引用 JS 可以采用@require,但 CSS 不行

可行的方法有两种

  1. 老办法:用 JS 往<head>插入 CSS 的<link>
  2. API 方法:在元数据中声明// @resource mycss <地址>,然后GM_addStyle(GM_getResourceText('mycss')); 别忘了用到的这两个 API 也要@grant声明

进阶

这部分主要是写脚本的过程中有可能遇到的一些难点的较优解决方法

避免将 setInterval 用作动态监听的解决方案

初学 JS 的新手在遇到监听动态元素的问题的时候,由于缺乏经验,通常只能想到用 setInterval 去“每隔一段时间就检测一下”,当然这也包括我自己,但不管从性能上还是从实现复杂度来说,这都不是一个好选择,不够优雅

大部分类似的问题都可以在事件监听层面运用点技巧来解决

此处会列举几个常见的场景来说明一下解决思路

1. 监听动态生成的页面元素的事件

在有些时候我们可能要去监听动态生成的页面元素的事件,例如自动翻页加载的评论这类

  • 不好的思路 setInterval 每隔一段时间检测一下有没有新生成的页面元素,然后对这些页面元素添加事件监听
  • 好的思路 由于事件冒泡机制,我们可以监听其父级元素的点击事件,然后通过事件信息来确定被点击的元素currentTarget或其父级元素currentTarget.parentNode

不仅是动态的场景下可以这么做,当你需要针对一个很多元素的静态列表监听每个元素的事件时也可以这么做,这种方法最大的优点是你只需要添加一个事件监听,如果你对列表中的每个元素都添加事件监听,会增大内存开销,影响页面性能

有种比较特殊的情况:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 复制1
2
3
4
5
6
7<ul class="list">
    <li class="item">
        <img class="image" />
        ...
    <li>
    ...
</ul>

假设在该场景下,点击 .image 时它自身会被移除,而你需要得到被点击的 .image 所在的 .item,由于该 .image 已经被移出页面的 DOM 树,因此你无法通过点击事件的currentTarget.parentNode来得到 .item

最简单的解决方案是在事件发生时获取鼠标所在的 .item,例如使用 jQuery$('.item:hover')

2. 对动态生成的页面元素进行修改

假设一个场景,此处借用一下 vue 的语法来说明页面元素逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 复制1
2
3
4
5
6
7
8
9<!-- Init: showA = true; showB = false; -->
<ul class="list">
    <li class="item">
        <div v-if="showA" class="item-a" @click="showA = false; doSth().then(() => { showB = true });">...</div>
        <div v-if="showB" class="item-b">...</div>
        ...
    <li>
    ...
</ul>

大致就是,当你点击 .item-a 的时候,.item-a 会被移除,并在一个异步函数doSth()完成后显示 .item-b

你当前的目标是要在 .item-b 出现的时候修改其内容

  • 不好的思路 监听 .item-a 的点击事件,setInterval 每隔一段时间检测一下当前 .item 内有没有 .item-b,有的话就进行修改然后终止该 interval
  • 好的思路 监听 .item-a 的点击事件,当其被点击后监视 .item 的 DOM 变化,若新增了 .item-b 就对其进行修改

是时候祭出 MutationObserver 了,利用它我们可以监视 DOM 树的改动,同时它也是过去的 Mutation Events 的替代品

上面所说的场景可以按这个思路来解决

  1. 监听 .list 的点击
  2. 当触发点击事件时,找到 :hover 状态的 .item,对其添加 MutationObserver
  3. 当 MutationObserver 监视到 .item-b 被添加时,修改 .item-b,并disconnect()该 MutationObserver

写成代码大概像这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 复制1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25const findItemB = $item => new Promise((resolve, reject) => {
    if ($item.length === 0) reject();
    // 有可能此时 .item-b 已经出现,所以先检查下
    const $itemB = $item.find('.item-b');
    if ($itemB.length > 0) {
        resolve($itemB);
        return;
    }
    // 监视 .item 的 DOM 树 childList 变化
    new MutationObserver((mutations, self) => {
        mutations.forEach(({ addedNodes }) => {
            addedNodes.forEach(node => {
                if (node.className !== '.item-b') return;
                self.disconnect();
                resolve($(node));
            });
        });
    }).observe($item[0], { childList: true });
});

$('.list').click(async ({ target }) => {
    if (target.className !== 'item-a') return;
    const $itemB = await findItemB($('.item:hover'));
    // do something with $itemB
});

补充

推荐的一些可能会常用的模块

Github

BootCDN

用途

jquery-pjax

Link

为页面添加 pjax 支持

jquery-mousewheel

Link

为 jQuery 添加鼠标滚轮事件的支持

FileSaver.js

Link

另存为任意 blob 为文件

jszip

Link

读写创建压缩文件

gif.js

Link

制作 gif,支持 worker 方式

clipboard.js

Link

虽然油猴提供剪贴板 API,但该模块可以提供一些扩展功能,例如 tooltips 反馈等

dragula

Link

提供页面元素的拖拽调序功能

toastr

Link

方便的显示页内通知

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
5 分钟,教你从零快速编写一个油猴脚本!
Tampermonkey,又称 Greasemonkey 油猴脚本,是一款免费的浏览器扩展,可用于管理用户脚本,它本质上是对浏览器接口的二次封装
AirPython
2022/05/22
3.3K0
5 分钟,教你从零快速编写一个油猴脚本!
从零实现的浏览器Web脚本
在之前我们介绍了从零实现Chrome扩展,而实际上浏览器级别的扩展整体架构非常复杂,尽管当前有统一规范但不同浏览器的具体实现不尽相同,并且成为开发者并上架Chrome应用商店需要支付5$的注册费,如果我们只是希望在Web页面中进行一些轻量级的脚本编写,使用浏览器扩展级别的能力会显得成本略高,所以在本文我们主要探讨浏览器Web级别的轻量级脚本实现。
WindRunnerMax
2023/11/04
9150
油猴脚本编写教程
油猴脚本(Tampermonkey)是一个非常流行的浏览器扩展,它可以运行由广大社区编写的扩展脚本,来实现各式各样的功能,常见的去广告、修改样式文件、甚至是下载视频。今天我们就来看看如何编写自己的油猴脚本。当然为了运行油猴脚本,你应该在浏览器中安装油猴插件。
乐百川
2020/02/18
7.4K0
油猴脚本编写教程
从油猴脚本管理器的角度审视Chrome扩展
在之前一段时间,我需要借助Chrome扩展来完成一个需求,当时还在使用油猴脚本与浏览器扩展之间调研了一波,而此时恰好我又有一些做的还可以的油猴脚本 TKScript (点个star吧 😁),相对会比较熟悉脚本管理器的能力,预估是不太能完成需求的,所以趁着这个机会,我又学习了一波浏览器扩展的能力。那么在后来需求的开发过程中,因为有些能力是类似于脚本管理器提供的基础环境,致使我越来越好奇脚本管理器是怎么实现的,而实际上脚本管理器实际上还是一个浏览器扩展,浏览器也并没有给脚本管理器开后门来实现相关能力,而让我疑惑的三个问题是:
WindRunnerMax
2024/05/14
3970
油猴脚本重写fetch和xhr请求
写过几个油猴脚本,经常对页面请求返回的数据进行拦截或者覆盖,这篇文章就做个总结,涉及到 fetch 和 xhr 两种类型的请求。
windliang
2022/09/27
3.9K0
油猴脚本重写fetch和xhr请求
油猴脚本下载安装使用教程 油猴 tampermonkey 脚本全流程指南
篡改猴 (Tampermonkey) 是拥有 超过 1000 万用户 的最流行的浏览器扩展之一。 它适用于 Chrome、Microsoft Edge、Safari、Opera Next 和 Firefox。
小焱
2025/06/08
9270
油猴脚本下载安装使用教程 油猴 tampermonkey 脚本全流程指南
使用 Tampermonkey 编写高级跨网站自动化任务脚本
为了照顾读者中一部分对 Tampermonkey(国内成油猴,以下都简称 TM)不熟悉的读者,这里我借助官方对 TM 的介绍和教程帮助入门用户做以下介绍。
拿我格子衫来
2022/01/24
5.5K0
使用 Tampermonkey 编写高级跨网站自动化任务脚本
油猴脚本:快速打开粘贴的多个网址
你好,我是喵喵侠。今天我将为你介绍一个非常实用的油猴脚本,可以帮助你快速打开多个粘贴的网址链接。在日常工作中,我们可能会遇到需要批量打开多个网页的情况,如果手动逐个打开,不仅耗时费力,而且容易出错。为了提高效率,我们可以利用油猴脚本来自动化这一过程。
喵喵侠
2024/08/04
5060
油猴脚本:快速打开粘贴的多个网址
国培计划油猴脚本
国培计划油猴脚本 功能 跳过确认按钮,一直学呀学 视频0.1倍速 老师培训网址http://study.teacheredu.cn // ==UserScript== // @name 2021教师能力提升 // @namespace http://tampermonkey.net/ // @version 0.1 // @description 跳过确认按钮,一直学呀学 // @AuThor bhl // @match http://study.
纯情
2023/04/26
6800
最新Tampermonkey 中文文档解析(附基础案例和高级案例)
@homepage, @homepageURL, @website and @source
拿我格子衫来
2022/01/24
5.8K0
油猴脚本从编写到检测
油猴脚本是在沙盒里执行用户脚本,不会对网页注入script元素,它通过沙盒向网页中传递信息以达到控制dom的操作。所以如果要对脚本进行检测,没有像上面代码这样子向页面中植入iframe的话,通过去检测dom和window是无法检测出使用油猴脚本的。
sugarbeet
2022/09/26
5.3K0
油猴脚本从编写到检测
油猴脚本实用大全
Tampermonkey(油猴),是一款免费的基于浏览器的扩展插件,它本身并不具备能影响浏览器的功能,需要安装其他脚本来发挥特殊的功能。也就是说,他是一个脚本管理器。
鸣奔博客
2023/03/31
1.7K0
油猴脚本实用大全
油猴脚本:markdown生成带网页标题的链接
你好,我是喵喵侠。在日常浏览网页和编写Markdown文档时,我们常常需要将网页链接插入到Markdown文档中,并附上网页的标题。然而,手动复制链接和标题不仅耗时,而且容易出错。为了解决这个问题,我们可以编写一个油猴脚本(Tampermonkey Script),自动生成带网页标题的Markdown格式链接。本文将详细介绍如何实现这一功能。
喵喵侠
2024/08/03
3920
油猴脚本:markdown生成带网页标题的链接
油猴脚本制作微信公众号批量添加全局可转载账号脚本
简单的说,在控制台执行的任何 js 操作,处理 dom 、发送网络请求等,都可以通过油猴脚本在某个网站打开的时候去自动执行。
windliang
2022/09/23
1.5K0
油猴脚本制作微信公众号批量添加全局可转载账号脚本
Web自动化测试 | 充分利用浏览器记录的信息
一切和效率提升,质量提高相关的工具/脚本都隶属于自动化的测试范围,所以这里要介绍的不是单纯的UI自动化和接口测试脚本。
京东技术
2018/09/28
1.7K0
Web自动化测试 | 充分利用浏览器记录的信息
油猴脚本去水印实现原理
上周微信公众号推出了一种新的形式,类似小红书这样子,群里有小伙伴调侃,是否是小红书的产品经理跳槽到微信了,那作为一个公众号运营者,我也想利用这一点。那么如何快速设计出好看的小红书封面,便成了我的目标。我在 google 上搜索到了一篇文章,可以通过一个好用的网站,比格设计,设计出好看的封面。它跟稿定设计一样,也是一个在线制图的网站,当然如果你没开会员的话,下载下来也是有水印的。那么我在想,是否也可以写一个油猴脚本来实现白嫖呢?
狂奔滴小马
2023/03/18
1.5K0
油猴脚本去水印实现原理
自媒体创作利器:借助油猴脚本助你轻松应对热门话题
对于做短视频自媒体的同学来说,在上传视频时需要指定多个热门话题,以此来增加短视频的流量
AirPython
2023/11/20
5261
自媒体创作利器:借助油猴脚本助你轻松应对热门话题
如何通过 Tampermonkey 快速查找 JavaScript 加密入口
在很多情况下,我们可能想要在网页中自动执行某些代码,帮助我们完成一些操作。如自动抢票、自动刷单、自动爬虫等等,这些操作绝大部分都是借助 JavaScript 来实现的。那么问题来了?在浏览器里面怎样才能方便地执行我们所期望执行的 JavaScript 代码呢?在这里推荐一个插件,叫做 Tampermonkey。这个插件的功能非常强大,利用它我们几乎可以在网页中执行任何 JavaScript 代码,实现我们想要的功能。
崔庆才
2020/01/02
2.5K0
浏览器用户脚本—打造自己的专属页面
一段用户脚本就是一个程序,通常用JavaScript语言来写,用于修改web页面以提升浏览体验。通常通过浏览器的用户脚本管理插件来开启,例如Tampermonkey、Greasemonkey等。
俗可耐
2018/11/07
5.5K2
浏览器用户脚本—打造自己的专属页面
【油猴脚本】在 Iconfont 上直接复制 React component 代码
在上文中介绍了使用 iconfont 的缺点,以及使用 SVG 的优点,简单归纳为以下几点:
狂奔滴小马
2022/09/16
2.1K0
【油猴脚本】在 Iconfont 上直接复制 React component 代码
推荐阅读
相关推荐
5 分钟,教你从零快速编写一个油猴脚本!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验