UserScripts & Greasemonkey:调用网站的 JavaScript 函数

Posted

技术标签:

【中文标题】UserScripts & Greasemonkey:调用网站的 JavaScript 函数【英文标题】:UserScripts & Greasemonkey: calling a website's JavaScript functions 【发布时间】:2011-06-27 17:55:54 【问题描述】:

我正在为 Firefox 和 Chrome 创建一个 UserScript 扩展程序,并且我正在尝试使用网站 javascript 中的一些代码,例如:

function: myFunction()
    return  Grooveshark.playNextSong();

问题是当我测试这段代码时,Grooveshark 是一个空引用。

我知道还有其他人做过:

see BetterGrooveshark

但我不知道为什么我的简单扩展不能调用 Grooveshark 的 JavaScript 函数。

我是否需要将我的脚本“附加”到文档中才能使其正常工作?: document.document.body.appendChild(script);

Greasemonkey 不是已经注入我的扩展 JavaScript 了吗?有人可以帮我澄清一下吗?

谢谢。

【问题讨论】:

【参考方案1】:

背景

Greasemonkey 不是已经注入我的扩展 JavaScript 了吗?有人可以帮我澄清一下吗?

Greasemonkey 在sandbox 中执行您的脚本,这是一个受限环境,无法直接访问页面中的 JavaScript。早期版本的 Greasemonkey 将脚本直接注入页面,但这会引入严重的安全漏洞。在旧模型中,脚本以浏览器 chrome 的提升权限运行,这允许远程页面使用一些 clever JavaScript 访问 Greasemonkey 的内置函数。这很糟糕:

Greasemonkey 脚本包含它们自己的 GM_xmlhttprequest 对象,与普通的 xmlttprequest 对象不同,该对象可以访问计算机的任何本地文件或向任意站点发出任意请求,而无需考虑通常适用于 xmlhttprequest 的相同来源策略。 (source)

当您今天从 Greasemonkey 脚本访问 window 对象时,您得到的是一个间接引用实际 window 属性的 wrapper object。这个包装对象可以安全地修改,但有important limitations。对实际窗口对象的访问由unsafeWindowwindow.wrappedJSObject 的简写)提供。使用unsafeWindow 会重新打开 Greasemonkey 的所有原始安全问题,并且在 Chrome 中不可用。应尽可能避免。

好消息:至少有两种方法可以安全地使用 Greasemonkey 的新安全模型。

脚本注入

现在 Greasemonkey 脚本可以安全地访问 DOM,将inject a <script> 标记到目标文档的<head> 中是微不足道的。像这样创建一个函数:

function exec(fn) 
    var script = document.createElement('script');
    script.setAttribute("type", "application/javascript");
    script.textContent = '(' + fn + ')();';
    document.body.appendChild(script); // run the script
    document.body.removeChild(script); // clean up

使用简单:

exec(function() 
    return Grooveshark.playNextSong();
);

定位黑客

在某些情况下,脚本注入可能有点过头了,尤其是当您只需要修改页面中变量的值或执行单个函数时。 Location Hack 利用 javascript: URL 访问文档内容中的代码。这很像在 Greasemonkey 脚本中运行书签。

location.assign("javascript:Grooveshark.playNextSong();void(0)");

奖励脚本

这是一个完整的 Greasemonkey 脚本,用于演示上述示例。您可以在此页面上运行它。

// ==UserScript==
// @name           Content Function Test
// @namespace      lwburk
// @include        http://***.com/questions/5006460/userscripts-greasemonkey-calling-a-websites-javascript-functions
// ==/UserScript==

function exec(fn) 
    var script = document.createElement('script');
    script.setAttribute("type", "application/javascript");
    script.textContent = '(' + fn + ')();';
    document.body.appendChild(script); // run the script
    document.body.removeChild(script); // clean up


window.addEventListener("load", function() 
    // script injection
    exec(function() 
        // alerts true if you're registered with Stack Overflow
        alert('registered? ' + isRegistered);
    );
    // location hack
    location.assign("javascript:alert('registered? ' + isRegistered);void(0)");
, false);

【讨论】:

约扎!你的手现在疼吗? unsafeWindow 在 Chrome 中不可用;偶尔在纯 FF 脚本中使用也可以。 我不知道你所说的“偶尔使用”是什么意思?如果您确定脚本只会在您控制的页面或您绝对信任的页面上执行,您应该只使用 unsafeWindow。您公开 unsafeWindow 的任何页面都有可能使用此处描述的技术提升其访问权限:groups.google.com/group/greasemonkey-dev/tree/browse_frm/thread/… 你的新措辞很好。 GM wiki 过于偏执和律师式的(这可能是最好的)。这就像警告你永远不要开车,因为你可能会死于车祸。如果您知道您的目标页面,那么使用 unsafeWindow 的风险可以忽略不计。 @PointedEars Chrome 的最新版本确实支持unsafeWindow【参考方案2】:

出于显而易见的原因,在 GreaseMonkey 脚本(以及 Chrome 的用户脚本)中声明的函数和变量与网页声明的函数和变量是分开的。对于Firefox中的GM脚本,您可以通过unsafeWindow访问全局变量。

确保安全性和兼容性的最佳方法是使用脚本元素将您的函数注入页面。我在我的用户脚本中使用了以下 sn-p:

function addFunction(func, exec) 
  var script = document.createElement("script");
  script.textContent = "-" + func + (exec ? "()" : "");
  document.body.appendChild(script);

这里的"-" 确保函数被解析为表达式,这样exec 可以在添加后立即执行。你这样调用函数:

function myFunction () 
    return Grooveshark.playNextSong();


// Inject the function and execute it:
addFunction(myFunction, true);

【讨论】:

以上是关于UserScripts & Greasemonkey:调用网站的 JavaScript 函数的主要内容,如果未能解决你的问题,请参考以下文章

是否可以保留单行注释? (在 CoffeeScript 中编写greasemonkey/userscripts)

向 DynamicFolderBundle 添加额外的订购包?

Chrome暴力猴插件(Violentmonkey)

滑动验证码-网易云盾初使用

检测特定文本框是不是有焦点[重复]

Unraid使用记录:系统安装与基础设置