简体   繁体   中英

Click multiple elements at the same time selenium Python

I am trying to click multiple elements at the same time without any delay in between. For example, instead of 1 then 2, it should be 1 and 2.

this is the 1st element that I want to click:

WebDriverWait(driver, 1).until(EC.element_to_be_clickable(
                (By.XPATH,
                 "//div[contains(@class, 'item-button')]//div[contains(@class, 'button-game')]"))).click()

this is the 2nd elements that I want to click: (run the first line then second line)

       WebDriverWait(driver, 1).until(
            EC.frame_to_be_available_and_switch_to_it((By.XPATH, "/html/body/div[4]/div[4]/iframe")))


        WebDriverWait(driver, 1.4).until(EC.element_to_be_clickable(
            (By.XPATH, "//*[@id='rc-imageselect']/div[3]/div[2]/div[1]/div[1]/div[4]"))).click()

Basically, Click 1st element and 2nd elements' first line then second line.

I have tried this, but did not work:

from threading import Thread

def func1():
        WebDriverWait(driver, 1).until(EC.element_to_be_clickable(
                    (By.XPATH,
                     "//div[contains(@class, 'item-button')]//div[contains(@class, 'button-game')]"))).click()

def func2():
               WebDriverWait(driver, 1).until(
                EC.frame_to_be_available_and_switch_to_it((By.XPATH, "/html/body/div[4]/div[4]/iframe")))


            WebDriverWait(driver, 1.4).until(EC.element_to_be_clickable(
                (By.XPATH, "//*[@id='rc-imageselect']/div[3]/div[2]/div[1]/div[1]/div[4]"))).click()



if __name__ == '__main__':
    Thread(target = func1).start()
    Thread(target = func2).start()

Use case: I am trying to automate a website and I need to be fast. Sometimes, element1 is not showing, the website shows element2 instead and vice versa. If I did not check element1 and element2 at the same time, I will be late. The code above starts function1 before function2 and not at the same time. Thank you

You can use ActionChains to perform multiple actions almost immediately.

actions = ActionChains(driver)

actions.move_to_element(element1).click()
actions.move_to_element(element2).click()

actions.perform()

Depending on the use case, you could also use click_and_hold which is also available using ActionChains .

You can make it simultaneous if you use jQuery:

click_script = """jQuery('%s').click();""" % css_selector
driver.execute_script(click_script)

That's going to click all elements that match that selector at the same time, assuming you can find a common selector between all the elements that you want to click. You may also need to escape quotes before feeding that selector into the execute_script. And you may need to load jQuery if it wasn't already loaded. If there's no common selector between the elements that you want to click simultaneously, then you can use javascript to set a common attribute between them.

You can also try it with JS execution, which might be fast enough:

script = (
    """var simulateClick = function (elem) {
           var evt = new MouseEvent('click', {
               bubbles: true,
               cancelable: true,
               view: window
           });
           var canceled = !elem.dispatchEvent(evt);
       };
       var $elements = document.querySelectorAll('%s');
       var index = 0, length = $elements.length;
       for(; index < length; index++){
       simulateClick($elements[index]);}"""
    % css_selector
)
driver.execute_script(script)

As before, you'll need to escape quotes and special characters first. Using import re; re.escape(STRING) import re; re.escape(STRING) can be used for that.

All of this will be made easier if you use the Selenium Python framework: SeleniumBase , which has build-in methods for simultaneous clicking:

self.js_click_all(selector)
self.jquery_click_all(selector)

And each of those above will automatically escape quotes of selectors before running driver.execute_script(SCRIPT) , and will also load jQuery if it wasn't already loaded on the current page. If the elements above didn't already have a common selector, you can use self.set_attribute(selector, attribute, value) in order to create a common one before running one of the simultaneous click methods.

Simultaneous clicking is possible with selenium ActionChains class.

Reference: https://github.com/SeleniumHQ/selenium/blob/64447d4b03f6986337d1ca8d8b6476653570bcc1/py/selenium/webdriver/common/actions/pointer_input.py#L24

And here is code example, in which 2 clicks will be performed on 2 different elements at the same time:

from selenium.webdriver.common.actions.mouse_button import MouseButton
from selenium.webdriver.common.action_chains import ActionChains
b1 = driver.find_element(By.ID, 'SomeButtonId')
b2 = driver.find_element(By.ID, 'btnHintId')
location1 = b1.rect
location2 = b2.rect
actions = ActionChains(driver)
actions.w3c_actions.devices = []
new_input = actions.w3c_actions.add_pointer_input('touch', 'finger1')
new_input.create_pointer_move(x=location1['x'] + 1, y=location1['y'] + 2)
new_input.create_pointer_down(MouseButton.LEFT)
new_input.create_pointer_up(MouseButton.LEFT)
new_input2 = actions.w3c_actions.add_pointer_input('touch', 'finger2')
new_input2.create_pointer_move(x=location2['x'] + 1, y=location2['y'] + 2)
new_input2.create_pointer_down(MouseButton.LEFT)
new_input2.create_pointer_up(MouseButton.LEFT)
actions.perform()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM