Reading documents CSS in Chrome Extension

2019-01-19 06:58发布

I am trying to read the pages CSS using a chrome extension. This is what i have in my content script :

   var allSheets = document.styleSheets;
     for (var i = 0; i < allSheets.length; ++i) {
      var sheet = allSheets[i];
          var src = sheet.href;
      var rules = sheet.cssRules || sheet.rules;
     }

For some reason the rules are always empty. I do get all the CSS files used in the 'src' variable. But the rules always come as null.. Its working when I try it as a separate javascript on a HTML page. But fails when I put it up in the content script of my chrome extension. Can somebody lemme know why?

4条回答
再贱就再见
2楼-- · 2019-01-19 07:39

Just a guess, but since chrome extensions are Javascript based, they may have cross domain issues. Chrome sets the rules and cssRules to null when programmatically trying to get a stylesheet from another domain.

查看更多
闹够了就滚
3楼-- · 2019-01-19 07:55

Answer is late, but I think I can help. One method of accessing the cssRules of external sheets protected by CORs is to use Yahoo's YQL service. I've incorporated it into a developer tools extension for Chrome for capturing styles and markup for a page fragment. The extension is in the Chrome Web Store and is on Github.

Grab the source from Github and look at the content.js script to see how YQL is used. Basically, you'll make an AJAX call to YQL and it will fetch the CSS for you. You'll need to take the CSS content and either inject it into the page as an embedded style tag or parse the CSS using JavaScript (there are some libraries for that purpose). If you choose to inject them back into the document, make sure to set the new style blocks to disabled so that you don't screw up the rendering of the page.

The extension itself might be useful to you:

Extension Screenshot

查看更多
我只想做你的唯一
4楼-- · 2019-01-19 07:58

For getting all external css and all internal css file, you can use devtools API. If you want to use it in chrome extension you need to hook devtool into you chrome extension. This code will work

chrome.devtools.panels.create(
    'my chrome extension',
    'icon.png',
    'index.html',
     function(panel) {
        var initial_resources = {};

        // collect our current resources
        chrome.devtools.inspectedWindow.getResources(function(resources) {
            for (var i = 0, c = resources.length; i < c; i++) {
                if (resources[i].type == 'stylesheet') {
                    // use a self invoking function here to make sure the correct
                    // instance of `resource` is used in the callback
                    (function(resource) {
                        resource.getContent(function(content, encoding) {
                            initial_resources[resource.url] = content;
                        });
                    })(resources[i]);
                }
            }
        });
    }
);
查看更多
地球回转人心会变
5楼-- · 2019-01-19 07:59

Well thats the Why, but for fun and interest (never done anything with style sheets before) I thought Id do a How....
manifest.json

{
    "name": "Get all css rules in stylesheets",
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js" : ["myscript.js"],
            "run_at":"document_end"
        }
    ],
    "permissions": [
        "tabs", "<all_urls>"
    ],
    "version":"1.0"
}

myscript.js

// Create the div we use for communication
 var comDiv = document.createElement('div');
 comDiv.setAttribute("id", "myCustomEventDiv");
 document.body.appendChild(comDiv);

// Utitlity function to insert some js into the page, execute it and then remove it
function exec(fn) {
    var script = document.createElement('script');
    script.setAttribute("type", "application/javascript");
    script.textContent = '(' + fn + ')();';
    document.body.appendChild(script); // run the script
    document.body.removeChild(script); // clean up
}


// function that gets inserted into the page
// iterates through all style sheets and collects their rules
// then sticks them in the comDiv and dispatchs the event that the content script listens for
getCSS=function (){
   var rules = '';

   // Create the event that the content script listens for
   var customEvent = document.createEvent('Event');
   customEvent.initEvent('myCustomEvent', true, true);

   var hiddenDiv = document.getElementById('myCustomEventDiv');
   var rules ='';
   var allSheets = document.styleSheets;
   for (var i = 0; i < allSheets.length; ++i) {
      var sheet = allSheets[i];
      for (var z = 0; z <= sheet.cssRules.length-1; z++) {
         rules = rules +'\n'+ sheet.cssRules[z].cssText;
      }
   }
   hiddenDiv.innerText = rules;
   hiddenDiv.dispatchEvent(customEvent);
}

// puts the rules back in the page in a style sheet that the content script can iterate through
// youd probably do most of this in the injected script normally and pass your results back through the comDiv....Im just having fun
document.getElementById('myCustomEventDiv').addEventListener('myCustomEvent', function() {
   var eventData = document.getElementById('myCustomEventDiv').innerText;
   document.getElementById('myCustomEventDiv').innerText='';

   var style = document.createElement('style');
   style.type = 'text/css';
   style.innerText=eventData;
   style = document.head.appendChild(style);
      var sheet = document.styleSheets[document.styleSheets.length-1];
      for (var z = 0; z <= sheet.cssRules.length-1; z++) {
         console.log(sheet.cssRules[z].selectorText +' {\n');
         for (var y = 0; y <= sheet.cssRules[z].style.length-1; y++) {
            console.log('  '+sheet.cssRules[z].style[y] + ' : ' + sheet.cssRules[z].style.getPropertyValue(sheet.cssRules[z].style[y])+';\n');
         };
         console.log('}\n');
      };

   // Clean up
   document.head.removeChild(style);
   document.body.removeChild(document.getElementById('myCustomEventDiv'));
});

exec(getCSS);

In the case of this question Id prolly do most of the checks in the injected script and then pass the results back through the div and its event. But I wanted to see if I could use the dom methods in the content script to go through the css and this was the only way I could figure to do it. I dont like the idea of inserting the rules back into the page, but couldnt figure any other way of doing it.

查看更多
登录 后发表回答