Marc Frankel
Marc Frankel

Reputation: 93

Accurately detect page with AJAX load time in Python using Selenium

I'm trying to accurately detect page load times on a company website I'm working on. I've decided to try and do this using python and selenium so I can automate it. However, I've seemed to have hit a wall since I'm unable to get a reliable page load time. The culprit appears to be the fact that we don't consider the page "loaded" until a ~3 second ajax call finishes. Yet, Selenium considers the page loaded when the DOM fully loads before that, which is not the load time we're looking for. I've read online I can use the WebDriverWait function to poll for an element that appears after the ajax executes. I should be able to do this as new elements are created after the ajax call, however, I've noticed online that it has a polling frequency of 500ms, which is far too large for me. I'm trying to very accurately determine page load times and 500ms is a large margin of error. I couldn't find anything online for how to change the default polling frequency in python, just similar stuff in Java that I can't decipher. If you know how to decrease the polling frequency by a lot or have a better idea of how to get the accurate page load time with Ajax with a margin of error around ~50ms please let me know. Thank you.

Upvotes: 1

Views: 296

Answers (1)

pythad
pythad

Reputation: 4267

In one of my project I wrote such a function:

def wait_for(condition_function, *args):
    start_time = time.time()
    while time.time() < start_time + 10:
        if condition_function(*args):
            return True
        else:
            time.sleep(0.1)
    raise TimeoutException(
        'Timeout waiting for {}'.format(condition_function.__name__)
    )

to later use it like this:

wait_for(obj_has_gone_stale, login_btn)

where login_btn is a Selenium object and obj_has_gone_stale is a function that tries to find object and catches a StaleElementReferenceException. It looks like this:

def obj_has_gone_stale(obj):
    try:
        # poll the link with an arbitrary call
        obj.find_elements_by_id('doesnt-matter')
        return False
    except StaleElementReferenceException:
        return True

With this approach you can set time.sleep() inside wait_for for any time you want. But don't forget to take into consideration that obj.find_elements_by_id('doesnt-matter') may also take some time to execute . No sure if it is much better that Selenium built-in wait for presence as I wrote wait_for for scenarios where the obj has to disappear and not to appear. But you may write something similar to obj_has_gone_stale but obj_has_rendered. It basically has to try to access obj and see if it has been rendered on the page and return true. Then pass the function to wait_for.

Upvotes: 0

Related Questions