创建一个“另存为”用户脚本
Posted
技术标签:
【中文标题】创建一个“另存为”用户脚本【英文标题】:Create a "Save As" userscript 【发布时间】:2016-06-28 01:04:51 【问题描述】:这个想法在概念上非常简单: 我想创建一个用户脚本,让我按下一个按钮并在页面上保存一些东西(最常见和有问题的图像)。 注意:用户脚本是客户端注入的脚本(通过 Tampermonkey 和 Greasemonkey 等浏览器扩展),用于向网站添加功能。
为此,我只需要调用saveAs()
函数并将数据传递给它。
然后问题就变成了我如何获取数据。
我见过的大多数方法都可能遇到资源与脚本不在同一个域的情况?(不确定这是如何工作的)。
现在,Tampermonkey(和 Greasemonkey)创建了一个专门处理这个问题的函数 - GM_XMLHTTPRequest,它可以规避对适当 CORS 标头的需求。
然而,这会为已下载的文件创建另一个对服务器的请求。
我的问题是:有没有办法不必向服务器发送辅助请求?
这是我努力的编年史:
根据我所做的研究,您可以创建一个canvas
并在其中绘制图像。但是,这会“污染”画布,使其无法运行提取该数据的函数(例如 .toBlob()
或 .toDataURL()
)。
据我了解,CORS 提供了 2 种机制:设置正确的 HTTP 标头,这需要控制服务器,以及可以放在 html 元素上的特殊属性:crossorigin
我尝试在加载后添加此属性,但它不起作用,您仍然会得到一个受污染的画布。
Tampermonkey 提供了几个关于何时运行脚本的不同选项。所以下一个想法是在 DOM 加载但尚未获取资源时运行。似乎最早可能是文档结束(之前getElementById
调用返回null
)。但是,当前在页面上加载图像时会返回错误(在运行任何其他附加代码之前):
Image from origin '...' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '...' is therefore not allowed access.
Chrome 中还有 --disable-web-security
标志,但我宁愿不去那里。
【问题讨论】:
所以你的图片数据和你的网页数据不在同一个域上?与您的网络域相关的图像来源在哪里? 如果您只是想在浏览器中将特定图像另存为 jpg 或 png 之类的下载文件,我已经做到了。无需再次调用服务器,也不知道为什么 CORS 会成为问题。如果是这样,我可以提供一些提示。 @Binvention 我不知道它如何与用户脚本一起使用,但所有错误都与违反同源策略有关。网页在page.com
,图片在images.page.com
@Will 是的,请。如果他们适用于这种情况,欢迎提供任何提示。
是的,这会干扰跨域,因为子域不被视为相同。例如 example.com 与 image.example.com 不是同一个域但是 example.com 与 example.com/images 就跨域安全性而言相同,解决方案是添加您的错误所指的标题离开服务器之前的图像标题
因此,您可以将标题 'Access-Control-Allow-Origin'='yourpagedomainhere' 添加到图像标题中
【参考方案1】:
不,如果没有对服务器的新请求,就无法做到这一点。
当第一个请求发出时,图像被浏览器标记为不安全,然后会阻止一些功能,如画布的toDataURL
、getImageData
或toBlob
,或者在音频文件的情况下, AudioContext 的 createMediaElementSource
和 AnalyserNode
的方法,可能还有其他一些方法。
您无法绕过此安全措施,一旦将其标记为不安全,它就是不安全的。 然后,您必须向服务器发出新请求,以便这次以安全的方式从服务器获取新文件。
通常,您只需在执行请求之前以及在服务器已正确配置为响应此类请求之后,在 media 元素上设置 crossOrigin
属性。
现在,在您的情况下,您似乎无法配置将在其中使用您的脚本的任何服务器。
但正如您所注意到的,GreaseMonkey 或 TamperMonkey 等扩展程序可以访问比从网页运行的基本 javascript 更多的功能。在这些功能中,有一个功能可以让您的浏览器对此类跨域请求不那么小心,这就是 GM_xmlhttpRequest
方法所做的。
但再一次,即使是扩展也没有足够的能力取消标记不安全的媒体。
您必须使用他们不太安全的方式执行新请求。
【讨论】:
并且需要注意的是,即便如此,这也取决于浏览器给予油脂猴的权限以及油脂猴给予你的权限。 感谢您的回答。 :-) 我不太确定你发现了什么。您是说GM_xmlhttpRequest
可以以在绘制到画布时不会触发污染的方式发出跨域请求?如果是的话,你能举一个简单的例子吗?如果成功,您能否快速解释一下他们是如何做到的?
@markE,我还没有测试它,而且这里已经很晚了(凌晨 2 点),所以我明天可能会提供一个示例脚本。但是你要明白的是,GM 是一个浏览器扩展。因此,它可以访问更多功能。在 chrome 中,扩展程序甚至可以截取您的桌面截图。因此,它们也可以规避跨域请求也就不足为奇了。如果文档中关于 GM_xmlhttpRequest 的说法属实,那么是的,您可以将图像绘制回画布而不会污染它,因为您根据 xhr 的响应在用户端构建了图像。不再涉及跨域,画布很开心。
我想我明白了。因此,用户通过安装削弱跨域安全性的扩展程序提前隐式允许跨域请求。
在发出 XHR 请求时使用 canvas
是没有意义的,因为它的全部使用目的是为了规避首先发出这个请求的需要(即严格保持本地操作)。 @markE 在这种特殊情况下,我使用的是 Tampermonkey(这是 Chrome 的等效项),它确实会在您发出跨域请求时触发请求明确批准的提示。每个脚本都有一个“XHR 安全”部分来处理这个安全问题。以上是关于创建一个“另存为”用户脚本的主要内容,如果未能解决你的问题,请参考以下文章
python模拟鼠标键盘操作 GhostMouse tinytask 调用外部脚本或程序 autopy右键另存为