Search code examples
javascriptjqueryphantomjscasperjs

Count every elements inside an iFrame with CasperJS


I am searching for a way to count every element inside a div. The problem is, the div is inside an iFrame.

casper.then(function() {
        this.echo(this.evaluate(function() {
             __utils__.getElementByXPath('//*[@id="main-frame"]', __utils__.findAll('#design-scrollbox-0')).length;
        }));
    });

What I trying to do above is:

  • Getting the iFrame with XPath
  • Collecting every element
  • and finally getting the length of the returned array.

I'd love if you could point my in the right direction. Sadly, I cannot use a jQuery version > 1.7, so jQuery.contents is not an option.


Solution

  • You could inject some other jQuery version, but you don't need it, since CasperJS provides a convenient way of changing into the iframe and doing stuff in its context. casper.withFrame is a shortcut for the PhantomJS functions page.switchToChildFrame and page.switchToParentFrame. It creates a new step from the callback where further steps can be nested.

    There are certainly different types to count elements, but probably the easiest is using

    casper.getElementsInfo(selector).length
    

    This is the function for printing the number of links I use for the proofs-of-concept:

    function printLinks(){
        try{
            this.echo("elements: " + this.getElementsInfo("a").length);
        } catch(e) {
            this.echo("CAUGHT: " + e);
        }
    }
    

    Proof-of-concept for iframes:

    casper.start("http://jsfiddle.net/anjw2gnr/1/")
        .then(printLinks)
        .withFrame(0, printLinks)
        //.withFrame(1, printLinks)
        .then(function() {
            console.log('Done', this.getCurrentUrl());
        })
        .run();
    

    prints

    elements: 33
    elements: 2
    

    Proof-of-concept for frames:

    casper.start("https://docs.oracle.com/javase/7/docs/api/index.html")
        .then(printLinks)
        .withFrame(0, printLinks)
        .withFrame(1, printLinks)
        .then(function() {
            console.log('Done', this.getCurrentUrl());
        })
        .run();
    

    prints

    CAUGHT: CasperError: Cannot get information from a: no elements found.
    elements: 210
    elements: 4024
    

    So, if you want to count elements, but don't want to use a try-catch block, this is better:

    casper.exists(selector) ? casper.getElementsInfo(selector).length : 0