如何通过Selenium和WebDriver等待JavaScript __doPostBack调用

时间:2018-03-29 17:05:33

标签: javascript python selenium asp.net-ajax dopostback

在尝试填写网站上的两个字段时,我在通过Selenium / Python自动化时遇到了一个罕见的问题。我的脚本填写了第一个字段,即 ORIGIN CITY 非常好。我为第二个字段 DELIVERY ADDRESS 引导了 WebDriverWait

我的猜测 DELIVERY ADDRESS 字段几乎可以点击甚至在服务员被诱导之前。

但是 ORIGIN CITY 字段通过onchange事件关联了 JavaScript ,如下所示:

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>

发送地址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 完成后,它会清除 DELIVERY ADDRESS 字段中的文字。

我确实将Java客户端的 ExpectedConditions 看作 jsReturnsValue ,而 Selenium Python客户端则没有。

网站: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")

任何建议都会有所帮助。

2 个答案:

答案 0 :(得分:2)

我发现,处理这些JS postbacks的最简单方法是等待受加载影响的元素去陈旧或者找不到。

这是一个示例函数:

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影响的元素,并将其与一些时序参数一起传递给函数。

如:

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事件的 最佳 方式,但就我而言,它一直非常有效的。

要添加到此答案 :我发现当有多个加载事件时,等待元素过时并不总是有效,我发现使用该方法以及使用下面的代码可以更有效地确保这些动态加载事件完成:(我从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()进行页面加载!

答案 1 :(得分:1)

@PixelEinstein的答案是工作和接受的答案,因为他的想法等待受负载影响的元素过时或未被发现做了伎俩。最后,我通过一种更为简单的方式找到了解决方案,然后才得以实现。我不得不等待 DELIVER ADDRESS 字段转到陈旧,然后调用&#39; send_keys(&#34; XYZ&#34;)&#39;再次在 DELIVER ADDRESS 字段中,如下所示:

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.staleness_of(driver.find_element_by_xpath("//input[@id='txtPickUp']")))
driver.find_element_by_xpath("//input[@id='txtPickUp']").send_keys("XYZ")

讨论How to wait on the __doPostBack method to complete in javascript?有助于理解__doPostBack()

TL;博士

Sys.WebForms.PageRequestManager endRequest Event