油猴(篡改猴)学习记录
第一个Hello World
- 注意点:默认只匹配了
http
网站,如果需要https
网站,需要自己添加@match https://*/*
- 代码如下
- 这样子访问任意网站就可以输出
Hello World
- 这样子访问任意网站就可以输出
// ==UserScript== |
- 后期熟练了,可以用框架开发了,这个不错
重要了解
@grant
@grant
用于将GM_*
和GM.*
函数、unsafeWindow
对象和一些强大的window
函数列入白名单。// @grant GM_setValue
// @grant GM_getValue
// @grant GM.setValue
// @grant GM.getValue
// @grant GM_setClipboard
// @grant unsafeWindow
// @grant window.close
// @grant window.focus
// @grant window.onurlchange由于关闭和聚焦选项卡是一个强大的功能,因此也需要将其添加到
@grant
语句中。如果@grant
后跟none
,则禁用沙盒。在此模式下,没有GM_*
函数,但GM_info
属性将可用。
// @grant none |
- 如果没有给定
@grant
标记,则假定为空列表。但是,这与使用none
不同。 - 说白了就是你不设置
@grant
标记,你就不能使用GM_addElement
等等GM_
的函数
@match
- 主要运行脚本的网站
- 如果需要在全部链接上运行,就只需添加如下
@match *://*/* |
- 需要注意的是
@match
规则是匹配多少次,就运行多少次编写的脚本文件
- 下面的例子就可以很好的说明match几次就执行多少次脚本
// @match http://www.yinghuavideo.com/v/* |
@require
油猴给我们提供了一个@require属性给我们来引用用户脚本,并且油猴给我们提供了md5,sha256等校验方法来校验引用的脚本是否正确,例如下面这样:
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js#md5=xxxx
如果md5不正确,console中则会显示下面的内容
- 也支持
SHA-256
和MD5
哈希 - 如果给出多个哈希(用逗号或分号分隔),则当前支持的最后一个哈希值由 Tampermonkey 使用。所有哈希都需要以十六进制或 Base64 格式编码。
// @require https://code.jquery.com/jquery-2.1.1.min.js#md5=45eef... |
@resource
一些可以通过
GM_getResourceText
和GM_getResourceURL
访问的静态资源。 后面写名值对,名是资源的名称,值是相应的url,中间以空格隔开(所以名字中不能包含空格😄),可多次定义// @resource logo https://my.cdn.com/logo.png
// @resource text https://my.cdn.com/some-text.txt然后就可以使用
getResourceText
引入了
// ==UserScript== |
@GM_addElement
- 可以用来添加
script
,css
,或者为指定的DOM添加对应属性或元素
添加script-1
head
下添加
GM_addElement('script',{ |
添加script-指向url
head
下添加
GM_addElement('script',{ |
添加style和css的link
- 下面这个操作就不解释什么意思了,应该都看得懂
GM_addElement(document.getElementsByTagName('div')[0], 'img', { |
style
应该这么用
GM_addElement("style", { |
@GM_addStyle
- 传入的参数就是css样式,css样式这么写,这里就可以写,用模板语法会很方便,和css书写一样,下面例子就是模板语法添加的样式信息
GM_addStyle( |
@GM_setValue
GM_setValue(key,value)
GM_setValue("someKey", "someData"); |
- 暂时不明白为什么需要
await
@GM_getValue
GM_getValue(key,defaultValue)
- 当
key
不存在的时候,则返回默认值
- 当
const someKey = GM_getValue("someKey", null); |
@GM_deleteValue
GM_deleteValue("someKey")
- 从用户脚本的存储中删除对应的key
GM_deleteValue("someKey"); |
@GM_listValues
GM_listValues
函数返回所有存储数据的key
列表。
const keys = GM_listValues(); |
unsafeWindow
- 作用:允许脚本可以完整访问原始页面,包括原始页面的脚本和变量。
- 简单理解为自己脚本里面的
window
是独立于外面的,无法访问到原始网页的window
对象里面的信息 - 注意
unsafeWindow
和window
是不一样的 - 比如有一个网页,代码如下
<html lang="en"> |
- 然后我们
@grant
引入unsafeWindow
//油猴脚本内容如下 |
- 可以看到,我们在代码直接访问
window
是获取不到的,需要使用unsafeWindow
@GM_registerMenuCommand
GM_registerMenuCommand(name, callback, accessKey);
name: 包含要为菜单项显示的文本的字符串。
callback: 回调:选择菜单项时要调用的函数。该函数将传递单个参数,即当前活动的选项卡。从Tampermonkey 4.14开始,MouseEvent或KeyboardEvent作为函数参数传递。
accessKey: 访问键:菜单项的可选访问键。这可用于为菜单项创建快捷方式。例如,如果访问键为“s”,则用户可以在打开Tampermonkey的弹出菜单时按“s”来选择菜单项。
该函数返回可用于注销命令的菜单项 ID。
- 也就是通过
GM_unregisterMenuCommand(menuCmdId)
- 也就是通过
const menu_command_id = GM_registerMenuCommand("Show Alert", function(event: MouseEvent | KeyboardEvent) { |
- 如果需要通过
alt
或者ctrl
这种组合键的,就需要如下的做法了
(function () { |
@run-at
- 说通俗点就是代码什么时候注入(因为注入时机不同,可以对网页的操作量也不同)
- 官方文档 @地址
- 就如同作者说的,想要替换
setInterval
函数,达到时间加速,就必须在调用之前被替换,所以就应该更改run-at
的值
首先来介绍一下时间加速的原理.一般情况下,都是使用setInterval来做定时器,我们只要把这个定时器的时间缩短,比如之前是1s触发一次,现在变成500ms触发一次,那么就相当于时间缩短了一倍. |
@GM_xmlhttpRequest
- 和自带的ajax请求和fetch更强大,支持跨域这个
GM_xmlHttpRequest
- 重要提示:如果要使用此方法,请同时查看有关
@connect
的文档。
// ==UserScript== |
@connect
- 设置允许通过
GM_xmlhttpRequest
连接访问的域名(包括子域名)。 - 说白了就是如果在调用
@GM_xmlhttpRequest
的时候,好像会有一个确认访问域的对话框
代码编写前置工作
前置工作1-@require引入本地文件
- 方式1:可以在油猴那边编写,然后运行
- 方法2:借助于
@require
引入本地文件,然后借助于第三方编辑器进行编写- 注意,需要开启
允许访问文件网址
才可以引入本地文件
- 注意,需要开启
- 然后将下面的文件路径替换为你自己的就好了
@require file://文件路径
: 将文件路径替换为自己的
// ==UserScript== |
前置工作2-添加jQuery便携DOM操作
- 如果不想用原生的或者原生的会用但是没jQuery方便,可以用jQuery来操作DOM,如下
// ==UserScript== |
- 这样子我们编写脚本直接就可以使用了
- 下面是我文件的
helloworld.js
内容
- 下面是我文件的
(function() { |
代码正式编写
1.练习-1
- 一个网页添加一个可操作的方块,并有几个功能按钮,效果图如下
测试网站
具体代码
(function () { |
2.练习-2-CSDN黑夜模式
2.1个人中心页面黑夜模式添加
- 先观察vip用户和普通用户看看
- 观察这二个人,后面发现一个类不同
- 然后我们尝试把
user-skin-Black
添加上去,发现变化了
- 我们书写下油猴脚本代码
(function() { |
- 但是发现顶部还没有变化
- 观察发现是这一个类的问题
- vip黑色背景为:
csdn-toolbar-dark.css
- 普通用户背景为:
csdn-toolbar-default.css
- vip黑色背景为:
- 我们油猴试试添加下这个css文件看看,代码就变成了下面这样子
@match
后期优化
// ==UserScript== |
- 添加完成后是这样子的
- 发现差一点效果和vip的
- 查看代码,然后优化后代码如下
// ==UserScript== |
2.2文章内容黑夜模式添加
- 老样子,观察下标题的样式,看看有什么区别
- 发现vip用户的黑色背景下的标题多了这个样式,而普通用户没有这个skin-clickm…1.min.css样式文件(不信看网络加载的css文件)
- 那就很简单了,优化下逻辑代码和添加css,结果如下
// ==UserScript== |
3.脚本自动化之模拟点击和表单填写
// ==UserScript== |
4.视频倍速播放
- 借助于video元素身上的
playbackRate
属性即可
5.bilibili一键三连
- 我们长按三连看看
- 参数重要的几个
csrf: 发现是从cookie获取 |
- 至于为什么是3秒,好像需要等页面加载完成后再插入,否则会无限刷新
// ==UserScript== |
6.樱花动漫简易去广告
- 打开樱花动漫,可以看到一堆广告
- 原理很简单,
display:none
就可以隐藏了,视频播放暂停的广告一开始是display:none
,暂停的时候被修改为display:block
,所以我们把宽度,高度更改为0就可以了
// ==UserScript== |
- 效果
7.bilibili小尾巴-hook思想
- 我们发送一个消息看看
- 参数有下面这些
- 发送的方式是
fetch
有关于怎么拦截重写fetch,这个文章说的很好
这里就使用博主的猴子补丁(monkey patching)
const { fetch: originalFetch } = window; |
- 代码如下
decodeURIComponent
目的是小尾巴所有的字符都编码,不管是不是特殊字符
// ==UserScript== |
链接
- 油猴官方文档
- post请求提交的数据
- Content-Type:application/x-www-form-urlencoded
- 点击查看源
- 我们的却是这样子
- 点击查看源
fetch('https://api.bilibili.com/x/web-interface/archive/like/triple',{ |
错误原因,我使用了json方式发送数据,这种对应的Content-type应该为application/json
- 而哔哩哔哩那种是Content-Type为application/x-www-form-urlencoded,也就是类似于key=value&key2=value2…这种形式
- 而Content-Type为form-data,一般是文件上传的,如下图
技巧
使用GM_xmlhttpRequest看不到请求怎么办?
- 找到扩展程序,点击下面的
- 然后会打开一个调试窗口,再次发送请求,就可以看到了
错误记录
because it violates the following Content Security Policy directive
- 油猴运行出现这个
because it violates the following Content Security Policy directive: "script-src *.weiyun.com *.qq.com *.gtimg.cn *.gtimg.com *.idqqimg.com *.idqqimg.cn *.tenpay.com *.qpic.cn *.url.cn *.qpimg.cn *.myqcloud.com cdn-go.cn cdn.addon.tencentsuite.com blob: 'self' 'unsafe-inline' 'unsafe-eval'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback. |
github解决办法
原来formData的append只能添加字符串形式的值,否则会出现这种问题,参数里面带
[]
,比如file_id[]:132424
const formData = new FormData(); |
还有,如果设置了formData发送post数据,一定要省略 xhr.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’); 这行代码,否者数据无法正常切割
- 否者会出现服务器需要下面格式的数据
- 因为手动设置了
Content-Type', 'application/x-www-form-urlencoded
,而导致的发送数据无法切割问题- 所以切记,切记