William Howley
William Howley

Reputation: 493

Is it possible to pass in a function into casper.evaluate()?

Is it possible to pass in a function into casper.evaluate()

var casper = require('casper').create({
    //verbose: true,
    logLevel: 'debug',
    pageSettings: {
        loadImage: false,
        userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4'
    }
});    
...
casper.then(function(){
    var config = {};
    config.test = function(a, b){
       return a + b;
    }

    var extractInfo = this.evaluate(function(config) {
       return value = config.test(1, 2);
    }, config);
});

This is not working, so I am assuming no, but it seems like we should be able to since we can pass other things in like objects and arrays. If I can attach functions to config and pass that in that would be a HUGE benefit to CasperJS.

This way the helper functions could be modularized and separated into different includes etc before I run the scrape making the code super clean!

Upvotes: 1

Views: 510

Answers (1)

Artjom B.
Artjom B.

Reputation: 61952

No, that is not directly possible. The documentation says the following:

Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.

Closures, functions, DOM nodes, etc. will not work!

Single functions

JavaScript is of course very dynamic, so you can serialize a function and pass it as a string into the page context. Then you only need to evaluate it in the page context.

Let's take this for example a named (for simplicity) function add:

function add(a, b){
    return a + b;
}

You can pass it into the page context as a string:

this.evaluate(function(addFun){
    // TODO: parse/evaluate function
}, add.toString());

new Function()

var addInternal = new Function("a", "b", addFun + "; return add(a, b);");

produces

var addInternal = function anonymous(a, b) {
function add(a, b){
    return a + b;
}; return add(a, b);
}

eval()

It's of course easier to simply evaluate the string.

eval(addFun)

which directly produces add.

Closures can also be evaluated with this technique, but you need to provide the references from the outer scopes inside of the page context at the time of eval.

Function libraries

If you want to do bigger utility functions, I would suggest that you look into how CasperJS includes the clientutils.js into each page (code).

It is done by having those function in an additional file which can be injected into the page. This can be done synchronously from a local file with casper.page.injectJs(filename) or asynchronously from a remote file with casper.page.injectJs(filename, callback).

Of course, CasperJS provides settings so that those are injected into every page with either casper.options.clientScripts or casper.options.remoteScripts.

Upvotes: 2

Related Questions