如何通过Selenium和WebDriver等待JavaScript __doPostBack调用 [英] How do I wait for a JavaScript __doPostBack call through Selenium and WebDriver

查看:155
本文介绍了如何通过Selenium和WebDriver等待JavaScript __doPostBack调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在通过Selenium/Python自动化同时尝试填写网站上的两个字段时,我面临一种罕见的问题.我的脚本填写了第一个字段,即起源城市很好.我已经为第二个字段交付地址"创建了 WebDriverWait .

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.

我猜想交付地址字段甚至在诱导服务员之前就可以 clickable 了.

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

但是起源城市字段具有通过onchange事件关联的 JavaScript ,如下所示:

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

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

起源城市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>

交付地址HTML:

<li>
  <div class="form-group">
    <div class="" id="div_AddPopup" style="display: none;">
      *Cars will not be delivered at Metro Stations, Malls or Public Place.
    </div>
    <input name="txtPickUp" type="text" id="txtPickUp" class="inputStyle locMark" placeholder="Delivery Address" onfocus="showOnKeyPress(); return true;" onblur="hideOnKeyPress(); return true;">

    <span id="ReqPickUp" style="color:Red;visibility:hidden;">Enter Delivery Address !</span>
  </div>
</li>

JavaScript 完成后,它会清除交付地址字段中的文本.

Once the JavaScript finishes it clears up the text from the DELIVERY ADDRESS field.

我确实以 jsReturnsValue 的形式查看了Java客户端的 ExpectedConditions ,而 Selenium Python客户端则没有.

I did had a look at the Java Client's ExpectedConditions as jsReturnsValue which is not there for the Selenium Python Client.

网站: https://www.avis.co.in/

我的代码:

    from selenium import webdriver
    from selenium.webdriver.support.ui import Select
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC

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

任何建议都会有所帮助.

Any suggestions will be helpful.

推荐答案

我发现,处理这些JS postbacks的最简单方法是等待受 load 影响的元素会变得陈旧" 或找不到.

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.

这是一个示例函数:

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

然后,我将选择一个受此postback load影响的元素,并将其与一些计时参数一起传递给函数.

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.

例如:

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")

我不知道这是否是处理JavaScript onchange load事件的 最佳 方法,但就我而言,它非常有效.

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)

希望这有助于防止将来有人使用time.sleep()进行页面加载!

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

这篇关于如何通过Selenium和WebDriver等待JavaScript __doPostBack调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