Chrome Uzantısı - DOM içeriğini alın


116

Açılır penceremden activeTab DOM içeriğine erişmeye çalışıyorum. İşte manifestom:

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

Arka plan komut dosyalarının (kalıcılığı olan olay sayfaları: yanlış) veya içerik_ komut dosyalarının doğru yol olup olmadığı konusunda gerçekten kafam karıştı. Tüm belgeleri ve diğer SO gönderilerini okudum ve hala bana mantıklı gelmiyor.

Biri neden birini diğerine kullandığımı açıklayabilir mi?

İşte denediğim background.js:

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

Ve bunu sadece açılır konsoldan çalıştırıyorum:

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

Ben alıyorum:

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

GÜNCELLEME:

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

Çalıştırdığımda hala aynı hatayı alıyorum:

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

Yanıtlar:


184

"Arka plan sayfası", "açılır pencere", "içerik komut dosyası" terimleri hala kafanızı karıştırıyor; Google Chrome Uzantıları Belgelerine daha derinlemesine bir göz atmanızı şiddetle tavsiye ederim .

Sorunuzla ilgili olarak, içerik komut dosyaları veya arka plan sayfaları izlenecek yol ise:

İçerik komut dosyaları : Kesinlikle
İçerik komut dosyaları, web sayfasının DOM'sine erişimi olan bir uzantının tek bileşenidir.

Arka plan sayfası / Açılır pencere : Belki (muhtemelen ikisinden en fazla 1'i)
İçerik komut dosyasının, daha fazla işlem için bir arka plan sayfasına veya açılır pencereye DOM içeriğini iletmesini sağlamanız gerekebilir.


Mevcut belgeleri daha dikkatli bir şekilde incelemenizi şiddetle tavsiye ettiğimi tekrar edeyim!
Bununla birlikte, StackOverflow sayfalarındaki DOM içeriğini alan ve bunu arka plan sayfasına gönderen ve ardından konsolda yazdıran örnek bir uzantı:

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.sendMessageMesajları BackgroundPage'e ve Popup'lara gönderir. chrome.tabs.sendMessageContentScripts'e mesaj gönderir.
gkalpak

23
Bu yanıt, geçerli sekmeden GERÇEK DOM'un nasıl elde edileceğini açıklamadığı için olumsuz oy verildi.
John Paul Barbagallo

2
@JohnPaulBarbagallo: Soru, DOM içeriğini almakla ilgiliydi, gerçek DOM'a erişmek / değiştirmekle ilgili değildi. Sanırım cevabım bunu yapıyor (ve diğerleri de aynı şekilde düşünüyor gibi görünüyor). Daha iyi bir çözümünüz varsa, yanıt olarak gönderin. Farklı bir gereksiniminiz varsa, bunu yeni bir soru olarak gönderin. Her durumda, geri bildirim için
teşekkürler

2
@zoltar: Arka plan sayfasının konsolunda basılmıştır.
gkalpak

2
Bu cevabı kopyaladım / pasterim var ancak içerik komut dosyasından herhangi bir console.log alamıyorum. yardım lütfen!
ClementWalter

72

DOM'u almak veya değiştirmek için iletiyi kullanmanıza gerek yoktur. Onun chrome.tabs.executeScriptyerine kullandım . Örneğimde yalnızca activeTab iznini kullanıyorum, bu nedenle komut dosyası yalnızca etkin sekmede yürütülüyor.

manifest.json parçası

"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
Mükemmel çalışıyor! Teşekkür ederim. Nedenini bilmiyorum ama kabul edilen çözümün benim için çalışmasını sağlayamadım.
goodfellow

Yalnızca activeTabizin kullandığınıza dair ifadeniz yanlış. <all_urls>Ek olarak açıkça elde ediyorsunuz activeTab.
Makyen

1
test.js, sayfanızın HTML'sine eklediğiniz bir komut dosyasıdır, bu nedenle herhangi bir izne ihtiyacınız olduğundan emin değilim .
Scott Baker

11

Gkalpak cevabını deneyenler için işe yaramadı,

Chrome'un, içerik komut dosyasını yalnızca Chrome başlatma sırasında uzantınız etkinleştirildiğinde gerekli bir sayfaya ekleyeceğini ve bu değişiklikleri yaptıktan sonra tarayıcıyı yeniden başlatmanız iyi bir fikirdir.


1
Bu benim günümü kurtardı
Romain Derie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.