Returning links inside iframe using a function in

2019-08-15 03:56发布

I am trying to get the links from inside an iframe and return them as a function result, my simplified code looks something like this:

var casper = require("casper").create({
    verbose: true,
    logLevel: "debug",
        webSecurityEnabled: false
});

var url = casper.cli.get(0);

casper.on('remote.message', function(msg) {
    this.echo(msg);
})

casper.start(url, function () {
    thelinks = getLinksFromIframes( casper );
    console.log("doesn't work:" + thelinks);
});

function getLinksFromIframes( context ) {
        var links = [];

        var iframes = context.evaluate( function() {
                var iframes = [];
                [].forEach.call(document.querySelectorAll("iframe"), function(iframe, i) { iframes.push( i ); });
                return iframes;
        });

        iframes.forEach( function( index ) {
            context.withFrame(index, function() {
                links = links.concat( this.getElementsAttribute( 'a', 'href' ) );
                console.log("works: " + links);
            });
        });

        return links;
}

casper.run(function() {
    console.log('done');
    this.exit();
});

The problem is that the function doesn't return anything, I can only read the links var inside withFrame, i know there are other ways to get the links, but the code is this way because it part of something more complex that will analyze nested iframes, and the amount of iframes inside iframes is unknown. Is there any way I could wait on withFrame or something that will allow me to return the links as the function result?

1条回答
forever°为你锁心
2楼-- · 2019-08-15 04:23

That's expected, because casper.withFrame is an asynchronous step function. Like all other functions that begin with either then or wait, it schedules a step in the CasperJS execution queue.

When those scheduled steps are executed (at the end of the current step, which is the then callback of casper.start in your case), getLinksFromIframes has long finished and returned an empty array.

Is there any way I could wait on withIframe or something that will allow me to return the links as the function result?

No, but you can use a callback:

function getLinksFromIframes( callback ) {
    var links = [];

    var iframes = this.evaluate( function() {
        var iframes = [];
        [].forEach.call(document.querySelectorAll("iframe"), function(iframe, i) { iframes.push( i ); });
        return iframes;
    });

    iframes.forEach( function( index ) {
        this.withFrame(index, function() {
            links = links.concat( this.getElementsAttribute( 'a', 'href' ) );
            console.log("works: " + links);
        });
    }, this);

    this.then(function(){
        callback.call(this, links);
    });
}

casper.start(url, function () {
    getLinksFromIframes.call(this, function(links){
        thelinks = links;
        console.log("Links: " + thelinks);
    });
})
.then(function(){
    console.log("Links later: " + thelinks);
})
.run();
查看更多
登录 后发表回答