本帖最后由 steven026 于 2023-5-17 21:17 编辑
本帖最后由 steven026 于 2023-5-17 15:03 编辑
前言
本编指南内容较少、原理简单,更偏向于实现方案,主要作为理论实战篇打下基础(实战篇以后有空的时候会写)
写这篇指南原因主要是前端限制太大,无法满足所有日常(办公)自动化需求,部分需求(比如读写文件)需要通过后端来实现,但后端在部分方面(比如网页处理)灵活性不如前端,因此可以前后端相结合,各取其长,分工合作提升自动化效率。
本编指南
难易度:低(新手也可看懂)
实用性:中(省去手动运行本地后端时间)
广泛性:低(需要有本地后端程序且需要额外注册注册表)
(仅在windows中测试成功,其余环境未测试)
原理
windows支持通过注册表regedit.exe
注册类似https://
的本地自定义协议,可自定义设置command
内容以实现通过自定义协议调用本地程序的方案。
而这个自定义协议亦可通过浏览器前端调用,限制较少,
因此前端使用自定义协议可以单向全自动唤醒本地后端并传输数据。
(双向需要通过XHR等方式,本文暂不讨论,可以等待日后的实战篇)
根据这一原理,使得油猴亦可调用本地后端,实现前后端相结合。
初级内容
准备工作
本地自定义协议实际上使用非常广泛,非常多的软件都在使用,因此我们可以直接根据原理逆向其他软件的实现方案。
首先要在浏览器中允许页面打开新窗口,否则会被浏览器阻止
以GitHub为例,在安装了GitHub Desktop后,可以通过一键打开x-github-client://
协议,使浏览器将目标GiuHub仓库链接传递给本地的应用程序,减少用户操作,提升用户使用体验。
从控制台可以看到这是通过<a>
标签打开的x-github-client://
协议,
这就说明我们亦可通过window.open(url)
打开这一协议链接。
在控制台尝试一下,
果然成功了,这就说明我们也可以在油猴脚本中使用这一特性。
那么问题就来了,这个协议怎么注册呢?查阅相关资料可以发现,这个自定义协议是通过注册表注册的。
因此打开regedit.exe
注册表,搜索x-github-client
可以找到是这条注册表控制的协议注册
直接右键导出,可以获取如下数据,内容非常简单
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\x-github-client]
"URL Protocol"=""
@="URL:x-github-client"
[HKEY_CLASSES_ROOT\x-github-client\shell]
[HKEY_CLASSES_ROOT\x-github-client\shell\open]
[HKEY_CLASSES_ROOT\x-github-client\shell\open\command]
@="\"C:\\Users\\XXX\\AppData\\Local\\GitHubDesktop\\app-3.2.3\\GitHubDesktop.exe\" \"--protocol-launcher\" \"%1\""
可以看到这个注册表路径就是自定义协议名称x-github-client
,而关键命令是最后一行的command
,这个命令和cmd命令非常相似,
参考这个注册表就能注册自己的协议了。
注册表 test.reg
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\test]
"URL Protocol"=""
@="URL:test"
[HKEY_CLASSES_ROOT\test\shell]
[HKEY_CLASSES_ROOT\test\shell\open]
[HKEY_CLASSES_ROOT\test\shell\open\command]
@="\"C:\\Program Files\\nodejs\\node.exe\" \"D:\\test\\test.js\" \"%1\""
我们依样画葫芦,注册一个test://
协议,利用nodejs调用test.js
将x-github-client
全部替换为test
将最后一行command
替换为我们自己需要调用的后端调用命令
记得将"
和\
转义
\"C:\\Program Files\\nodejs\\node.exe\"
是自定义程序绝对路径
\"D:\\test\\test.js\"
是自定义参数
\"%1\"
是打开的协议链接,这个最后不要改动,如果不需要传递数据的话可以删除
保存后双击.reg
文件进行注册表注册。
至此我们完成了自定义协议注册工作,自定义协议无法通过前端完成,只能通过后端或者手动运行.reg
文件进行注册。
我们在控制台中测试一下立马跳出了确认框,直接点击打开就行。
(注:仅在https://
页面中,打开协议链接会弹出始终允许选项,如果勾选了始终允许后,后续在该站点打开该协议就不会再弹出二次确认了,会直接自动打开该协议
而在http://
页面中没有始终允许的选项,每次打开协议都会弹出确认框阻塞页面,必须每次手动确认。这是浏览器特性,克服方法几乎没有,强行克服可以参考下文进阶内容)
可以看到我们的test.js
被成功打开了,而这个协议链接也成功被之前注册表command
中的%1
传递了过去,我们可以利用这个特性将前端数据自动传递给后端。
油猴脚本调用这个协议和控制台方法一样,只要在合适的时机运行原生函数即可window.open("test://XXXXX")
进阶内容
监听窗口事件
testWindow = window.open('test://a')
if (testWindow) {
console.log("窗口打开成功")
testWindow.onunload = () => console.log("窗口被关闭")
} else {
console.log("窗口打开失败,可能被浏览器阻止")
}
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/open
具体API使用方法不再赘述,如有需要直接查阅MDN文档即可。
由于自定义协议不需要用到特殊API,因此可以不使用脚本管理器的GM_openInTab
API,直接用原生的window.open
即可。
由于没有违反同源策略,因此可以监听新窗口的onunload
事件。
(似乎无法监听用户是点击了确认还是取消,只能通过其他方法实现)
(如果勾选了始终允许
后onunload
事件发生即代表后端成功被调用)
在http页面中始终允许打开协议链接
目前发现只有在https://
或者chrome-extension://
使用window.open
打开自定义协议链接才会有始终允许
的选项框.
除此以外,连插件APIchrome.tabs.create
都不会弹出始终允许
的选项框
(GM_openInTab
也不会弹出因为其实现原理也是用了chrome.tabs.create
)
据查阅文档说是出于安全考虑,禁用了http
页面的始终允许
选项。
但这也使得每次在http
页面打开协议链接都会阻塞页面必须手动确认才行,非常影响自动化效率,实在不能忍!
因此经过漫长时间的研究,发现我们只要在脚本管理器的background页面运行window.open
即可绕过浏览器的http
页面限制。
那么怎么在脚本管理器的background页面运行代码呢?
改源码即可【……
由于油猴闭源,而脚本猫开源,因此我们直接爆改GM_openInTab
API,然后把新代码去GitHub提交给脚本猫不就行了吗🙄。
详细源码可以查阅GitHub
https://github.com/scriptscat/scriptcat/pull/178
使用了window.open
与chrome.tabs
相结合的方式,
实现在http
页面运行油猴脚本猫脚本亦可始终允许自动打开自定义协议链接
补上了最后一块拼图。
该方法仅适用于脚本猫,这是一个实验性/不兼容其他管理器/不兼容Firefox的功能
(火狐我用的实在太少,尝试了一下似乎background页面强制阻止使用window.open
,无法通过这一原理实现,也有可能是我方法不对,如果有实现的大佬欢迎讨论或者提交PR)
使用方法非常简单
调用GM_openInTab
函数,在参数中加上{ useOpen: true }
即可
该方法做了向下兼容性处理,只有在新版(v0.12.0后的版本)脚本猫中使用了{ useOpen: true }
才会生效使用新方法去打开链接,并会忽略其余所有参数(因为该方法不适用默认参数)
如果在油猴或者旧版脚本猫中即使加了该参数亦不会生效,不会造成其余不利的影响,只是会和旧GM_openInTab
一样弹出没有始终允许
的选项框而已
const protocol = GM_openInTab('test://', { useOpen: true })
protocol.onclose = () => console.log("onclose")
完结撒花
具体脚本前后端相结合的自动化实战篇待有空时会写,【最好不要抱太大期望
实在写不动了……原本以为一个小时最多了,结果写了快2个小时,直接过载,灵思枯竭了,感觉还有点东西想写没写出来,一下子竟然想不起是啥了……等想起来再更新吧