Chrome 扩展:在内容脚本中获取页面变量

IT技术 javascript google-chrome google-chrome-extension
2021-01-24 00:04:37

有没有办法从 Google Chrome 内容脚本中检索页面的 javascript 变量?

6个回答

如果你真的需要,你可以<script>在页面的 DOM 中插入一个元素;<script>元素中的代码将被执行,并且该代码将可以访问窗口范围内的 JavaScript 变量。然后,您可以使用data-属性和触发自定义事件将它们传达回内容脚本

听起来很别扭?为什么是的,它是,并且出于 serg 引用的文档中的所有原因故意如此。但如果你真的,真的需要这样做,它是可以做到的。请参阅此处此处了解更多信息。还有祝你好运!

谢谢!!如此简单而明显的需求,却隐藏得如此之深。访问页面变量并与扩展进行通信。
2021-03-21 00:04:37
好的,这比我的答案更好。
2021-03-22 00:04:37

我创建了一个小助手方法,玩得开心:)

要检索窗口的变量"lannister", "always", "pays", "his", "debts",请执行以下操作:

var windowVariables = retrieveWindowVariables(["lannister", "always", "pays", "his", "debts"]);
console.log(windowVariables.lannister);
console.log(windowVariables.always);

我的代码:

function retrieveWindowVariables(variables) {
    var ret = {};

    var scriptContent = "";
    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        scriptContent += "if (typeof " + currVariable + " !== 'undefined') $('body').attr('tmp_" + currVariable + "', " + currVariable + ");\n"
    }

    var script = document.createElement('script');
    script.id = 'tmpScript';
    script.appendChild(document.createTextNode(scriptContent));
    (document.body || document.head || document.documentElement).appendChild(script);

    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        ret[currVariable] = $("body").attr("tmp_" + currVariable);
        $("body").removeAttr("tmp_" + currVariable);
    }

    $("#tmpScript").remove();

    return ret;
}

请注意,我使用了 jQuery.. 你可以轻松地使用原生 js “removeAttribute”“removeChild”来代替。

如果您想访问无法序列化的内容,这将不起作用。
2021-03-21 00:04:37
是的,它是 .. 直接从你的插件 js 中使用它
2021-03-26 00:04:37
完美的解决方案,谢谢
2021-03-29 00:04:37
太好了,但这不适用于对象,请查看此版本的更正版本,滚动底部由用户“Taras”发布
2021-03-31 00:04:37
此答案是否适用于内容脚本的上下文?
2021-04-01 00:04:37

使用 Liran 的解决方案,我正在添加一些修复程序Objects,这是正确的解决方案:

function retrieveWindowVariables(variables) {
    var ret = {};

    var scriptContent = "";
    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        scriptContent += "if (typeof " + currVariable + " !== 'undefined') $('body').attr('tmp_" + currVariable + "', JSON.stringify(" + currVariable + "));\n"
    }

    var script = document.createElement('script');
    script.id = 'tmpScript';
    script.appendChild(document.createTextNode(scriptContent));
    (document.body || document.head || document.documentElement).appendChild(script);

    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        ret[currVariable] = $.parseJSON($("body").attr("tmp_" + currVariable));
        $("body").removeAttr("tmp_" + currVariable);
    }

     $("#tmpScript").remove();

    return ret;
}
使用JSON.stringify(" + currVariable + ")like时出现错误TypeError: Converting circular structure to JSON
2021-04-11 00:04:37

Chrome 的文档为您提供了一个很好的起点:https : //developer.chrome.com/extensions/content_scripts#host-page-communication

此方法允许您将全局页面变量提取到内容脚本中。它还使用一个想法来只接受您在握手时识别的传入消息。你也可以只Math.random()用于握手,但我玩得很开心。

