0

Selenium has a lot of actions, e.g., driver.find_element_by_xpath('XXX').click(), driver.find_element_by_xpath('XXX').send_keys(). I would like to add some features (e.g. random pause) to make them real (like humans).

Adding time.sleep() before each action is not Pythonic and takes too many lines (one line before an action). In addition, we want the pause time for different types of actions are different (send_keys(input_text) should be longer than click()).

I tried the following but failed:

from selenium.webdriver.common.action_chains import ActionChains

def pause_wrapper(func, min_time=0, max_time=None):
    """Before execute func, we pause some time [min_time, max_time]."""
    def wrapper(*args, **kwargs):
        pause_time = random.uniform(min_time, max_time)
        print(f'We are going to pause {pause_time} s.')
        time.sleep(pause_time)
        return func(*args, **kwargs)
    return wrapper

ActionChains.send_keys = pause_wrapper(ActionChains.send_keys, min_time=5, max_time=10)
ActionChains.click = pause_wrapper(ActionChains.click, min_time=1, max_time=3)

driver.find_element_by_xpath('XXX').send_keys(Keys.ENTER)

My questions are: 1. Why my method fails (no pause and no print result)? 2. How to approach it?


To clarify: I want to force hard pause, not the other around (as wrongly flagged as similar).

Tengerye
  • 1,796
  • 1
  • 23
  • 46
  • @DebanjanB This question is WRONGLY flagged as similar to another. I want the hard pause, but the similar question is to avoid hard pause. They are opposite. – Tengerye Apr 22 '19 at 01:05

1 Answers1

2

you could define a wait like:

from selenium.webdriver.support.ui import WebDriverWait
wait = WebDriverWait(driver_instance, 1000)

and then use it to perform certain waits like:

from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as EC

wait.until(
    EC.url_contains("http://example.com")
)

do keep in mind that the wait will throw a TimeoutException after a while.

In some cases time.sleep is an acceptable solution.

More about the expected conditions can be consulted in the selenium documentation

andreihondrari
  • 5,743
  • 5
  • 30
  • 59
  • Thanks for your kind reply. But I think it is too troublesome because I have to write codes whenever I need an action. Is there a way to _decorate_ the actions? – Tengerye Apr 16 '19 at 08:06
  • @Tengerye well you could put this in a decorator, I don't see why not. – andreihondrari Apr 16 '19 at 08:06
  • My approach in the question somehow failed and I don't know why. – Tengerye Apr 16 '19 at 08:09
  • @Tengerye failed in what way? The code seems to be alright, you are calling `func` after the `time.sleep`. – andreihondrari Apr 16 '19 at 08:15
  • It should print out `We are going to pause`, but nothing printed out. – Tengerye Apr 16 '19 at 08:21
  • 1
    @Tengerye that's because the `find_element_by_xpath('XXX').send_keys(Keys.ENTER)` doesn't use your decorated `ActionChains.send_keys` method. It uses the one derived from it's DOM element base class. I wouldn't complicate too much and just make a method that waits, and just call that method. – andreihondrari Apr 16 '19 at 08:25