記錄我遇到的使用selenium讓人摸不著頭腦的問題
問題一
使用webdriver驅動firefox瀏覽器時如果不設定引數,預設使用的Firefox的profile和平時開啟瀏覽器使用的firefox不一樣,如果要使用平常使用的配置,解決方法:
string sPath = @"C:\Users\xxxx\AppData\Roaming\Mozilla\Firefox\Profiles\5f3xae4a.default"; FirefoxProfile ffprofile = new FirefoxProfile(sPath);
sPath 是你的firefox瀏覽器的配置檔案路徑,如何獲得這個路徑,google一下你就知道。
btw,火狐瀏覽器的profile還可能引起
問題二
我之前一篇文章《selenium webdriver缺陷》介紹過,當頁面上有js或者ajax等動態元素時,webdriver判斷頁面載入完成實際上只是html和js程式碼載入完成,js生成的元素是否已經出現在頁面原始碼中是未知的,所以必須顯示指明等待某元素出現,以判斷這個元素是否已經被js等動態指令碼生成:
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60)); wait.Until(ExpectedConditions.ElementExists(by));
問題三
操作頁面元素時丟擲異常,頁面元素為不可見,無法操作。這個問題的原因我遇到二種,一種是css樣式直接指定該元素或者父元素的display屬性為none,解決方法, 使用js注入直接修改元素的display屬性為block,下面的程式碼是修改FindElements獲取的多個元素的display屬性。
ReadOnlyCollection<IWebElement> eles = driver.FindElements(by); IJavaScriptExecutor js = driver as IJavaScriptExecutor; foreach (IWebElement ele in eles) { js.ExecuteScript("arguments[0].style.display='block';", ele); }
第二種原因是js的問題,因為還沒有輸出完畢,獲取到的元素有可能被提示為不可見,解決方法:
執行緒sleep一定的時間等待它為可見,或者用webdriver的判斷元素是否可見的方法,等待直到元素可見才執行之後的程式碼。(建議使用webdriver提供的方法)
問題四
操作元素時得到等待元素超時的異常。這個問題大多人第一反應可能是元素還沒出現在頁面原始碼中,例如問題二中提到的。但還有另外一個原因也會導致丟擲這個異常,這是我今天做youtube自動上傳模組遇到的情況。
其實webdriver對頁面元素的所有操作都是通過將js程式碼注入到目標頁面實現的(btw,為了實現這個目的webdriver使用了一個技巧避開了瀏覽器的”同源策略“,這也是webdriver的一個創造性的地方,有興趣可以google一下),那麼就存在js指令碼的執行順序問題,youtube上傳頁面需要執行js指令碼以把檔案上傳到伺服器,在整個檔案上傳的過程中,我程式碼中對頁面元素的操作都會丟擲超時異常,而且這個時候元素已經出現在頁面原始碼中了(我的程式中在操作元素之前獲取了當時的頁面原始碼,元素確實已經存在),所以不是因為元素不存在導致的超時,而是頁面上的上傳檔案的js原始碼執行阻塞了操作元素的webdriver的js原始碼的執行,直到超時報錯,另外,如果由於對元素的操作本身時間過長,比如sendkey()一大堆的文字,當超過設定的超時時限sendkey還沒執行完畢也會得到這個異常。解決方法:
因為不知道上傳檔案需要多久,所以如果元素的操作時機沒什麼限制的話,捕獲異常後繼續等待,直到操作成功為止。
如果是因為元素自身操作超時,那麼可以尋找不需要那麼長執行時間的替代方案,或者加長超時時間保證操作有充足的執行時間。
問題五
driver初始化異常。我遇到過兩種原因導致出現這個問題,一是firefox配置資料夾所在的硬碟分割槽空間不夠,二是程式執行時有以webdriver以外的方法開啟的firefox瀏覽器例項(比如雙擊firefox瀏覽器快捷方式開啟)。解決方法:
清理硬碟空間。先關閉導致問題產生的瀏覽器例項再執行程式。
問題六
元素click()之後,本該執行的操作順利執行,但是程式卻掛在click()方法中,直到丟擲連結遠端伺服器超時異常。
解決方法:在google code上很多老外都遇到這樣的問題,似乎是一個selenium的bug,目前沒有很好的解決方法,只能等到超時後捕獲這個異常,繼續下面的程式執行,為了縮短等待的時間,可以把這個超時時間設定得短一點:
driver = new FirefoxDriver(new FirefoxBinary(), ffprofile, new TimeSpan(0, 0, 0, 60)); 最後一個引數就是設定對應的超時時間,這個超時時間不是隱式、顯式等待以及scripttimeout,而且似乎也沒辦法在driver 初始化之後進行改動。