油猴子从入门到喵喵喵喵(实例:9/9 完结)

【本文为付费内容,如您尚未付费请点此】

【返回目录】 | 【上一章 油猴子用什么写】

油猴子的基本格式

校对完成,更新时间:2020-07-23 11:22:25

首先记住它会分为两部分:

  • 上面以注释形式出现的元数据
  • 下面要注入页面中的脚本代码

在各种编辑器中这两部分都会以不同的颜色进行显示,所以很容易区分,我们先来研究元数据。

元数据,这个名词又很新鲜,英文 meta。就是对脚本的一些基本信息的说明,或者你叫它头部信息什么的,只要能够顺畅的交流,叫什么名字其实并不太重要。而且好多翻译也确实做不到信达雅,反倒让人增加迷惑。所以不要太在意这些,小老鼠自己也完全搞不清楚这些名词,反正会写就完事儿了。

那么起到说明性的作用,就是说明书?!那就是不用读系列……

并不是哦!虽然也许不书写元数据部分在某些平台下它也是可以使用的。但元数据信息真的是非常重要。这就好像做好我们本职的工作这是份内的事情,而处理好人际关系,似乎并不在这个本职工作之内,但是大家都懂的,如果人际关系处理不好,那你的本职工作也很难顺利完成。所以在工作前先和各部门打好招呼,我要做什么事情了,大家要给予支持,然后相互协调,避免冲突。这些话虽然很套路,但是总还是要说一下的。

居然是套路,那应该就有模板。你在脚本管理器里去新建一个脚本,它就会自动填写上一些基本的元数据。比如我在暴力猴中新建一个脚本,得到的内容是下面这个样子的:

// ==UserScript==
// @name        New script - meta.appinn.net
// @namespace   Violentmonkey Scripts
// @match       https://meta.appinn.net/t/topic/17705
// @grant       none
// @version     1.0
// @author      -
// @description 2020/7/20 上午7:22:46
// ==/UserScript==

虽然全是英文,但也不用紧张,咱们要看的主要是格式。反正程序员一般都有强迫症,所以代码里你会看到许多整整齐齐的格式,很舒适的。

这里的第 1 行和第 9 行就是个固定格式,表示元数据的开始和结束,并且说明这是用户脚本。对,这又是一个我必须要给你们讲一下,但是你们并不一定需要记住的问题。反正每一次新建脚本模板都给好了,要不是需要给你们讲,我早都忘了这两行的事情……

每一行用双斜线开头,是表示这是注释不参与运行,这就避免了某些不兼容的情况下,这些元数据对脚本产生影响。

然后中间几行,前面有一个以 @ 开头的单词,然后一些空格,后面写了些内容。前面的单词是说这一行记录了什么信息,后面的内容就是对应的信息。

那么现在看第 2 行,@name 显然是说名字,空格后面的内容就是这个脚本的名字,我们可以根据自己的需求进行修改。

理解这一条后面的就都好理解了,因为书写的格式是一样的。现在的问题就是,我要知道都可以去设置哪些数据。对这个事情总是要有一个规范的,要不然像小老鼠这么碎嘴子的,能在上面写个长篇小说,固然会把该说的都说清楚了,但是脚本管理器表示宝宝并看不懂,不就鸡对鸭讲了么……(咦,好像哪里不太对的亚子

可用的元数据

在告诉大家有哪些元数据的字段(标签)可用之前要先做一些简要的说明:

  • 我们并不需要把所有可用的字段全写上,只要写自己用得上的那部分就好;
  • 有些字段是可以多次出现的,但有些就只能出现一次,这些我会进行标注,大家根据字段所表达的意思去理解为什么是这样;
  • 不同的脚本管理器,对元数据的支持也不相同,但基础部分大家基本是一致的。而且你即便写上了这个脚本管理器无法理解的字段,也不会产生负面影响。

如果你以前看过一些相关的内容,那么很容易理解我将要做什么,就是把这些元数据的字段罗列出来,挨个给大家解释。差不多等于把文档复制过来并翻译一遍。

但如果我真的那么做,我估计连篇累牍的内容能立刻劝退 1/3 的小伙伴。讲还是要讲的,我们就稍微换一个角度,对这些元数据做一个粗略的归类。

必须有的元数据

这也不是绝对的必须,不写也不是说完全不行。但如果你要去写元数据,我觉得应该没有人会拒绝把这几个项目写上去。

@name

脚本总要有个名字吧。要不以后怎么称呼它?嘿,那个脚本……

但这里存在一个误解,就是把它看得过分重要。其实比较准确的理解是这里大概相当于昵称。就是用来让人便于识别和称呼的,它也会用来显示在脚本列表等地方,让我们能够快速的了解这是哪一个脚本。

@namespace

命名空间,这名词又让人迷惑。而且上面已经有一个名字了,那就更让人迷惑。那你把它理解为用户(脚本) ID 好了。

我们和上面对照一下,昵称是用来称呼的,ID 是用来识别它就是它的。这就好像在微信里,我们可以经常的去修改昵称,但是微信号轻易是不能修改的。

在文档中的描述是:用 @name@namespace 的组合来识别脚本,但在不同的脚本管理器下可能有所区别。总之这两个内容设置好之后,尽量就不要修改了。尤其是 @namespace,如果修改肯定要引发问题。

自然也很容易理解,这两者不要和其他的脚本冲突。两个学生具有相同的名字或者相同的学号,就会让人很难分辨,然后引发错误。

@version

版本号,基本格式就是: 1.0.0 这样。第 1 位表示大版本,第 2 位表示小功能的增加,第 3 位表示细节的修补。

但是对于版本号也没有那么严格的要求,按着这个格式去书写就可以了,至于数字代表什么,或者你随便去写,都没所谓。比如现在浏览器的大版本号(第一位)就是随着时间固定的增长。而我自己写东西一般第 1 位就永远是 0,因为我一直认为自己写的东西不够完善,不足以发出一个正式的版本。

但是新版本的版本号一定要比旧版本的大,因为这是判断升级的一个依据。如果脚本管理器发现,线上的版本比当前已安装的版本版本号更高,那么这个脚本就可以进行升级。

@author

作者,这后面写上你的大名,愿意加上邮箱,也没人管你。或者加上一堆形容词。反正就是写清楚脚本的作者是谁,你一定不会希望别人用了这个脚本,却不知道它是你写的,那就真的变得默默无闻了。

@description

对于这个脚本的描述,它会显示在应用市场的简介中,就是脚本名字下面最先显示出来的那部分。在脚本列表中,显示的脚本信息也对应着这里的内容。

这里进行一些补充说明。上面这 4 个都只能出现一次哦,很容易理解的吧,我们总不能给一个脚本弄出两个名字来,两个版本号就更加荒唐了。如果有多个作者,那就都写在那一行里就好。对,一行。就算是描述也要写成一行,不要用回车换行。(别抬杠,抬杠就兼容性,不一定所有脚本管理器都支持特殊的格式,所以用最基本的格式最不容易出错)

@name@description 因为是描述性的内容,所以支持多语言,就是你可以为每一种语言单独设置一份名字和描述,具体格式如下:

// @name                My first user script.
// @name:zh-CN          我的第一个脚本
// @name:en-US          Meow~
// @description         dms is a sunshine boy.
// @description:zh-CN   小老鼠帅帅哒~
// @description:en-US   Delicacies

描述中建议写上脚本的创作日期和更新日期,这样方便自己日后回顾。如果你有强迫症,觉得在描述中混入这样的信息,让自己不舒服,也完全可以自己创造两个字段来标记,反正脚本管理器不理解就会把这些字段跳过去,但是自己看代码的时候是有意义的。

@match

这是描述这个脚本要在哪些网址下运行。如果和后面的网址匹配就运行。

但大多数时候我们的脚本并不只运行在某一个确定的网址下,而是希望在某个网站上都起作用,或者这个网站的某个分类下都起作用,这时候就要用到通配符。

网址会被分为三部分:协议、域名、路径。

https://www.appinn.com/auto-expand-full-text/

这样的一个网址,其中 https 就是协议,那我们知道还有 http 的协议。

www.appinn.com 这部分就是域名,表示的这是哪一个网站。

auto-expand-full-text/这部分,就是在域名后面那条斜线之后的部分,用来表达这个网站中的哪个页面,这就是路径。

然后对于每一部分,我们都可以完整准确的去写出它的内容,或者使用星号代替一定的字符。

如果在协议部分使用星号,那么代表的是:http 或者 https ,对,只有这两种协议,并不包含其他。

如果在域名部分只有星号,那么它匹配任何网站。如果域名的子域是星号(比如上面域名的 www 部分),那就表示这个域名下的任何子域(www 可以被换成任何内容)。

如果是路径位置的星号,它可以匹配 0 到任意多个字符。

*://*/*

所以像上面这样写就表示匹配任何协议下的任何网站的任何路径,就是在所有能运行的页面全都运行这个脚本。

*://www.appinn.com/*

上面这样写表示在这个网站下的所有页面都运行。

*://www.appinn.com/posts/*

上面这样写表示在这个网站下的 posts 目录下的页面中全都运行。

这个规则并不难掌握,因为它没有搞得很复杂。几种简单的情况,稍微熟悉一下就可以很好的掌握了。但这时候我们就会遇到一个很普通又很棘手的问题,都有很多网站,我们在域名部分写出下面两种形式都可以正常的访问:

www.appinn.com
appinn.com

就是加不加 www 都可以。但这就很难使用通配符进行表达。

*://*.appinn.com/*

这样前面不是 www 的也会被匹配,并不符合我们的预期。而且注意在星号后面多了一个点,所以这种书写方式并没有办法匹配到完全不加 www 的情况。

有同学可能说,反正星号可以代替各种字符,那我就这样写:

*://*appinn.com/*

先不考虑这个写法是不是真的符合规则。就算可以正常使用,那么会不会匹配到下面的网址:

https://meow-appinn.com/

这显然就完全是另外一个网站了,所以这样写的疏漏太大,是完全不可取的。正确的方法是,索性写两条规则好了,就像下面这样:

@match *://www.appinn.com/*
@match *://appinn.com/*

所以,@match 可以出现多条。把你需要适配的情况写完全,一条规则一行,就像上面这样书写就好。

可选的地址信息

写不写都可以,写上会更完善一些。

@homepage, @homepageURL, @website, @source

这是个选择题,4 选 1,因为表达的意思是一样的。由此可见,对于脚本的元数据,大家创造了很多规范,也并不是那么十分统一。还有就是随着规范的不断更新,又要去兼容以前的规范,导致多种规范并行。

这个字段设置的是脚本的主页,就是官方网站的意思。但很多脚本也并没有主页,于是就放上作者自己的网站博客等。有人说这就是免费的广告位,谁会放弃呢?(我的脚本好像大部分都没有写,亏了亏了

这个信息会显示在脚本市场或者脚本列表中的主页信息上,一般只要点击就会直接跳转到对应的网站。

然后如果在 @namespace 中填写的直接是一个网址,也会被视为这个脚本的主页。

@icon, @iconURL, @defaulticon

三选一,设置脚本的图标,放上图标图片的网址。这时候你可能需要一个好用的图床,这确实挺麻烦,所以好多脚本就并没有设置。

当然如果设置了会显得很好看,也很专业的样子。

@icon64, @icon64URL

表示 64×64 像素尺寸的图标,和上面一样给出一个图片的地址。和上面的区别是这代表更高清晰度的图标。但一般来说我们也不怎么会用上,而且也不是所有脚本管理器都支持。如果设置图标,就设置上面的字段就够了,这个就作为了解一下,又是你可以不用,但我不能不说的内容。

@supportURL

支持页地址,如果用户有问题去什么地方找你进行反馈,那么把这个地址放在这里。脚本市场和脚本列表中对应的位置会进行显示。

@downloadURL

脚本的下载地址,就是你的脚本文件在网络中的访问地址。脚本管理器会通过访问这个网址来更新脚本。

但一般也没有人写,因为如果是通过网络地址安装的脚本,脚本管理器会自动为这个脚本添加它的下载地址,以备日后进行更新。我们上传到脚本市场的内容,即便没有填写这些信息,也会被添加/修改为市场的地址。这可以让用户更方便稳定的获得脚本更新。

@updateURL

脚本的更新地址。首先这个不是所有的脚本管理器都支持,很多脚本管理器直接通过上面的下载地址判断是否需要更新。

脚本管理器通过访问这个地址,获取当前最新版本的版本号,然后得出一个是否有更新的结果。所以只是借此进行判断,而不是通过这个网址进行更新。

大部分情况下无需填写此信息。只不过是既然这些网址都出现了,索性把它们放在一起讲一下。

为了避免疑惑,也方便大家出去装 x,所以我把这个没什么用的东西也解释一下。这个更新地址里放什么呢,也放你的脚本,就和上面的 @downloadURL 是一样的。然后脚本管理器访问 @updateURL 来获取脚本的版本号和更新日期,来判断是否需要更新。如果需要,那么通过 @downloadURL 的地址来下载更新。

好像这样复杂的设计,非常莫名其妙,因为这两个网址可以完全一样,并且会正常的工作,搞成两个,这不是多此一举么?那现在我们来设想一个特殊的情况:我的脚本非常复杂,所以体积很大,下载一次需要好几分钟那种。然后用户又有强迫症,希望保持脚本的及时更新,那每一次检查更新需要花费的时间就很长。然后我很懒惰,三年才更新一次脚本,三年里用户的脚本管理器每天都在检查更新,这是怎样的资源浪费啊!但把检查更新和实际进行更新这两个网址分开,就意味着我可以在 @updateURL 这里放一个只包含脚本元数据的版本,这样检查的速度就非常快了,反正也就是对照一下元数据,看看是否需要更新嘛。如果发现确实有更新的需要,再去下载地址,下载那个体积巨大的完整版本。

这么一解释就会发现这个设计是合理的,但为什么现在又不需要呢?下载地址完全可以让脚本管理器自动去解决,你从哪里安装的这个脚本,它就把这个地址自动的记录下来,然后随时从这个地址去检查更新,这样无论是作者还是用户都会更加方便。至于检查更新的时候,脚本管理器可以只下载前面的一段数据进行比较,反正元数据都写在最前面,我读取到版本号就好了,后面的内容不下载。就是通过脚本管理器的增强和优化,让这些以前有意义的设计变得没有什么必要了。

出于强迫症或者一致性的考虑,主页字段我会选择使用 @homepageURL 这个名称,图标字段用 @iconURL。当然如果新建脚本的时候给出的模板已经写了,那我也懒得去修改,直接填上内容就好。

需要时才会出现的内容

以下内容仅在你需要进行这项设置的时候才书写它。否则就没有必要让它们露面了。

@exclude-match

这个和我们前面讲到的 @match 书写和使用都是一样的,但表达的意思是不要在这些网站上去运行脚本。可以认为 @match 是一个白名单,而 @exclude-match 则是一个黑名单。

如果我们只打算匹配几个确定的网站,那么使用白名单(@match)肯定最方便;而如果要匹配几乎所有的网站,只有极个别的网站要排除掉,这时候就要配合使用。先用白名单(@match)匹配所有网站(*://*/*),再用黑名单(@exclude-match)将特定的网站排除掉。

@match 是必须有的,@exclude-match 则根据情况去进行设置。这两项在(针对单个)脚本的设置中,也会有相应的选项,这是供用户进行设置的,用户的设置可以覆盖脚本自带的设置,并且不会受到脚本更新的影响。

@include / @exclude

@match / @exclude-match 差不多,建议使用 @match/ @exclude-match 而不是 @include/@exclude 因为匹配规则更安全,更严格。

你可以把这认为是旧的方式,可以用,但不推荐,然后一些脚本管理器可能不支持 @exclude-match ,那就只好用 @exclude 了。

@require

引入的库。

写脚本就是为了给自己带来便利,那如果每一个功能都自己写,确实挺不容易的。要是把别人写好的工具库引入进来,然后再做一些简单的调用,那就方便多了。

这个字段后面应该写一个 js 文件的地址,就是你要引入的那个库。然后脚本管理器就会自动的把它插入到页面之中。其实我们通过自己书写脚本来实现这个功能也不算很麻烦,但是能少写几行代码总是很开心的。

因为可能需要引入多个库,所以这个字段可以书写多个。

@resource

这个字段用来将一些在脚本中会使用的资源进行预加载。就是打开页面以后,它就会开始下载这些资源,这样等到我们需要使用的时候,就不需要再去等待那个下载的时间了。

具体的使用需要配合接口,这个我们在后面会讲到,这里只先演示它的书写:

// @resource logo https://img3.appinn.net/static/wp-content/uploads/appinn190.png

后面的内容首先是我们给这个资源取的名称,用来在脚本中调用。然后是这个资源的地址,可以是图片或者某些文件的网址。

当然我们需要引入的资源可能不止一个,所以这个字段也可以书写多个。

@grant

上面说到了接口,就是脚本管理器给我们脚本提供的一些便利,和更高的权限,让我们能够更好的完成工作。就好像可爱的女仆打算为小老鼠做饭,她就要跟管家申请使用厨房,管家允许她使用厨房,并且有权使用厨房中的各种食材,厨房里的厨师们也要听从她的指挥来进行辅助。那么烹饪这件事情就变得简单而畅快起来了。

当然如果你需要这些权限,这些辅助,要先和管家明确的提出申请,这样管家才知道如何安排才能够更好的帮助到你。@grant 这个字段就是用来申请接口的权限,说明我要使用这个接口,然后才可以在脚本中进行使用,它的书写格式是这样的:

// @grant GM_getValue
// @grant GM_setValue

在它后面写上要使用的接口名称就可以了,每一行只能申请一个接口,如果需要多个接口,那就像上面这样书写多行。

@run-at

这个字段是用来设定我们的脚本在什么时候注入到页面之中,有如下几个值可供选择:

  • document-end 这是 Violentmonkey 的默认值,就是当页面加载完成之后,再注入我们的脚本。一般来说这个时机是不错的,页面加载完成以后不会再发生大的变化了,然后我们对它进行修改,就不容易出现混乱,或者被后续的改变而覆盖。但如果某些页面使用了懒加载技术,那么可能虽然已经宣称页面加载结束,其实还在进行着各种加载工作,这时候就要具体问题具体处理了;
  • document-start 这表示让我们的脚本尽可能早的被注入,但这并不能够保证我们的脚本就在其他所有脚本之前运行。
  • document-idle 这是 Tampermonkey 的默认值。这个时机可以简单粗暴的认为是在页面加载完成之前的那一瞬间。虽然在页面加载完成之后去注入是一个不错的时机,但是可能有许多脚本都在等待着这个时机运行,我们不想和其他脚本争抢,所以就走一个 VIP 通道,当页面加载完成,但还没有对外宣布的时候,就是还没有到 document-end 这个时间点的时候,注入我们的脚本。然后再对外宣布页面加载完成,即到达 document-end 这个时间点。
  • document-body 如果存在 <body> 元素,则执行脚本。Tampermonkey 支持此选项,Violentmonkey 中则未提及。
  • context-menu 当在浏览器的右键菜单中点击该脚本的项目,才进行脚本的注入。这个方法最大限度的保证了脚本不被使用就不被加载。Tampermonkey 支持此选项(但未来可能改变,并且文档中没有说如何设置右键菜单),Violentmonkey 中则未提及。

@noframes

这个字段后面不需要写任何的内容。如果没有写这个字段,则脚本默认是在页面和页面里的所有的框架中运行(如果这个框架的网址也符合我们设定的条件的话)。

添加上这个标记,则只在页面中运行,而忽略掉所有的框架。

如果你没有听懂这是在说什么,就在发现某个页面中这个脚本被运行了多次,不符合你预期时加上这个。

一些不是所有脚本管理器都支持的标记

其实上面已经讲到一些,比如 @icon64@updateURL,以及上面运行时机中的一些选项。后面这些则是对于新手几乎是完全没有用的,即便是老手也很少需要用到它们,或者在用到的时候需要十分慎重,因为要认真的考虑兼容性和可能引发的其他问题。

@connect

后面是书写一个域名,用来声明我们会在脚本中使用到这个域名中的资源。这可以用来解决跨域问题。

这个功能我没有使用过,而且我也希望所有作者都能够谨慎使用此功能。虽然在前端上禁止跨域是一件非常烦人的事情,但这个限制在安全层面考虑还是非常有必要的。现在工具可以给我们更高的权限来突破这个限制,但是“能力越大,责任越大”,我们也有必要十分谨慎的对待这个强大的权限。

此字段可书写多个,Violentmonkey 似乎并不支持。

@nocompat

标记不兼容的浏览器,因为每个浏览器在技术上总是有着细微的差别,所以导致有些脚本只能在特定的浏览器上去运行。我们通过这个标记来告诉脚本管理器,当前的脚本不兼容哪些浏览器。

此属性似乎 Tampermonkey 独有。

@inject-into

用来指定脚本的注入模式,有如下三种选项:

  • page:这是默认值,脚本会被直接注入到页面之中,各方面都和页面原生的脚本是一样的;
  • content:在一个与页面隔离的环境下运行,可以访问和修改页面的 DOM,但是无法访问到网页的 JavaScript 对象。 不过可以通过 unsafeWindow 对象来绕过限制进行访问,但这种做法(绕过)是非常不推荐的。
  • auto:先尝试使用 page 模式进行注入,如果出现问题,则改用 content 模式来进行注入。

这个字段似乎是 Violentmonkey 独有。Tampermonkey 默认用 content 模式注入,在必要的情况下用 unsafeWindow 来访问 window 对象。

应用市场提供的标记

这里仅参照 Greasy Fork 的说明,不同市场会有不同的规定。

@license

脚本的许可协议,如果没有填写,则表示仅允许个人使用,且不得二次分发。

@contributionURL

用来收取捐助的链接。

@contributionAmount

建议的捐助金额

@compatible

脚本兼容的浏览器,并可附加更多说明。如:

@compatible firefox 火狐上必须关闭广告过滤器

目前能被网站识别的浏览器名称有:firefox, chrome, opera, safari

@incompatible

不被兼容的浏览器,并可附加更多说明,格式参照上一条。


附录:上面提到的所有元数据的速读版本

  • @name 【通用】【多语言】脚本名称

  • @namespace 【通用】命名空间

  • @version 【通用】版本号

  • @author 【通用】作者

  • @description 【通用】【多语言】脚本描述

  • @match 【通用】【可多条】匹配规则

  • @homepage, @homepageURL, @website, @source 【可选】主页

  • @icon, @iconURL, @defaulticon 【可选】图标

  • @icon64, @icon64URL 【非通用】高清图标

  • @supportURL 【通用】【可选】支持页地址

  • @downloadURL 【通用】【不必填写】脚本下载地址,一般无需书写

  • @updateURL 【非通用】【不必填写】脚本的升级地址,无需书写

  • @exclude-match 【非通用】【可多条】排除规则

  • @include 【通用】【可选】【可多条】匹配规则

  • @exclude 【通用】【可选】【可多条】排除规则

  • @require 【通用】【可选】【可多条】引入的脚本

  • @resource 【通用】【可选】【可多条】预加载资源

  • @grant 【通用】【可选】【可多条】接口权限申请

  • @run-at 【通用】【可选】脚本注入时机

  • @noframes 【通用】【可选】不在框架内注入脚本

  • @connect 【非通用】【可选】【可多行】白名单外部域

  • @nocompat 【非通用】【可选】不兼容的浏览器

  • @inject-into 【非通用】【可选】脚本的注入模式

  • @license 【市场】脚本的许可协议

  • @contributionURL 【市场】脚本的捐助链接

  • @contributionAmount 【市场】建议的捐助金额

  • @compatible 【市场】兼容的浏览器

  • @incompatible 【市场】不兼容的浏览器


以上内容,小老鼠花费了一天多的时间辛苦整理。肯定还有很多疏漏,也有很多不准确的地方。但我也很难将它做的面面俱到,毕竟在不同的浏览器下,不同的脚本管理器下,面临的情况都不相同。而且还有油猴标准不断更新的因素在影响。所以这些内容只是作为给大家的参考,但实际书写的时候还是要以实际运行的效果为标准,根据自己面对的情况灵活的选择。
【返回目录】 | 【下一章 如何调试脚本】