如何从下拉列表中选择一个选项

时间:2017-08-24 14:40:25

标签: puppeteer

我可以点击选择器,但我的问题是如何从下拉列表中选择其中一个选项?

  await page.click('#telCountryInput > option:nth-child(4)')

单击使用CSS选择器的选项不起作用。

例如,从下面的列表中选择国家/地区代码,

enter image description here

8 个答案:

答案 0 :(得分:30)

Puppeteer v0.13.0采用page.select()方法,就是这样做的。你只需要给它选择值。因此,假设您<option value="my-value">中有<select>

await page.select('#telCountryInput', 'my-value')

答案 1 :(得分:9)

对于下拉组件,我认为我们应该考虑两种情况:

  • 原生HTML select元素
  • JS编写的组件,由按钮和选项列表组成,以bootstrap dropdown为例

对于第二种情况,我认为click可以解决问题。

对于第一种情况,我只找到了两种方法:

  1. page.select
  2. elementHandle.type(通知已于27/04/2018更新)
  3. page.select是v0.12.0中添加的新功能。

    例如,您有一个选择元素:

    <label>Choose One:
        <select name="choose1">
            <option value="val1">Value 1</option>
            <option value="val2">Value 2</option>
            <option value="val3">Value 3</option>
        </select>
    </label>
    

    您可以通过两种方式选择第二个选项&#39;值2&#39;。

    // use page.select
    await page.select('select[name="choose1"]', 'val2');
    
    // use elementHandle.type
    const selectElem = await page.$('select[name="choose1"]');
    await selectElem.type('Value 2');
    

    通常elementHandle.type用于在输入文本框中键入文本,但是因为它

      

    聚焦元素,然后为文本中的每个字符发送keydown,keypress / input和keyup事件。

    select HTML元素有输入事件,因此该方法有效。

    我个人认为elementHandle.type更好,因为它不需要知道选项值属性,只需要知道人们可以看到的标签/名称。

    27/04/2018更新

    我以前只在Mac OSX上使用elementHandle.type。最近,我的同事报告了与此相关的错误。他正在使用Linux / Win。另外,我们都使用puppeteer v1.3.0。

    经过反复试验,我们发现此elementHandle.type可以将值分配给<select>元素,但这不会触发元素的change事件。
    因此,我不再建议在elementHandle.type上使用<select>

    最后,我们按照this comment手动调度更改事件。它就像:

    // use manually trigger change event
    await page.evaluate((optionElem, selectElem) => {
        optionElem.selected = true;
        const event = new Event('change', {bubbles: true});
        selectElem.dispatchEvent(event);
    }, optionElem, selectElem);
    

答案 2 :(得分:7)

对于原生选择框,我的解决方案是在页面上执行一些JS:

await page.evaluate(() => {
  document.querySelector('select option:nth-child(2)').selected = true;
})

答案 3 :(得分:3)

我从一条消息着陆,有人在询问如何从下拉菜单中选择第一个选项。这就是我刚想出的方法:

await page.click('.select-input');
await page.waitFor(300);
await page.keyboard.press('ArrowDown');
await page.keyboard.press('Enter');

上面的代码首先选择相关输入。然后我等待,因为我的加载速度不够快。然后,我使用键盘按键向下导航到第一个选项。

答案 4 :(得分:2)

事实证明这比我想象的要容易,因为下拉列表不是本机HTML选项和选项组合,因此,我实际上可以使用下面的代码来选择我想要的目标。

  await page.click('#telCountryInput')
  await page.click('#select2-telCountryInput-results > li:nth-child(4)')

答案 5 :(得分:0)

Page.select并不总是对我有用,而且page.type也不可靠。今天我想出了:

await page.evaluate((css, text) => {
  let sel = document.querySelector(css)
  for(let option of [...document.querySelectorAll(css + ' option')]){
    if(text === option.text){
      sel.value = option.value
    }
  }
}, '#telCountryInput', 'my-value')

答案 6 :(得分:0)

pyppeteer中,当按文本选择时,我可以这样做:

示例页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>example</title>
</head>
<body>
<form id="add" method="post" action="/detail">
    <label for="title"></label>
    <input id="title" name="title">

    <label for="tag">Tag</label>
    <select id="tag">
        <option>java</option>
        <option>python</option>
        <option>kotlin</option>
    </select>
</form>

<button id="submit" onclick="submitHandle()">Submit</button>

<script>
    const submitHandle = () => {
        document.getElementById('add').submit()
    }
</script>
</body>
</html>

示例python代码

import asyncio

from pyppeteer import launch


async def post_spider():
    """Open page and add value in form, then submit."""
    browser = await launch(headless=False)
    try:
        page = await browser.newPage()
        await page.goto('http://127.0.0.1:8000/posts')

        expect_value = 'kotlin'

        # not work.
        # await page.select('#tag', to_select_value)

        select_element = await page.querySelector('#tag')

        # extract all options value
        option_texts = []
        for option_ele in await page.querySelectorAll('#tag > option'):
            text = await page.evaluate('(element) => element.textContent', option_ele)
            option_texts.append(text)

        # check expect value in options
        if expect_value in option_texts:
            # F-format use `{{` to escape a `{`
            # Use JavaScript set select element value that in options.
            await page.evaluate(f'(element) => {{element.value = "{expect_value}"}}', select_element)

        submit_ele = await page.querySelector('#submit')
        await submit_ele.click()
    finally:
        await browser.close()


if __name__ == '__main__':
    asyncio.run(post_spider())

注意:

您可以使用评估 JavaScript 将选项文本之一设置为其选择,如果文本不在选项中,则选择的值不会更改。

这是一个python的例子,它的用法和puppeteer类似,我想在这里记录一下,以帮助更多的人。

我的环境:

  • Python:3.7
  • pyppeteer:0.2.5

答案 7 :(得分:0)

@华刚

你的想法很棒,我扩展了value属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>example</title>
</head>
<body>
<form id="add" method="post" action="/detail">
    <label for="title"></label>
    <input id="title" name="title">

    <label for="tag">Tag</label>
    <select id="tag">
        <option value="1">java</option>
        <option value="2">python</option>
        <option value="3">kotlin</option>
    </select>
</form>

<button id="submit" onclick="submitHandle()">Submit</button>

<script>
    const submitHandle = () => {
        document.getElementById('add').submit()
    }
</script>
</body>
</html>

        expect_value = '3'
        select_tag = '#tag'

        # extract all options value
        option_texts = []
        for option_ele in await page.querySelectorAll(f'{select_tag} > option'):
            text = await page.evaluate('(element) => ({"value":element.value,"text":element.textContent})', option_ele)
            option_texts.append(text)

        value = ''
        for v in option_texts:
            if v.get('text') == expect_value:
                value = v.get('value')
                break
        await page.select(select_tag, value)