casperjs: evaluating document.querySelector return

2019-04-09 07:53发布

问题:

I'm using the waitForSelector() and captureSelector() methods in CasperJS to wait for and select an element using a CSS selector, then save a screenshot of it.

However, I'm finding that because the css background has been set to transparent, the screenshot turns out pretty ugly, so I'd like to set the background to white. I've made sure that I'm using document.querySelector in an evaluate() call, but that doesn't seem to work.

Here's my script (you can ignore everything before casper.start(..., I just included the beginning part for context for the next code snippet):

var casper = require("casper").create({
  verbose: true,
  clientScripts: ["libs/jquery-1.10.2.js"]
});
var utils = require("utils");

var requiredOptions = [ 'url', 'selector', 'filename' ];
var missingOptions = new Array();

for (var i = 0 ; i < requiredOptions.length ; i++) {
  var opt =  requiredOptions[i];
  if (!casper.cli.has(opt)) {
    missingOptions.push(opt);
  }
}

if (missingOptions.length > 0) {
  casper.die("\nMissing the following CLI options: " + missingOptions.join(", ") + "\n\nExiting.\n");
}

var url = casper.cli.get('url');
var selector = casper.cli.get('selector');
var filename = casper.cli.get('filename');

casper.start(url, function() {
  this.waitForSelector(selector, function then() {
    var element = this.evaluate(function() {
      return document.querySelector(selector);
    });
    console.log(element); // returns null
    element.style.backgroundColor = "white"; // throws TypeError: 'null' is not an object (evaluating 'element.style') 
    this.captureSelector("captures/" + filename, selector);
  }, function onTimeout() {
    this.die("URL timed out.");
  });
});

casper.run();

And this is the output I get when I pass in a url, selector, and filename to write the screenshot to:

yiqing:~/Repos/rectslice()$ casperjs slice.js --filename='screenshot.png' --url='https://github.com/n1k0/casperjs/issues/192' --selector='.discussion-bubble-inner'
null
TypeError: 'null' is not an object (evaluating 'element.style')                 
  /Users/yiqing/Repos/rectslice/slice.js:31 in then
  /Users/yiqing/Repos/rectslice:1329 in runStep
  /Users/yiqing/Repos/rectslice:332 in checkStep

Note: Yes, I am well aware that this screenshot turns out fine (in that the background is white)... I just decided to use any old url, since I'm only trying to illustrate that the document.query() call doesn't work as expected.

Also, not sure if the versions are relevant, but here they are anyway:

yiqing:~/Repos/rectslice()$ casperjs --version
1.0.2
yiqing:~/Repos/rectslice()$ phantomjs --version
1.9.0

回答1:

You are running into issues because you can't pass back DOM elements from evaluate(). You can work directly with the element inside of the evaluate block however.

casper.start(url, function() {
  this.waitForSelector(selector, function then() {
    this.evaluate(function(sel) {
      document.querySelector(sel).style.backgroundColor = "white";
    }, selector);
    this.captureSelector("captures/" + filename, selector);
  }, function onTimeout() {
    this.die("URL timed out.");
  });
});

casper.run();

I've tested this on CasperJS 1.1-beta1, but it should work with versions >= 1.0.0

Edit: Can pass back objects, but not DOM elements.