将 Greasemonkey/Tampermonkey 用户脚本应用到 iframe

Posted

技术标签:

【中文标题】将 Greasemonkey/Tampermonkey 用户脚本应用到 iframe【英文标题】:Apply a Greasemonkey/Tampermonkey userscript to an iframe 【发布时间】:2016-10-03 15:56:20 【问题描述】:

如何让用户脚本在 inside iframe 中运行?

【问题讨论】:

这是一个已知的错误:Greasemonkey issue 2574 声明“Greasemonkey 4 至今仅检测顶层的导航事件,因此它有效地将 @noframes 应用于每个脚本。” 【参考方案1】:

在 Greasemonkey(以及 Tampermonkey 和大多数用户脚本引擎)中,脚本将在 iframe 上自动触发,如果它符合 @include、@exclude 和/或 @match 指令。 而且,一个流行的问题是how to stop Greasemonkey from firing on iframes。

所以,如果你的脚本有这样的匹配:

@match https://fiddle.jshell.net/*

无论它们是否出现在 iframe 中,它都会在 jsFiddle“输出”页面上触发。


如果您想触发 JUST iframe 内容:

然后您将检查 window.self 属性。 例如,假设您有一个目标页面,例如:

<body>
    <h1>I'm some webpage, either same-domain or not.</h1>
    <iframe src="//domain_B.com/somePath/somePage.htm">
...

然后你可以使用如下脚本:

// ==UserScript==
// @name    _Fires specially on domain_B.com iframes
// @match   *://domain_B.com/somePath/*
// ==/UserScript==

if (window.top === window.self) 
    //--- Script is on domain_B.com when/if it is the MAIN PAGE.

else 
    //--- Script is on domain_B.com when/if it is IN AN IFRAME.
    // DO YOUR STUFF HERE.


重要:

随着Greasemonkey 4, iframes handling is severely crippled 的发布(除此之外,还有许多其他事情被破坏了)。 它仍然可以与 Tampermonkey、Violentmonkey 和几乎所有其他用户脚本引擎一起正常工作。 强烈建议 (including by Greasemonkey itself) 不要使用 Greasemonkey 4 或更高版本。

【讨论】:

请注意,这是 GreaseMonkey 4 中的 broken 谢谢,@Mathnerd314。更新了答案。请注意,现在 GM4 有一个单独的标签,以将其与运行良好的 GM 版本区分开来。 Greasemonkey 似乎不建议您不要使用 4 或更高版本。他们只是通知它破坏了向后兼容性。【参考方案2】:

这是iframe没有位置触发@include@match的情况的解决方案。

这适用于 Greasemonkey 4。

我们必须等待每一帧都加载完毕才能对其进行操作。我通过使用waitForKeyElements.js 来做到这一点,它等待匹配给定CSS 选择器的元素,就像循环遍历document.querySelectorAll("selector") 中的匹配项,然后将给定函数应用于响应:

// ==UserScript==
// @include https://blah.example.com/*
// @require https://git.io/waitForKeyElements.js
// ==/UserScript==

function main(where) 
  // do stuff here with  where  instead of  document
  // e.g. use  where.querySelector()  in place of  document.querySelector()
  // and add stylesheets with  where.head.appendChild(stylesheet)


main(document); // run it on the top level document (as normal)

waitForKeyElements("iframe, frame", function(elem) 
  elem.removeAttribute("wfke_found"); // cheat wfke's been_there, use our own
  for (let f=0; f < frames.length; f++) 
    if (!frames[f].document.body.getAttribute("been_there")) 

      main(frames[f].document);

      frames[f].document.body.setAttribute("been_there", 1);
    
  
);

请注意,所选元素只是一个占位符,表示 iframe 已加载。我们从waitForKeyElements 中删除了“一直在那里”跟踪器,因为稍后可能会再次加载框架(我们不能只使用iframe,因为它的内容已加载到其他地方)。

当我们知道一个框架已经加载时,我们循环遍历每个框架并寻找我们的标记,即框架的body 中的一个 html 属性,称为been_there(如&lt;body been_there="1"&gt;)。如果它丢失了,我们可以在框架的文档上运行我们的main() 函数。完成后,我们添加 been_there 属性,这样我们就不会再次被触发。

【讨论】:

【参考方案3】:

请注意,如果您要为用户脚本制作 chrome 扩展程序,还需要将 "all_frames": true 添加到清单中,否则您的扩展程序将无法在 iframe 上运行。

清单文件示例:

"content_scripts": [
    
      "matches": ["*://*/*"],
      "all_frames": true,
      "js":["dont.js"],
      "run_at":"document_start"
    
  ]

示例用例:https://github.com/NavinF/dont

【讨论】:

【参考方案4】:

https://***.com/a/55837286/12469007 的解决方案对我不起作用,因此我对其进行了一些更改。它适用于 Greasemonkey 4.10。

// ==UserScript==
// @include https://blah.example.com/*
// @require https://git.io/waitForKeyElements.js
// ==/UserScript==

function main(where) 
  // do stuff here with  where  instead of  document
  // e.g. use  where.querySelector()  in place of  document.querySelector()
  // and add stylesheets with  where.head.appendChild(stylesheet)


main(document); // run it on the top level document (as normal)

waitForKeyElements("iframe, frame", function(elem) 
  elem.addEventListener("load", function () 
    elem.removeAttribute("wfke_found");
  );
  main(elem.contentDocument);
);

最大的变化是它现在即使在 iframe 导航时也能正常工作。

【讨论】:

我可以确认这也适用于用于 Goggle Chrome 的 Tampermonkey,并且与原始答案相比看起来更加优雅。非常感谢,这真的很有帮助!【参考方案5】:

iframe.contentWindow.document 允许在 FireMonkey 中获取 iframe 内容,例如:

const iframeDocument = document.getElementById('iframe_id').contentWindow.document;
const iframeAnchors = iframeDocument.evaluate(
  '//a',
  iframeDocument,
  null,
  XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  null);

【讨论】:

以上是关于将 Greasemonkey/Tampermonkey 用户脚本应用到 iframe的主要内容,如果未能解决你的问题,请参考以下文章

如何将Ios文件上传到

Javascript 将正则表达式 \\n 替换为 \n,将 \\t 替换为 \t,将 \\r 替换为 \r 等等

如何将视频文件转换格式

sh 一个将生成CA的脚本,将CA导入到钥匙串中,然后它将创建一个证书并与CA签名,然后将其导入到

python怎么将0写入文件?

如何将CMD窗口背景改成透明?