Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop CasperJS execution and let the user input some value and then continue to execute?

I'm using PhantomJS and CasperJS to automate some of my tasks. In one of the task, I need to manually provide captcha strings before I can actually work on the task. For this problem, what I can think of is to capture a screenshot of the web page, then manually check the captured image and save the captcha string into a text file. After that I can use the file system module in CasperJS to read that value and continue to do the process. I want to know what's the best way to do this kind of tasks.

like image 245
Just a learner Avatar asked Oct 24 '14 20:10

Just a learner


1 Answers

Because of the stuctured manner/control flow of CasperJS compared to PhantomJS, such a task is not easy.

1. Pull approach (file polling)

Let's say there is a secondary program (type 1) which handles showing the CAPTCHA, receiving the input and writing a text file with the CAPTCHA input. All that CasperJS can handle is to write the CAPTCHA screenshot to disk and wait for the file with the "parsed" text.

var fs = require("fs"),
    captchaFile = "cfile.png",
    parsedFile = "pfile.txt";
casper.waitForCaptcha = function(captchaFile, parsedFile){
    casper.then(function(){
        this.captureSelector(captchaFile, "someSelectorOfTheCaptcha");
    });
    casper.waitFor(function check(){
        return fs.exists(parsedFile);
    }, function then(){
        // do something on time
        // check if correct...
        if (!correct) {
            fs.remove(captchaFile);
            fs.remove(parsedFile);
            this.waitForCaptcha(captchaFile, parsedFile);
            // Problem: the secondary process needs to sense that a new CAPTCHA is presented
        }
    }, function onTimeout(){
        // do something when failed
    }, 60000); // 1min should suffice as a timeout
    return this;
};
casper.start(url).waitForCaptcha(captchaFile, parsedFile).run();

This code assumes that you want to retry when the CAPTCHA was wrong, but not if the minute deliberately passed without the decoded file. This is a pull process by polling if files are already there.

2. Push approach

A push process is also possible where the secondary program (type 2) sends requests to the CasperJS process by utilizing the PhantomJS webserver module. Because there will be two concurrent control flows, the CasperJS part needs to wait a long time, but as soon as a request is received with the decoded words the waiting can be broken with unwait.

var server = require('webserver').create(),
    fs = require("fs"),
    captchaFile = "cfile.png";

function neverendingWait(){
    this.wait(5000, neverendingWait);
}

casper.checkCaptcha = function(captchaFile, phantomPort, secondaryPort){
    // here the CAPTCHA is saved to disk but it can also be set directly if captured through casper.captureBase64
    this.captureSelector(captchaFile, "someSelectorOfTheCaptcha");

    // send request to the secondary program from the page context
    this.evaluate(function(file){
        __utils__.sendAJAX("http://localhost:"+secondaryPort+"/", "POST", {file: file}, true);
    }, captchaFile);

    // start the server to receive solved CAPTCHAs
    server.listen(phantomPort, {
       'keepAlive': true
    }, function (request, response) {
        console.log('Request received at ' + new Date());
        if (request.post) { // is there a response?
            this.then(function(){
                // check if it is correct by reading request.post ...
                if (!correct){
                    response.statusCode = 404;
                    response.headers = {
                        'Cache': 'no-cache',
                        'Content-Type': 'text/plain;charset=utf-8'
                    };
                    response.close();
                    server.close();
                    this.checkCaptcha(captchaFile, phantomPort, secondaryPort);
                } else {
                    response.statusCode = 200;
                    response.headers = {
                        'Cache': 'no-cache',
                        'Content-Type': 'text/plain;charset=utf-8'
                    };
                    response.close();
                    server.close();
                    this.unwait(); // abort the neverendingWait
                }
            });
        } else {
            response.statusCode = 404;
            response.headers = {
              'Cache': 'no-cache',
              'Content-Type': 'text/plain;charset=utf-8'
            };
            response.close();
            server.close();
            this.checkCaptcha(captchaFile, phantomPort, secondaryPort);
        }
    });
    return this;
};

casper.start(url).then(function(){
    this.checkCaptcha(captchaFile, 8080, 8081);
}).then(neverendingWait).then(function(){
    // Do something here when the captcha is successful
}).run();
like image 141
Artjom B. Avatar answered Oct 23 '22 15:10

Artjom B.