瀏覽器的基本操作與元素定位
通過上一章學習,我們已經學會了如何設置驅動路徑,如何創建瀏覽器對象,如何打開一個網站,接下來我們要進行一些復雜的操作比如先打開百度首頁,在打開博客園,網頁后退,前進等等,甚至可以獲取一些瀏覽器信息等等。
首先看一個基本的例子,流程如下:
- 打開百度的網站
- 獲取到百度首頁的Title
- 獲取當前頁面的URL
- 獲取頁面的html信息
對應的代碼如下:
public class SeleniumTest { public static void main(String... args){ System.setProperty("webdriver.gecko.driver","c:\\geckodriver.exe"); WebDriver webDriver = new FirefoxDriver(); webDriver.get("http://www.baidu.com"); System.out.println(webDriver.getTitle());//獲取首頁的Title System.out.println(webDriver.getCurrentUrl());//獲取當前url System.out.println(webDriver.getPageSource());//獲取頁面的html信息 } }
再來看一個例子,操作流程如下:
- 打開百度首頁
- 打開我的博客頁面
- 后退到百度頁面
- 前進到博客頁面
- 刷新頁面
- 關閉頁面
對應的代碼如下:
public class SeleniumTest { public static void main(String... args){ System.setProperty("webdriver.gecko.driver","c:\\geckodriver.exe"); WebDriver webDriver = new FirefoxDriver(); webDriver.navigate().to("http://www.baidu.com"); webDriver.navigate().to("https://www.cnblogs.com/jacktest"); webDriver.navigate().back();//后退 webDriver.navigate().forward();//前進 webDriver.navigate().refresh();//刷新 webDriver.close();//關閉瀏覽器 webDriver.quit();//關閉瀏覽器以及驅動 } }
close 和 quit區別:close 只會關閉當前瀏覽器,而quit不僅會關閉瀏覽器也會殺掉驅動進程。close的問題在於你多次進行調試時,進程中會殘留多個驅動進程,這種情況有可能會引起一些其他的問題,建議使用quit。
源碼分析,close和quit在發送 HttpRequest 請求時,method 都是DELETE ,但uri不同,如下:
close的HttpRequest

quit 的HttpRequest

最后看一個例子,基礎元素定位,流程如下:
- 打開百度首頁
- 點擊登錄鏈接
- 輸入用戶名、密碼
- 點擊登錄
對應的代碼如下:
public class SeleniumTest { public static void main(String... args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", "C:\\driver\\geckodriver.exe"); WebDriver webDriver = new FirefoxDriver(); webDriver.manage().window().maximize();//瀏覽器最大化 webDriver.get("https://www.baidu.com"); webDriver.findElement(By.xpath("//div[@id='u1']/a[@name='tj_login']")).click();//點擊登錄鏈接 Thread.sleep(1000); webDriver.findElement(By.id("TANGRAM__PSP_10__footerULoginBtn")).click();//點擊用戶名登錄 webDriver.findElement(By.id("TANGRAM__PSP_10__userName")).sendKeys("jacktest");//輸入用戶名 webDriver.findElement(By.id("TANGRAM__PSP_10__password")).sendKeys("123456");//輸入密碼 webDriver.findElement(By.id("TANGRAM__PSP_10__submit")).click();//點擊登錄 } }
運行該腳本,我們發現打開了火狐瀏覽器,打開百度首頁,點擊了登錄鏈接,輸入了用戶名、密碼並成功進行了登錄。什么登錄失敗,哈哈,當然,賬號換成你自己的就ok 了。
代碼分析,在該腳本中,我們看到了Thread.sleep(1000),它的作用是讓腳本執行時暫停1秒,有的同學會問,為什么要暫停呢?因為我的腳本在執行完webDriver.findElement(By.xpath("//div[@id='u1']/a[@name='tj_login']")).click()這條語句后,彈出窗口不會馬上彈出來,大概需要 0.5-1秒的時間,如果在窗口未彈出的情況下執行下一條語句時,就會發生錯誤(org.openqa.selenium.NoSuchElementException異常---找不到元素),所以,我要等待一下,等窗口出現以及頁面上的元素出現就不會出現以上錯誤了。有的同學會問,難道所有的窗口以及元素或頁面都得等待嗎,我們都需要加sleep嗎,浩哥的回答是當然不需要。在腳本調試過程中,只有極個別的情況需要加等待,當然我們也有更好的方式去解決這個問題,比如顯示等待,隱式等待,自定義等待等等。
接下來,我們再來看幾個常用的方法:
public class SeleniumTest { public static void main(String... args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", "C:\\driver\\geckodriver.exe"); WebDriver webDriver = new FirefoxDriver(); webDriver.manage().window().fullscreen();//瀏覽器全屏,相當於F11 Point point = new Point(50, 100); webDriver.manage().window().setPosition(point);//指定窗口出現的位置 Dimension dimension = new Dimension(500, 600); webDriver.manage().window().setSize(dimension);//指定窗口大小 WebDriver.ImeHandler imeHandler = webDriver.manage().ime(); System.out.println(imeHandler.isActivated());//輸入法相關的API,查了一些資料好像只支持linux,有興趣可以自己試試 } }
日志相關的API,指的是Selenium原生的日志支持,並不是指比如像 log4j 這樣的外部提供的日志支持。
public class SeleniumTest {
public static void main(String... args) throws InterruptedException {
System.setProperty("webdriver.gecko.driver", "C:\\driver\\geckodriver.exe");
DesiredCapabilities desiredCapabilities = DesiredCapabilities.firefox();
LoggingPreferences loggingPreferences = new LoggingPreferences();
loggingPreferences.enable(LogType.BROWSER, Level.ALL);
loggingPreferences.enable(LogType.CLIENT, Level.ALL);
loggingPreferences.enable(LogType.DRIVER, Level.ALL);
desiredCapabilities.setCapability(CapabilityType.LOGGING_PREFS, loggingPreferences);
WebDriver webDriver = new FirefoxDriver(desiredCapabilities);
LogEntries logEntries = webDriver.manage().logs().get(LogType.BROWSER);
for (LogEntry logEntry : logEntries) {
System.out.println(logEntry.getMessage()+"--");
}
webDriver.get("https://www.baidu.com");
}
}
自己試驗了一下上述代碼,在Selenium 3.0 之前的版本中可以支持,在之后無法支持,提示org.openqa.selenium.UnsupportedCommandException: POST /session/419bca1f-d33d-46ff-8979-10e88901cd12/log did not match a known command。好像是由於logs 並不支持 W3C 規范,大家也可以試試其他的方法是否支持。如果想關閉運行Selenium的日志輸出,可把loggingPreferences.enable(LogType.BROWSER, Level.OFF)設置成off即可。
接下來,我們再看一個有關 Session id 相關的 API:
public class SeleniumTest { public static void main(String... args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", "C:\\driver\\geckodriver.exe"); WebDriver webDriver = new FirefoxDriver(); webDriver.get("https://www.baidu.com"); Set<String> strings = ((FirefoxDriver) webDriver).getLocalStorage().keySet(); for (String s : strings) { System.out.println(s); //輸出結果為BIDUPSID } System.out.println(((FirefoxDriver) webDriver).getLocalStorage().getItem("BIDUPSID"));//獲取值 } }
有的同學問,輸出結果為什么是BIDUPSID呢,代表什么意思呢,看完后面的內容大家就明白了。
首先我們先看一下api,根據 Selenium3 官方文檔 LocalStorage 的表示當前在瀏覽器中打開站點的本地存儲,每個站點都有自己的獨立的存儲區域,也就是打開不同的網站 LocalStorage 各不相同,大家可以自行試驗。有的同學會問,那這和 Session id 有什么關系呢,接下來,我們來普及一下 Session 的一些知識。
Session id 主要是用來維持會話狀態的通信秘鑰,在請求過程中,默認名字SESSIONID,當然也可以自定義命名(百度的Sessionid是自定義命名)。以百度為例,用戶第一次訪問www.baidu.com的時候,由於請求頭(Request Header)中沒有帶BIDUPSID,百度服務器認為這是一個新的會話,會在服務端給這次會話生成一個唯一標識的 Session id,同時會在http請求的(Response header)中將這個 Session id 帶給瀏覽器,反應在請求的Response header,如下:
Set-Cookie:BIDUPSID=EEAE958FDBA12D0BECDA19585965F6E8; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
這個Session id 就是 key=BIDUPSID,value=EEAE958FDBA12D0BECDA19585965F6E8 這樣一個結構,瀏覽器接收到 response 中Set-Cookie命令之后,會在瀏覽器設置cookie 值 BIDUPSID=EEAE958FDBA12D0BECDA19585965F6E8,並在以后請求 baidu.com 這類域名時帶上cookie值,既 Request Header 中帶上Cookie:BAIDUID=EEAE958FDBA12D0BECDA19585965F6E8,這樣服務器就可以通過這個秘鑰來識別請求來自哪個用戶了。
繼續驗證上述問題,打開google瀏覽器,清除百度頁面相關的所有緩存,打開開發者模式,切換到 Network 頁,在瀏覽器中輸入https://www.baidu.com,其中部分請求頁面如下:

點擊第一個請求,在Header中進行查看,
General
Request URL:https://www.baidu.com/
Request Method:GET
Status Code:200 OK
Remote Address:111.13.100.92:443
Referrer Policy:no-referrer-when-downgrade
Response Headers
Connection:Keep-Alive
Content-Length:225
Content-Type:text/html
Date:Mon, 09 Jul 2018 07:20:43 GMT
Location:https://www.baidu.com/
P3p:CP=" OTI DSP COR IVA OUR IND COM "
Server:BWS/1.1
Set-Cookie:BD_LAST_QID=10490791214885359030; path=/; Max-Age=1
Set-Cookie:BAIDUID=813A9265BC68AC521C003B3ABEFDB222:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie:BIDUPSID=D09FD09E7F46EBE0242500D6844DEE1D; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie:PSTM=1531120843; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
X-Ua-Compatible:IE=Edge,chrome=1
Request Header
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.9
Connection:keep-alive
Host:www.baidu.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
分析如下:由於第一次請求時未存在 BIDUPSID,所以百度服務器認為這是一次新的會話,接着在服務端生成唯一標識Sessionid,既Set-Cookie:BAIDUID命令,下次請求baidu.com的網頁時會帶上這個信息。
打開另一個Tab頁面,輸入百度首頁,查看 Request Header,信息如下:
General
Request URL:https://www.baidu.com/
Request Method:GET
Status Code:200 OK
Remote Address:111.13.100.91:443
Referrer Policy:no-referrer-when-downgrade
Response Headers
Bdpagetype:1
Bdqid:0xa07b1f01000072b3
Cache-Control:private
Connection:Keep-Alive
Content-Encoding:gzip
Content-Type:text/html
Cxy_all:baidu+7fa1ff7e20dcb627a29697a5f962bcc8
Date:Mon, 09 Jul 2018 07:43:37 GMT
Expires:Mon, 09 Jul 2018 07:43:22 GMT
Server:BWS/1.1
Set-Cookie:BDSVRTM=0; path=/
Set-Cookie:BD_HOME=0; path=/
Set-Cookie:H_PS_PSSID=1425_25810_21083_20719; path=/; domain=.baidu.com
Strict-Transport-Security:max-age=172800
Transfer-Encoding:chunked
Vary:Accept-Encoding
X-Ua-Compatible:IE=Edge,chrome=1
Request Header
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.9
Connection:keep-alive
Cookie:BAIDUID=813A9265BC68AC521C003B3ABEFDB222:FG=1; BIDUPSID=813A9265BC68AC521C003B3ABEFDB222; PSTM=1531121867; BD_HOME=0; H_PS_PSSID=1425_25810_21083_20719; BD_UPN=12314353; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1
Host:www.baidu.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
因為在第一次請求時服務器已經返回了BIDUPSID,所以下一次請求時候直接在request header 中加上了BIDUPSID(Sessionid),既驗證了上述內容。
關於 Selenium cookie 操作的 API,我們會在之后的API 進行分析,此處先略過。
通過本章的學習的,我們學會了幾個操作,如何操作瀏覽器,怎么點擊元素(click),怎么輸入數據(sendKeys),元素定位(id的方式),元素定位(xpath的方式)。是不是感覺很簡單,其實 Selenium 的API 中常用方法只有十幾個,使用起來還是蠻簡單的。
在下一篇 《常用定位模式分析》中,我們會一一介紹所有的元素定位模式。
