Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
288 views
in Technique[技术] by (71.8m points)

python - How do I wait for a JavaScript __doPostBack call through Selenium and WebDriver

I am facing a rare kind of issue while Automating through Selenium/Python while trying to fill out two fields on a website. My script fills out the first field i.e. ORIGIN CITY pretty fine. I have induced WebDriverWait for the second field DELIVERY ADDRESS.

My guess the DELIVERY ADDRESS field is pretty much clickable even before the waiter is induced.

But the ORIGIN CITY field have a JavaScript associated through onchange event as follows :

onchange="javascript:setTimeout('__doPostBack('DrpCity','')', 0)"

ORIGIN CITY HTML :

<li>
  <div class="form-group">
    <select name="DrpCity" onchange="javascript:setTimeout('__doPostBack('DrpCity','')', 0)" id="DrpCity" class="inputStyle">
<option selected="selected" value="0">Origin City</option>
<option value="3">Bangalore</option>
<option value="6">Chennai</option>
<option value="8">Delhi - NCR</option>
<option value="10">Hyderabad</option>
<option value="7">Kochi</option>
<option value="12">Kolkata</option>
<option value="13">Mumbai</option>
<option value="15">Pune</option>

</select>
    <span id="ReqCity" style="color:Red;visibility:hidden;">Select your city !</span>
  </div>
</li>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I have found, the easiest way to deal with these JS postbacks, is to wait for the element that is affected by the load to go stale or not be found.

Here is an example function:

def waitForElementRemoved(Element, WaitCount, WaitTime):
    ElementRemoved = False
    WaitTry = 0
    while not ElementRemoved:
        try:
            if WaitTry > WaitCount:
                raise Exception("Element not removed from page in alloted time")
            Test = Element.text
            WaitTry += 1
            time.sleep(WaitTime)
        except (NoSuchElementException, StaleElementReferenceException):
            ElementRemoved = True

And then I would pick an element that is affected by this postback load and pass it to the function along with some timing arguments.

such as:

driver = webdriver.Firefox()
driver.get("https://www.avis.co.in")
removedElement = driver.find_element_by_id("DrpCity")
mySelect = Select(driver.find_element_by_id("DrpCity"))
mySelect.select_by_visible_text("Pune")
waitForElementRemoved(removedElement, 10, .5)
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[@id='txtPickUp']"))).send_keys("XYZ")

I don't know if this is the best way to deal with JavaScript onchange load events, but in my case, it has been very effective.


To add on to this answer: I have found that waiting until element goes stale does not always work when there are multiple load events, I have found that using that method along with using the below code works much more effectively to make sure these dynamic load events are complete: (I adapted the below code from HERE)

# Wait for AJAX (Jquery or JS) dynamic page load events
class DynamicLoadState:
    def __call__(self, driver):
        LoadComplete = False
        JQueryLoadComplete = False
        JSLoadComplete = False
        try:
            if driver.execute_script("return jQuery.active") == 0: JQueryLoadComplete = True
        except Exception:
            # JQuery is not present on page
            JQueryLoadComplete = True
        if driver.execute_script("return document.readyState") == 'complete': JSLoadComplete = True
        if JQueryLoadComplete and JSLoadComplete: LoadComplete = True
        return LoadComplete

def WaitForDynamicLoad(driver, WaitTime):
    WebDriverWait(driver, WaitTime).until(DynamicLoadState())

# Use the first method of waiting for the element to go stale
# then run this to make sure all loading is completed

WaitForDynamicLoad(driver, Counts.WaitTime)

Hope this helps keep someone from using time.sleep() in the future for page load!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...