CasperJS dynamic selectlists

2019-02-24 05:01发布

问题:

Need help

I am scraping data from this website which has a form that contains three selectlists interconnected to each other that is if the any option from the from the first select list is selected this function is called onchange="Javascript:submitForm2(); and the second selectlist is populated.

And subsequently if an option from the second selectlist is selected the same js function is called onchange="Javascript:submitForm2();" And finally two submit buttons for this form each call different js function which populate the result. So I checked out the docs and I did not find any info about selectlists.

Three dynamically changing select lists interconnected to each other

<select name="s1" onChange="Javascript:submitForm2();" style="width: 150px" width="150"> <select name="s2" onChange="Javascript:submitForm2();" style="width: 300px" width="300"> <select name="s3" style="width:300px" width="300">

And the form has two submit buttons

Tried with these codes this.click('select#s1 option[value="26"]'); this.debugHTML();

Gives me this error CasperError: Cannot dispatch click event on nonexistent selector: select#s1 option[value="26"]

I also tried document.querySelector('select[name="s1"]').setAttribute('value', "26"); Which gives TypeError: 'null' is not an object (evaluating'document.querySelector('select[name="s1"]').setAttribute')

回答1:

Sharing the solution script. I Iterated upon the select lists n*n*n times along with dates and two buttons.


    require 'rubygems'
    require 'capybara-webkit'
    require 'capybara/dsl'
    require 'nokogiri'

    include Capybara::DSL
    Capybara.current_driver = :webkit

    visit("http://thewebsite.com")

    op0_xpath = "//*[@name='selectlist0']/option[1]"
    op0 = find(:xpath, op0_xpath).text
    select(op0, :from => 'selectlist0')

    page.evaluate_script("$('body').submitForm2()")
    sleep(2)

    op1_xpath = "//*[@name='selectlist1']/option[1]"
    op1 = find(:xpath, op1_xpath).text
    select(op1, :from => 'selectlist1')

    page.evaluate_script("$('body').submitForm2()")
    sleep(2)

    op2_xpath = "//*[@name='selectlist2']/option[1]"
    op2 = find(:xpath, op2_xpath).text
    select(op2, :from => 'selectlist2')

    sleep(2)

    find(:xpath, "//input[@name='curYear']").set "2012"
    find(:xpath, "//input[@name='curMonth']").set "10"
    find(:xpath, "//input[@name='curDay']").set "09"

    click_button('button1')
    page.evaluate_script("$('body').submitForm()")



回答2:

You can do something like this you have a form with three interconnected selects.

var valueFirstSelect  = 125;    
var valueSecondSelect = 6;      
var valueThirdSelect  = 47;     

//create casper object
var casper = require('casper').create({
    loadImages:false,
    verbose: true,
    logLevel: 'debug'
});

//open url
casper.start('http://thewebsite.com');

casper.then(function(){

    //select option on first select
    this.evaluate(function(selectValue){
        document.querySelector('select[name=s1]').value = selectValue; 
        return true;
    },valueFirstSelect);

    //firing onchange event to populate the second select
    this.evaluate(function() {
        var element = document.querySelector('select[name=s1]');
        var evt = document.createEvent('HTMLEvents');
        evt.initEvent('change', false, true);
        element.dispatchEvent(evt);
    });

    //wait until the second select is populated
    this.waitFor(function check() {
        return this.evaluate(function() {
            return document.querySelectorAll('select[name=s2] option').length > 1;
        });
    }, function then() {

            //select option on second select
            this.evaluate(function(selectValue){
                document.querySelector('select[name=s2]').value = selectValue; 
                return true;
            },valueSecondSelect);

            //firing onchange event to populate the third select        
            this.evaluate(function() {
                    var element = document.querySelector('select[name=s2]');
                    var evt = document.createEvent('HTMLEvents');
                    evt.initEvent('change', false, true);
                    element.dispatchEvent(evt);
            });

            //wait until the third select is populated            
            this.waitFor(function check() {
                return this.evaluate(function() {
                    return document.querySelectorAll('select[name=s3] option').length > 1;
                });
            }, function then() {

                    //select option on third select
                    this.evaluate(function(selectValue){
                        document.querySelector('select[name=s3]').value = selectValue; 
                        return true;
                    },valueThirdSelect);

                    //click submit button
                    casper.thenClick('form.items input[type="submit"]', function() {

                        /* Do something after click  */                

                    });
            });         
    }); 
});

casper.run(function() {

    //finish execution script 
    this.exit();
});

If you context page includes jQuery library, this code could be different (smaller and cleaner).

Here there is example using casperjs and jQuery with dynamic selectlists.

CasperJs and Jquery with chained Selects