解释

  1. 此方法创建一个脚本标记
  2. 它将函数字符串化propagateVariable并将当前的 handShake 和目标变量名称传递到字符串中以进行保存,因为函数将无法访问我们的内容脚本范围。
  3. 然后它将该脚本标记注入页面。
  4. 然后,我们在我们的内容脚本中创建一个监听器,等待从页面收到回音以传回我们所追求的变量。
  5. 到目前为止,注入的脚本已经命中页面。
  6. 注入的代码包含在IIFE 中,因此它会自行运行,将数据推送到侦听器。
  7. 可选:侦听器确保它有正确的握手,瞧,我们可以信任数据源(它实际上并不安全,但在这种情况下它有助于创建一个标识符,这给了我们一定程度的信任)。

第1轮

v1.0

v1.1 Promise!

第 2 轮 - 课堂和Promise

v2.0

如果使用 es module,我建议将类放入自己的文件中并将其导出为默认值。然后它就变成了:

ExtractPageVariable('someGlobalPageVariable').data.then(pageVar => {
  // Do work here 💪
});

class ExtractPageVariable {
  constructor(variableName) {
    this._variableName = variableName;
    this._handShake = this._generateHandshake();
    this._inject();
    this._data = this._listen();
  }

  get data() {
    return this._data;
  }

  // Private

  _generateHandshake() {
    const array = new Uint32Array(5);
    return window.crypto.getRandomValues(array).toString();
  }

  _inject() {
    function propagateVariable(handShake, variableName) {
      const message = { handShake };
      message[variableName] = window[variableName];
      window.postMessage(message, "*");
    }

    const script = `( ${propagateVariable.toString()} )('${this._handShake}', '${this._variableName}');`
    const scriptTag = document.createElement('script');
    const scriptBody = document.createTextNode(script);

    scriptTag.id = 'chromeExtensionDataPropagator';
    scriptTag.appendChild(scriptBody);
    document.body.append(scriptTag);
  }

  _listen() {
    return new Promise(resolve => {
      window.addEventListener("message", ({data}) => {
        // We only accept messages from ourselves
        if (data.handShake != this._handShake) return;
        resolve(data);
      }, false);
    })
  }
}

const windowData = new ExtractPageVariable('somePageVariable').data;
windowData.then(console.log);
windowData.then(data => {
   // Do work here
});

优秀的答案,写得很清楚,很高兴看到过程和最终结果。它非常有效,可以启动。全明星!
2021-03-20 00:04:37
@GiffordN。我正在考虑将它打包成一个可重用的库并将其放在 npm 上。
2021-04-11 00:04:37

正如在其他答案中部分解释的那样,页面中的 JS 变量与您的 Chrome 扩展内容脚本隔离。通常,没有办法访问它们。

但是如果你在页面中注入一个 JavaScript 标签,你将可以访问在那里定义的任何变量。

我使用一个实用函数在页面中注入我的脚本:

/**
 * inject - Inject some javascript in order to expose JS variables to our content JavaScript
 * @param {string} source - the JS source code to execute
 * Example: inject('(' + myFunction.toString() + ')()');
 */
function inject(source) {
  const j = document.createElement('script'),
    f = document.getElementsByTagName('script')[0];
  j.textContent = source;
  f.parentNode.insertBefore(j, f);
  f.parentNode.removeChild(j);
}

然后你可以这样做:

function getJSvar(whichVar) {
   document.body.setAttribute('data-'+whichVar,whichVar);
}
inject('(' + getJSvar.toString() + ')("somePageVariable")');

var pageVar = document.body.getAttribute('data-somePageVariable');

请注意,如果变量是复杂数据类型(对象、数组...),您需要将值作为 JSON 字符串存储在 getJSvar() 中,并将其 JSON.parse 返回到您的内容脚本中。

我喜欢这个解决方案。谢谢你提供。但是,它仅在我替换document.body.setAttribute('data-'+whichVar,whichVar);document.body.setAttribute('data-'+whichVar,window[whichVar]);. 在这样做之前,它只是简单地将属性值设置为等于属性名称的字符串,例如:my_variable="my_variable"而不是my_variable="the_correct_value"
2021-03-18 00:04:37
这是目前最好的选择
2021-04-03 00:04:37