Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
456 views
in Technique[技术] by (71.8m points)

phantomjs - CasperJS/ Javascript Selecting Multiple Options

Trying to scrape a website, where this is the generic HTML code

<select id="xxx" multiple name="zzz">
<option value="123">xaxaxa</option>
<option value="124">zazaza</option>
<option value="125">ajajaj</option>
<option value="126">azzzsa</option>
</select>

It is not enclosed by a form so I tried using the fill() function that casperjs provides but that did not work.

For single entries, I would usually casper.click() and that would work but this does not work for multiple entries even with looping

Also the website I am trying to scrape says hold "shift" to select multiple elements but then it can be done by also dragging and selecting.

I need to select multiple values

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This can be easily done by setting the selected property of each option element to true.

CasperJS by values

casper.selectOptionsByValues = function(selectCssSelector, values){
    this.evaluate(function(selector, values){
        [].forEach.call(document.querySelector(selector).options, function(opt){
            if (values.indexOf(opt.value) !== -1) {
                opt.selected = true;
            }
        });
    }, selectCssSelector, values);
};

Values must be strings. You can use it like this:

casper.selectOptionsByValues("#xxx", [ "124", "125" ]);

CasperJS by text

A similar function can be achieved when selecting by text:

casper.selectOptionsByTexts = function(selectCssSelector, texts){
    texts = texts.map(function(t){ return t.trim() });
    this.evaluate(function(selector, texts){
        [].forEach.call(document.querySelector(selector).options, function(opt){
            if (texts.indexOf(opt.text.trim()) !== -1) {
                opt.selected = true;
            }
        });
    }, selectCssSelector, texts);
};

And use it like this:

casper.selectOptionsByTexts ("#xxx", [ "zazaza", "ajajaj" ]);

PhantomJS by values

The same thing can be done for PhantomJS directly:

function selectOptionsByValues(page, selectCssSelector, values){
    page.evaluate(function(selector, values){
        [].forEach.call(document.querySelector(selector).options, function(opt){
            if (values.indexOf(opt.value) !== -1) {
                opt.selected = true;
            }
        });
    }, selectCssSelector, values);
};

and use it like this:

selectOptionsByValues(page, "#xxx", [ "124", "125" ]);

Triggering a change

It may be necessary to trigger a change event in case another element on the page depends on the

this.evaluate(function(selector, values){
    [].forEach.call(...);

    var evt = document.createEvent("UIEvents"); // or "HTMLEvents"
    evt.initUIEvent("change", true, true);
    document.querySelector(selector).dispatchEvent(evt);
}, selectCssSelector, values);

Change event trigger was taken from here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...