pythonautomationnewlinechrome-devtools-protocol

Cannot inject newline characters into input field using Nodriver


I am using Python to automate interactions with a web application. My goal is to send newline characters into an input field to separate domain names, but all attempts have failed to properly input newlines. Instead, trying different methods has either resulted in no action or has deleted the existing input.

Environment:

Here is a snippet of the function I am using to send text to an input field:

# Find the specific div element and fill it with domain names
editable_div = await tab.select('div[contenteditable="true"][role="textbox"]')
if (editable_div):
    await editable_div.click()  # Focus on the div
    for domain in domains:
        await editable_div.send_keys(domain)
        await editable_div.send_keys("\n")  # Send newline character

I have tried sending "\n", "\r\n", and even just "\r", but none have resulted in a newline:

Symptoms:

How can I correctly send newline characters to an input field in a web application using Python and the Nodriver library?

The input field accepts the newline when manually pressing enter key.

semrush.com/batch


Solution

  • It seems send_keys() in nodriver has problem with this page but send_keys() in undetected_chromedriver (created by the same author) works correctly.

    But it works when I use JavaScript to send KeyboardEvent with keyCode: 13 and with bubbles: true

    js_function = "(item) => { item.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 13, bubbles: true})); }"
    
    await editable_div.apply(js_function)
    

    and maybe the whole point is in bubble because this element on page is not standard textbox but <div> with nested <span> for every domain - and maybe it has to send this event to parent element which catches it and it replaces Enter with new <span> (with next domain) inside <div>


    Full working code

    import asyncio
    import nodriver as uc
    
    async def main():
        domains = ['A.com', 'B.com', 'C.com']
    
        browser = await uc.start()
    
        page = await browser.get('https://www.semrush.com/batch/')
        await page.maximize()
    
        await asyncio.sleep(5)
        
        editable_div = await page.select('div[contenteditable="true"][role="textbox"]')
        
        if (editable_div):
            await editable_div.click()
            
            # js_function = """() => { document.querySelector('div[role="textbox"]').dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter', code: 'Enter', which: 13, keyCode: 13, bubbles: true, cancelable: true})); }"""
        
            js_function = "(item) => { item.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 13, bubbles: true})); }"
            
            for domain in domains:
                await editable_div.send_keys(domain)
                #await editable_div.send_keys('\n')
                #from selenium.webdriver.common.keys import Keys
                #await editable_div.send_keys(Keys.ENTER)
                await editable_div.apply(js_function)
    
    if __name__ == '__main__':
        uc.loop().run_until_complete(main())
    
        input("Press ENTER to close")