我在尝试通过Selenium / Python自动化同时尝试填写网站上的两个字段时遇到一种罕见的问题。我的脚本填写了第一个字段,即 ORIGIN CITY 很好。我已经为第二个字段 DELIVERY ADDRESS 引入了 WebDriverWait 。 __
我猜想,甚至在诱使服务员之前,“ 交付地址” 字段都可以 单击 。
但是 ORIGIN CITY 字段具有通过事件关联的 JavaScriptonchange,如下所示:
onchange
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的 完成它清除了从文本 送货地址 字段。
我确实将Java Client的 ExpectedConditions 视为 jsReturnsValue ,而 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")
任何建议都会有所帮助。
我发现,处理这些JS最简单的方法postbacks,就是等待受影响的元素 负载 去 陈旧 或无法找到。
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并将其与一些计时参数一起传递给函数。
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,但就我而言,它非常有效。
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()将来有人使用页面加载!
time.sleep()