Ekstensi Chrome - Dapatkan konten DOM

116

Saya mencoba mengakses konten DOM activeTab dari popup saya. Ini manifestasi saya:

{
  "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"
  }
}

Saya benar-benar bingung apakah skrip latar belakang (halaman acara dengan ketekunan: false) atau content_scripts adalah cara yang harus dilakukan. Saya telah membaca semua dokumentasi dan posting SO lainnya dan masih tidak masuk akal bagi saya.

Adakah yang bisa menjelaskan mengapa saya mungkin menggunakan salah satu dari yang lain.

Berikut ini background.js yang saya coba:

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

Dan saya hanya menjalankan ini dari konsol popup:

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

Saya mendapatkan:

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

MEMPERBARUI:

{
  "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);
  });
});

Ketika saya menjalankannya, saya masih mendapatkan kesalahan yang sama:

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

Jawaban:

184

Istilah "halaman latar belakang", "munculan", "skrip konten" masih membingungkan Anda; Saya sangat menyarankan untuk melihat lebih dalam pada Dokumentasi Ekstensi Google Chrome .

Mengenai pertanyaan Anda apakah skrip konten atau halaman latar belakang adalah cara yang tepat:

Skrip konten : Pasti
Skrip konten adalah satu-satunya komponen ekstensi yang memiliki akses ke DOM laman web.

Halaman latar belakang / Popup : Mungkin (mungkin maks. 1 dari keduanya)
Anda mungkin perlu membuat script konten meneruskan konten DOM ke halaman latar belakang atau popup untuk diproses lebih lanjut.


Izinkan saya mengulangi bahwa saya sangat menyarankan studi yang lebih cermat tentang dokumentasi yang tersedia!
Karena itu, berikut adalah contoh ekstensi yang mengambil konten DOM pada halaman StackOverflow dan mengirimkannya ke halaman latar belakang, yang kemudian mencetaknya di konsol:

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"]
}
gkalpak.dll
sumber
6
@solvingPuzzles: chrome.runtime.sendMessagemengirim pesan ke BackgroundPage dan ke Popup. chrome.tabs.sendMessagemengirim pesan ke ContentScripts.
gkalpak
22
Diturunkan karena jawaban ini tidak menjelaskan cara mendapatkan DOM SEBENARNYA dari tab saat ini.
John Paul Barbagallo
2
@JohnPaulBarbagallo: Pertanyaannya adalah tentang mendapatkan konten DOM, bukan tentang mengakses / memanipulasi DOM yang sebenarnya. Saya pikir jawaban saya melakukan itu (dan orang lain tampaknya berpikir dengan cara yang sama). Jika Anda memiliki solusi yang lebih baik, posting sebagai jawaban. Jika Anda memiliki persyaratan yang berbeda, posting sebagai pertanyaan baru. Dalam hal apapun,
terima kasih
2
@zoltar: Ini dicetak di konsol halaman latar belakang.
gkalpak
2
Saya telah menyalin / paster jawaban ini tetapi tidak bisa mendapatkan console.log apa pun dari skrip konten. tolonglah!
ClementWalter
72

Anda tidak harus menggunakan message passing untuk mendapatkan atau mengubah DOM. Saya menggunakan chrome.tabs.executeScriptsebagai gantinya. Dalam contoh saya, saya hanya menggunakan izin activeTab, oleh karena itu skrip dijalankan hanya pada tab aktif.

bagian dari 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]);
    });
});
Oskar
sumber
1
Bekerja dengan sempurna! Terima kasih. Saya tidak tahu mengapa tetapi saya tidak dapat membuat solusi yang diterima berhasil untuk saya.
Goodfellow
Pernyataan Anda bahwa Anda hanya menggunakan activeTabizin tidak akurat. Anda jelas mendapatkan <all_urls>tambahan activeTab.
Makyen
1
test.js adalah skrip yang Anda sertakan di HTML halaman Anda, jadi saya tidak yakin Anda memerlukan izin apa pun .
Scott Baker
11

Bagi yang mencoba menjawab gkalpak dan tidak berhasil,

Ketahuilah bahwa chrome akan menambahkan skrip konten ke halaman yang diperlukan hanya jika ekstensi Anda diaktifkan selama peluncuran chrome dan juga sebaiknya mulai ulang browser setelah melakukan perubahan ini

bxN5
sumber
1
Ini menyelamatkan hari saya
Romain Derie