PhantomJS click on an image and wait for load

11,041

There is an example function phantom.waitFor(callback) that I explain on the following post, it goes as follows:

phantom.waitFor = function(callback) {
  do {
    // Clear the event queue while waiting.
    // This can be accomplished using page.sendEvent()
    this.page.sendEvent('mousemove');
  } while (!callback());
}

This can help streamline your code and avoid nested calls to window.setTimeout(), which are not very reliable anyway as you are waiting for a pre-set amount of time instead of waiting for the element to become visible. An example would be as follows:

// Step 1: Open and wait to finish loading
page.open('http://localhost/');
phantom.waitFor(function() {return !page.loading;});

// Step 2: Click on first panel and wait for it to show
page.evaluate(function() { $("#activate-panel1").click(); });
phantom.waitFor(function() {
   return page.evaluate(function() {return $("#panel1").is(":visible");})
});

// Step 3: Click on second panel and wait for it to show
page.evaluate(function() { $("#activate-panel2").click(); });
phantom.waitFor(function() {
   return page.evaluate(function() {return $("#panel2").is(":visible");})
});
console.log('READY!');
phantom.exit();

This will load each panel in succession (ie synchronously) while keeping your code simple and avoiding nested callbacks.

Hope it makes sense. You could also use CasperJS as an alternative, its aimed at making this stuff simpler.

Share:
11,041
user3803788
Author by

user3803788

Updated on June 18, 2022

Comments

  • user3803788
    user3803788 almost 2 years

    I'm trying to do page automation with PhantomJS. My goal is to be able to go to a website, click an image, and continue with other code once the page has loaded from the click. To test this I'm trying to write a script that will go to the url of the quick start guide on the PhantomJS website and then click on the PhantomJS logo bringing the page to the PhantomJS homepage. Also to render a picture of the website before and after the click to make sure the click worked. This is my current code:

    var page = require('webpage').create();
    
    page.open('http://phantomjs.org/quick-start.html', function(status) {
    console.log(status);
    page.render('websiteBeforeClick.png');
    console.log(page.frameUrl); //check url before click
    
    var element = page.evaluate(function() {
      return document.querySelector('img[alt="PhantomJS"]');
    });
    
    page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
    
    window.setTimeout(function () {
    console.log(page.frameUrl); //check url after click
    }, 3000);
    
    console.log('element is ' + element); //check that querySelector() is returning an element
    page.render('websiteAfterClick.png');
    phantom.exit();
    });
    

    Problem is my before and after pictures are the same. This is my output when I run it.

     success
     element is [object Object]
    

    Im using their sendEvent method from here "http://phantomjs.org/api/webpage/method/send-event.html" but I'm not sure if its working.

    Also why doesnt the console.log(page.frameUrl) in my window.setTimeout() get executed?

    I was looking at their page automation examples on the PhantomJS website. Particularly this one "https://github.com/ariya/phantomjs/blob/master/examples/imagebin.js". I noticed their examples used

    document.querySelector('input[name=disclaimer_agree]').click()
    

    But when I tried it with my code I got an error.

    document.querySelector('img[alt="PhantomJS"]').click();
    TypeError: 'undefined' is not a function
    

    EDIT#1:

    I changed the end section of my code to this:

    page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
    
    
    window.setTimeout(function () {
      console.log(page.frameUrl);
      page.render('websiteAfterClick.png');
      phantom.exit();
    }, 3000);
    
    console.log('element is ' + element);
    });
    

    Now my after image is correct. But now my question is, If I want to continue on with my code i.e. click on another element on the site, will my new code have to be all nested inside of the timeout function?