Estensione Chrome: ottieni contenuti DOM


116

Sto cercando di accedere al contenuto DOM di activeTab dal mio popup. Ecco il mio manifest:

{
  "manifest_version": 2,

  "name": "Test",
  "description": "Test script",
  "version": "0.1",

  "permissions": [
    "activeTab",
    "https://api.domain.com/"
  ],

  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

  "browser_action": {
    "default_icon": "icon.png",
    "default_title": "Chrome Extension test",
    "default_popup": "index.html"
  }
}

Sono davvero confuso se gli script in background (pagine di eventi con persistenza: false) o content_scripts siano la strada da percorrere. Ho letto tutta la documentazione e altri messaggi SO e non ha ancora senso per me.

Qualcuno può spiegare perché potrei usare uno sull'altro.

Ecco il background.js che ho provato:

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
    // LOG THE CONTENTS HERE
    console.log(request.content);
  }
);

E lo sto solo eseguendo dalla console popup:

chrome.tabs.getSelected(null, function(tab) {
  chrome.tabs.sendMessage(tab.id, { }, function(response) {
    console.log(response);
  });
});

Sto ottenendo:

Port: Could not establish connection. Receiving end does not exist. 

AGGIORNARE:

{
  "manifest_version": 2,

  "name": "test",
  "description": "test",
  "version": "0.1",

  "permissions": [
    "tabs",
    "activeTab",
    "https://api.domain.com/"
  ],

  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],

  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

  "browser_action": {
    "default_icon": "icon.png",
    "default_title": "Test",
    "default_popup": "index.html"
  }
}

content.js

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.text && (request.text == "getDOM")) {
      sendResponse({ dom: document.body.innerHTML });
    }
  }
);

popup.html

chrome.tabs.getSelected(null, function(tab) {
  chrome.tabs.sendMessage(tab.id, { action: "getDOM" }, function(response) {
    console.log(response);
  });
});

Quando lo eseguo, ricevo ancora lo stesso errore:

undefined
Port: Could not establish connection. Receiving end does not exist. lastError:30
undefined

Risposte:


184

I termini "pagina di sfondo", "popup", "script di contenuto" ti creano ancora confusione; Consiglio vivamente uno sguardo più approfondito alla documentazione delle estensioni di Google Chrome .

Per quanto riguarda la tua domanda se gli script di contenuto o le pagine di sfondo sono la strada da percorrere:

Script di contenuto : sicuramente gli
script di contenuto sono l'unico componente di un'estensione che ha accesso al DOM della pagina web.

Pagina di sfondo / Popup : forse (probabilmente max. 1 dei due)
Potrebbe essere necessario che lo script del contenuto trasmetta il contenuto del DOM a una pagina di sfondo o al popup per un'ulteriore elaborazione.


Ripeto che consiglio vivamente uno studio più attento della documentazione disponibile!
Detto questo, ecco un'estensione di esempio che recupera il contenuto DOM sulle pagine StackOverflow e lo invia alla pagina in background, che a sua volta lo stampa nella console:

background.js:

// Regex-pattern to check URLs against. 
// It matches URLs like: http[s]://[...]stackoverflow.com[...]
var urlRegex = /^https?:\/\/(?:[^./?#]+\.)?stackoverflow\.com/;

// A function to use as callback
function doStuffWithDom(domContent) {
    console.log('I received the following DOM content:\n' + domContent);
}

// When the browser-action button is clicked...
chrome.browserAction.onClicked.addListener(function (tab) {
    // ...check the URL of the active tab against our pattern and...
    if (urlRegex.test(tab.url)) {
        // ...if it matches, send a message specifying a callback too
        chrome.tabs.sendMessage(tab.id, {text: 'report_back'}, doStuffWithDom);
    }
});

content.js:

// Listen for messages
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
    // If the received message has the expected format...
    if (msg.text === 'report_back') {
        // Call the specified callback, passing
        // the web-page's DOM content as argument
        sendResponse(document.all[0].outerHTML);
    }
});

manifest.json:

{
  "manifest_version": 2,
  "name": "Test Extension",
  "version": "0.0",
  ...

  "background": {
    "persistent": false,
    "scripts": ["background.js"]
  },
  "content_scripts": [{
    "matches": ["*://*.stackoverflow.com/*"],
    "js": ["content.js"]
  }],
  "browser_action": {
    "default_title": "Test Extension"
  },

  "permissions": ["activeTab"]
}

6
@solvingPuzzles: chrome.runtime.sendMessageinvia messaggi a BackgroundPage e Popups. chrome.tabs.sendMessageinvia messaggi a ContentScripts.
gkalpak

22
Downvoted poiché questa risposta non spiega come ottenere il DOM ACTUAL dalla scheda corrente.
Giovanni Paolo Barbagallo

2
@JohnPaulBarbagallo: la domanda riguardava l'acquisizione del contenuto DOM, non l'accesso / la manipolazione del DOM effettivo. Penso che la mia risposta lo faccia (e altri sembrano pensarla allo stesso modo). Se hai una soluzione migliore, pubblicala come risposta. Se hai un requisito diverso, pubblicalo come nuova domanda. In ogni caso, grazie per il feedback :)
gkalpak

2
@zoltar: viene stampato nella console della pagina di sfondo.
gkalpak

2
Ho copia / paster questa risposta ma non riesco a ottenere alcun console.log dallo script del contenuto. aiuto per favore!
ClementWalter

72

Non è necessario utilizzare il passaggio del messaggio per ottenere o modificare DOM. Ho usato chrome.tabs.executeScriptinvece. Nel mio esempio sto usando solo l'autorizzazione activeTab, quindi lo script viene eseguito solo sulla scheda attiva.

parte di manifest.json

"browser_action": {
    "default_title": "Test",
    "default_popup": "index.html"
},
"permissions": [
    "activeTab",
    "<all_urls>"
]

index.html

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <button id="test">TEST!</button>
    <script src="test.js"></script>
  </body>
</html>

test.js

document.getElementById("test").addEventListener('click', () => {
    console.log("Popup DOM fully loaded and parsed");

    function modifyDOM() {
        //You can play with your DOM here or check URL against your regex
        console.log('Tab script:');
        console.log(document.body);
        return document.body.innerHTML;
    }

    //We have permission to access the activeTab, so we can call chrome.tabs.executeScript:
    chrome.tabs.executeScript({
        code: '(' + modifyDOM + ')();' //argument here is a string but function.toString() returns function's code
    }, (results) => {
        //Here we have just the innerHTML and not DOM structure
        console.log('Popup script:')
        console.log(results[0]);
    });
});

1
Funziona perfettamente! Grazie. Non so perché, ma non sono riuscito a far funzionare la soluzione accettata per me.
goodfellow

La tua dichiarazione che stai utilizzando solo il activeTabpermesso non è accurata. Stai chiaramente ottenendo <all_urls>in aggiunta a activeTab.
Makyen

1
test.js è uno script che hai incluso nel HTML della pagina, quindi non sono sicuro che avete bisogno di alcun permesso.
Scott Baker

11

Per coloro che hanno provato la risposta gkalpak e non ha funzionato,

tieni presente che Chrome aggiungerà lo script del contenuto a una pagina necessaria solo quando l'estensione è abilitata durante l'avvio di Chrome e anche una buona idea riavviare il browser dopo aver apportato queste modifiche


1
Questo mi ha salvato la giornata
Romain Derie
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.