Подтвердить что ты не робот

Переменные страницы в контенте script

Есть ли способ получить переменные javascript страницы из содержимого Google Chrome Script?

4b9b3361

Ответ 1

Если вам действительно нужно, вы можете вставить элемент <script> в страницу DOM; код внутри вашего элемента <script> будет выполнен, и этот код будет иметь доступ к переменным JavaScript в области окна. Затем вы можете передать их обратно в контент script с помощью атрибутов data- и активировать пользовательские события.

Звучит неудобно? Почему да, это так и преднамеренно по всем причинам в документации, которую цитировал серг. Но если вам действительно нужно это сделать, это можно сделать. Подробнее см. здесь и здесь. И удачи!

Ответ 2

Я создал небольшой вспомогательный метод, получаю удовольствие:)

для получения переменных окна "lannister", "always", "pays", "his", "debt", вы выполняете следующее:

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".

Ответ 3

Используя решение 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;
}

Ответ 4

Документация Chrome дает вам хорошую отправную точку: https://developer.chrome.com/extensions/content_scripts#host-page-communication

Этот метод позволяет вам извлечь глобальную переменную страницы в ваш контент-скрипт. Он также использует идею, чтобы принимать только входящие сообщения, которые вы узнаете, учитывая ваше рукопожатие. Вы также можете просто использовать Math.random() для рукопожатия, но мне было весело.

объяснение

  1. Этот метод создает тег сценария
  2. Он stringifies функции propagateVariable и передает текущее Рукопожатие и целенаправленное имя переменного в строку для сохранения, так как функция не будет иметь доступ к нашей области содержимого сценария.
  3. Затем он вставляет этот тег сценария на страницу.
  4. Затем мы создаем слушателя в нашем скрипте контента, ожидая ответа от страницы, чтобы передать переменную, которую мы ищем.
  5. К настоящему времени введенный скрипт попал на страницу.
  6. Внедренный код был обернут в IIFE, поэтому он сам отправляет данные слушателю.
  7. Необязательно: слушатель удостоверяется, что у него было правильное рукопожатие, и вуаля, мы можем доверять источнику данных (он на самом деле не защищен, но в этом случае помогает создать идентификатор, что дает нам некоторый уровень доверия).

Раунд 1

v1.0

const globalToExtract = 'someVariableName';
const array = new Uint32Array(5);
const handShake = window.crypto.getRandomValues(array).toString();

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

(function injectPropagator() {
  const script = '( ${propagateVariable.toString()} )('${handShake}', '${globalToExtract}');'
  const scriptTag = document.createElement('script');
  const scriptBody = document.createTextNode(script);
  
  scriptTag.id = 'chromeExtensionDataPropagator';
  scriptTag.appendChild(scriptBody);
  document.body.append(scriptTag);
})();

window.addEventListener("message", function({data}) {
  console.log("INCOMINGGGG!", data);
  // We only accept messages from ourselves
  if (data.handShake != handShake) return;

  console.log("Content script received: ", data);
}, false);

Ответ 5

Я действительно работал над этим, используя localStorge API. Примечание. Чтобы использовать это, наш текст должен иметь возможность читать localStorage. В файле manifest.json просто добавьте строку "storage":

"permissions": [...,"storage"]

Функция hijack находится в содержимом script:

function hijack(callback) {
    "use strict";
    var code = function() {
      //We have access to topframe - no longer a contentscript          
      var ourLocalStorageObject = {
        globalVar: window.globalVar,
        globalVar2: window.globalVar2
      };
      var dataString = JSON.stringify(ourLocalStorageObject);
      localStorage.setItem("ourLocalStorageObject", dataString);
    };
    var script = document.createElement('script');
    script.textContent = '(' + code + ')()';
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);
    callback();
  }

Теперь мы можем вызывать из contentcript

document.addEventListener("DOMContentLoaded", function(event) { 
    hijack(callback);
});

или если вы используете jQuery в своем тексте, например:

$(document).ready(function() { 
    hijack(callback);
});

чтобы извлечь содержимое:

function callback() {
    var localStorageString = localStorage.getItem("ourLocalStorageObject");
    var ourLocalStorageObject= JSON.parse(localStorageString);

    console.log("I can see now on content script", ourLocalStorageObject);
    //(optional cleanup):
    localStorage.removeItem("ourLocalStorageObject");
}

Это можно вызвать несколько раз, поэтому, если ваша страница изменяет элементы или внутренний код, вы можете добавить прослушиватели событий, чтобы обновить расширение с помощью новых данных.

Изменить: я добавил обратные вызовы, чтобы вы могли быть уверены, что ваши данные не будут считаться недействительными (была ли эта проблема)

Ответ 6

Если вы знаете, какие переменные вы хотите получить, вы можете сделать быстрый пользовательский контент script для получения своих значений.

В popup.js:

chrome.tabs.executeScript(null, {code: 'var name = "property"'}, function() {
    chrome.tabs.executeScript(null, {file: "retrieveValue.js"}, function(ret) {
        for (var i = 0; i < ret.length; i++) {
            console.log(ret[i]); //prints out each returned element in the array
        }
    });
});

В retrieveValue.js:

function returnValues() {
    return document.getElementById("element")[name];
    //return any variables you need to retrieve
}
returnValues();

Вы можете изменить код для возврата массивов или других объектов.

Ответ 7

Нет.

Скрипты содержимого выполняются в специальной среде, называемой изолированным миром. Они имеют доступ к DOM страницы, на которую они вставляются, но не на любые переменные или функции JavaScript, созданные на этой странице. Он просматривает каждый контент script, как будто на странице, на которой он запущен, нет другого исполняемого кода JavaScript. То же самое верно в обратном: JavaScript, запущенный на странице, не может вызывать какие-либо функции или обращаться к любым переменным, определенным сценариями контента.

Изолированные миры позволяют каждому контенту script вносить изменения в свою среду JavaScript, не беспокоясь о конфликте со страницей или другими сценариями контента. Например, контент script может включать JQuery v1, и страница может включать JQuery v2, и они не будут конфликтовать друг с другом.

Другим важным преимуществом изолированных миров является то, что они полностью отделяют JavaScript на странице от JavaScript в расширениях. Это позволяет нам предлагать дополнительные функции для скриптов контента, которые не должны быть доступны с веб-страниц, не беспокоясь о доступе к веб-страницам.

Ответ 8

Как объяснено частично в других ответах, переменные 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 вернуть его в свой скрипт содержимого.