在機票預定的頁面,輸入出發城市和到達城市輸入框的時候, 發現直接使用sendkeys不好使,
大部分情況出現輸入某城市后沒有輸入進去, 經過幾天的研究,發現可以采取三種方式:
1. 先點擊輸入框,待彈出 城市選擇框之后,點擊相應的城市
2. 緩慢輸入城市的縮略字母或者城市的名字的部分,會顯示出待選城市的下拉列表,進而從下拉列表中選擇相應的城市.
3. 直接執行 js腳本對input的value設置為想要的值
首先說一下第三種方式:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].value=\"北京\"", from_inpox);
執行效果最好,
22:35:34.885 INFO - Executing: [execute script: arguments[0].value="北京", [[[Ch
romeDriver: chrome on XP (6452a4a961be7bffa2af9d1b63f3d111)] -> xpath: //div[@id
='js_flighttype_tab_domestic']//input[@name='fromCity']]]])
如上圖所演示,兩種方式均是用戶真實行為。
采取第一種方式:
- 首先定位到輸入框
- 點擊輸入框
- 從彈出的熱門城市框中點擊所需要的城市
WebElement from_inpox = driver .findElement(By.xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='fromCity']")); Actions actions = new Actions(driver); actions.moveToElement(from_inpox).click().perform(); driver.findElement(By .xpath("//div[@data-panel='domesticfrom-flight-hotcity-from']//a[@class='js-hotcitylist' and text()='西安']")) .click();
這里我並沒有直接使用click, 而是使用Actions,原因是我在對到達城市操作時,發現經常報element can't be clicked這樣的錯誤,
大意是,當要點擊到達城市輸入框,其實是被上層的元素遮擋,沒法使用click方法,但是可以使用Actions的moveToElement方法之后可以click
或者采取滾動到該元素,調用JS
JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("arguments[0].scrollIntoView()",element);
之后就可進行click操作.
如果使用第二種方法,就會遇到一個很大的問題:
如何定位到JS生成的下拉列表的城市?Firebug定位之前列表就消失!
看上去很難哈,反復嘗試無所成, 最后突然想起既然是JS生成的,何不使用瀏覽器的JS debug功能,設置斷點一步一步
果不其然,葯到病除。nice job~
思路有了,跟我一起做,點開firebug ,切換到“腳本”界面,首先在輸入框輸入單字母s,待彈出下拉列表后,單擊左側的插入斷點操作
你會發現該下拉框被凍結,不錯呦,之后切換到html界面進行定位。
不光是去哪網,像百度輸入框也可以采取這樣的辦法,JS設置斷點,js的彈出框,彈出菜單就會凍結.
接下來我的輸入就是選擇下拉菜單中所需城市:
from_inpox.clear(); from_inpox.sendKeys("BJ"); Thread.sleep(8000); By bj=new By.ByXPath("//div[@class='qcbox-fixed js-suggestcontainer']//td[contains(text(),'北京')]"); if(isElementPresent(driver,bj,20)) { driver.findElement(bj).click(); }
所要注意的是,下拉菜單中未必彈出那么快,需要做一次等待,在選擇下拉菜單的時候需要做一次判斷,當然這個判斷方法是使用WebDriverWait
/** * @author Young * @param driver * @param by * @param timeOut * @return */ public static boolean isElementPresent(WebDriver driver, final By by, int timeOut) { WebDriverWait wait = new WebDriverWait(driver, timeOut); boolean isPresent = false; isPresent = wait.until(new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver d) { return d.findElement(by); } }).isDisplayed(); return isPresent; }
依然不夠完美,為什么這么說,如果元素沒有出現,並不是返回的false而是直接拋異常,並不是期望的,所以修改為findElements
如果找不到,返回List長度必然為0,進而返回false而不是拋出異常
/** * @author Young * @param driver * @param by * @param timeOut * @return * @throws InterruptedException */ public static boolean isElementPresent(WebDriver driver, final By by, int timeOut) throws InterruptedException { boolean isPresent = false; Thread.sleep(timeOut * 1000); List<WebElement> we = driver.findElements(by); if (we.size() != 0) { isPresent = true; } return isPresent; }
測試步驟:
1.選擇出發城市-> 北京
到達城市->上海
選擇今天之后的七天
點擊search button
2.選擇某帶“每段航班均需繳納稅費” 的訂單
public static void main(String[] args) throws InterruptedException { WebDriver driver = DriverFactory.getChromeDriver(); driver.get("http://flight.qunar.com/"); driver.manage().window().maximize(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); WebElement from_inpox = driver .findElement(By .xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='fromCity']")); WebElement to_inpox = driver .findElement(By .xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='toCity']")); WebElement from_date = driver .findElement(By .xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='fromDate']")); WebElement sigleWayCheckBox = driver .findElement(By .xpath("//div[@id='js_flighttype_tab_domestic']//input[@class='inp_chk js-searchtype-oneway']")); if (!sigleWayCheckBox.isSelected()) { sigleWayCheckBox.click(); } from_inpox.clear(); from_inpox.sendKeys("BJ"); Thread.sleep(8000); By bj = new By.ByXPath( "//div[@class='qcbox-fixed js-suggestcontainer']//td[contains(text(),'北京')]"); if (isElementPresent(driver, bj, 20)) { driver.findElement(bj).click(); } to_inpox.clear(); to_inpox.sendKeys("SH"); Thread.sleep(8000); By sh = new By.ByXPath( "//div[@class='qcbox-fixed js-suggestcontainer']//td[contains(text(),'上海')]"); if (isElementPresent(driver, sh, 20)) { driver.findElement(sh).click(); } // Actions actions = new Actions(driver); // actions.moveToElement(from_inpox).click().perform(); // driver.findElement( // By.xpath("//div[@data-panel='domesticfrom-flight-hotcity-from']//a[@class='js-hotcitylist' and text()='西安']")) // .click(); // driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); // driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); // actions.moveToElement(to_inpox).click().perform(); // driver.findElement( // By.xpath("//div[@data-panel='domesticto-flight-hotcity-to']//a[@class='js-hotcitylist' and text()='北京']")) // .click(); // driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); // driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); from_date.clear(); from_date.sendKeys(getDateAfterToday(7)); WebElement search = driver .findElement(By .xpath("//div[@id='js_flighttype_tab_domestic']//button[@class='btn_search']")); search.submit(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); WebElement page2 = driver.findElement(By .xpath("//div[@id='hdivPager']/a[@value='2']")); JavascriptExecutor jse = (JavascriptExecutor) driver; jse.executeScript("arguments[0].scrollIntoView()", page2); page2.click(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); driver.findElement( By.xpath("(//div[@class='avt_trans']//p[contains(text(),'每段航班均需繳納稅費')]/ancestor::div//div[@class='a_booking']/a)[3]")) .click(); driver.findElement( By.xpath("//div[@id='flightbarXI883']//div[@class='t_bk']/a")) .click(); } public static String getDateAfterToday(int dateAfterToday) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, +dateAfterToday); System.out.println(cal.getTime().toString()); Date date = cal.getTime(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); System.out.println(df.format(date)); return df.format(date); } /** * @author Young * @param driver * @param by * @param timeOut * @return * @throws InterruptedException */ public static boolean isElementPresent(WebDriver driver, final By by, int timeOut) throws InterruptedException { boolean isPresent = false; Thread.sleep(timeOut * 1000); List<WebElement> we = driver.findElements(by); if (we.size() != 0) { isPresent = true; } return isPresent; }
效果如下: