有没有办法从 Google Chrome 内容脚本中检索页面的 javascript 变量?
Chrome 扩展:在内容脚本中获取页面变量
IT技术
javascript
google-chrome
google-chrome-extension
2021-01-24 00:04:37
6个回答
我创建了一个小助手方法,玩得开心:)
要检索窗口的变量"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”来代替。
使用 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;
}
Chrome 的文档为您提供了一个很好的起点:https : //developer.chrome.com/extensions/content_scripts#host-page-communication
此方法允许您将全局页面变量提取到内容脚本中。它还使用一个想法来只接受您在握手时识别的传入消息。你也可以只Math.random()
用于握手,但我玩得很开心。
解释
- 此方法创建一个脚本标记
- 它将函数字符串化
propagateVariable
并将当前的 handShake 和目标变量名称传递到字符串中以进行保存,因为函数将无法访问我们的内容脚本范围。 - 然后它将该脚本标记注入页面。
- 然后,我们在我们的内容脚本中创建一个监听器,等待从页面收到回音以传回我们所追求的变量。
- 到目前为止,注入的脚本已经命中页面。
- 注入的代码包含在IIFE 中,因此它会自行运行,将数据推送到侦听器。
- 可选:侦听器确保它有正确的握手,瞧,我们可以信任数据源(它实际上并不安全,但在这种情况下它有助于创建一个标识符,这给了我们一定程度的信任)。
第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
});
正如在其他答案中部分解释的那样,页面中的 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 返回到您的内容脚本中。