Selenium 4.0beta:讀原始碼學習新功能
阿新 • • 發佈:2021-03-14
# Selenium 4 原始碼分析
這一篇文章我們來分析Selenium 4 python版原始碼。
除非你對Selenium 3的原始碼爛熟於心,否則通過對比工具分析更容易看出Selenium 4更新了哪些API。
檔案對比工具推薦 Beyond Compare
![](https://img2020.cnblogs.com/blog/311516/202103/311516-20210313234449346-700238718.png)
## 驅動支援
Selenium 4 去掉了`android`、`blackberry`和`phantomjs` 等驅動支援。
* Selenium 對 android的支援本來就比較雞肋,我想幾乎沒有人用Selenium來做android自動化測試,所以,去掉android專注於 Web 才是Selenium的定位。
* Blackberry 是針對黑莓手機的驅動,嗯!沒落的黑莓手機。
* phantomjs 自從有了 chrome headless 模式,phantomjs 幾乎沒有維護的必要的。
Selenium 增加了 `chromium` 和 `wpewebkit` 驅動。
* chromium 是一個開源瀏覽器專案,chrome、chromiumEdge 都是基Chromium開發的。
* wpewebkit 關於wpewebkit的資料很少,只找到了一名介紹`為低端裝置優化的WebKit埠`。
chromium 不需要直接使用,它主要是給chrome、chromiumEdge 繼承的父類,如果要直接使用,必須要指定 `browser_name` 和 `vendor_prefix` 兩個引數。
```python
from selenium.webdriver.chromium.webdriver import ChromiumDriver
dr = ChromiumDriver(browser_name='??', vendor_prefix='??')
'''
- browser_name - Browser name used when matching capabilities.
- vendor_prefix - Company prefix to apply to vendor-specific WebDriver extension commands.
'''
```
wpewebkit 是可以直接使用,但是驅動應該只支援 Linux系統,我沒做驗證。
```python
from selenium import webdriver
dr = webdriver.WPEWebKit()
```
## 棄用定位方法
以前常用的定位方法將被棄用。
` warnings.warn("find_element_by_* commands are deprecated.
Please use find_element() instead")`
```python
from selenium import webdriver
dr = webdriver.Chrome()
dr.get("https://www.baidu.com")
dr.find_element_by_id("kw").send_keys("selenium4")
dr.find_element_by_id("su").click()
```
`find_element_by_xx` 將被棄用,推薦使用`find_element()`
```python
from selenium import webdriver
from selenium.webdriver.common.by import By
dr = webdriver.Chrome()
dr.get("https://www.baidu.com")
dr.find_element(By.ID, "kw").send_keys("selenium grid4")
dr.find_element(By.ID, "su").click()
dr.close()
```
上面的定位寫法在 selenium3 一直是被支援的,只是我們一般很少使用。
## 相對定位
這是 Selenium4 的一個亮點,官方稱他為`相對定位`, 官方部落格對相對定位的說明。
想想我們如何描述元素在頁面上的位置。想想你在電話裡會怎麼做。你永遠不會談論原始DOM,`啊,找到巢狀在span標籤中的第五個div標籤,其id為foo`。你永遠不會這麼說!相反,當談到內容在頁面上的位置時,你會說`只需在圖片上方和連結右側找到該內容`。
很久以前,一個名為[Sahi](https://sahipro.com/docs/sahi-apis/accessor-api-basics.html)的專案開始定位這樣的元素。在Selenium4中,我們稱它們為`相對定位器`。你有時可能會看到我們將它們稱為`友好定位器`,因為最初的實現稱它們為友好定位器,但`相對`更好地描述了它們的工作方式。我們有幾個:`near`, `above`, `below`, `to_left_of`, `to_right_of`。它們允許你用人類語言談論元素在頁面上的位置。
```python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import with_tag_name
dr = webdriver.Chrome()
dr.get("https://www.xx.com")
lowest = dr.find_element(By.ID, "below")
elems = dr.find_elements(with_tag_name("p").above(lowest))
ids = [el.get_attribute('id') for el in elems]
print(ids)
```
## 新增API
在`remote.webdriver`檔案的`WebDriver` 類(所有瀏覽器類都繼承該類)新增的幾個API無關痛癢,而且還沒註解,所以暫時不清楚具體用法。
* log: 無註釋
* pin_script:無註釋
* unpin: 無註釋
* get_pinned_scripts: 無註釋
```py
dr.pin_script(script="??")
dr.unpin(script_key="??")
print(dr.get_pinned_scripts())
```
不過,我也發現了幾個有用的API
* 開啟並切換到新視窗/標籤。
```python
dr.switch_to.new_window("window")
dr.switch_to.new_window("tab")
```
* 獲取不同設定的超時間。
```python
from selenium import webdriver
dr = webdriver.Chrome()
dr.implicitly_wait(10)
dr.set_page_load_timeout(3)
dr.set_script_timeout(7)
print(dr.timeouts.implicit_wait)
print(dr.timeouts.page_load)
print(dr.timeouts.script)
```
* 獲取當前頁面PDF檔案。
```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.headless = True
dr = webdriver.Chrome(options=chrome_options)
dr.get("https://docs.pytest.org/en/stable/#documentation")
# 獲取當前頁面PDF檔案
print(dr.print_page())
```
## Trio CDP
`common`目錄下面多出`bidi` 和`devtools` 兩個子目錄。檢視原始碼 提供了Trio CDP的專案連線。
https://github.com/HyperionGray/trio-chrome-devtools-protocol
CDP全稱:Chrome DevTools Protocol
關於CDP的介紹,官方有一段介紹:
> CDP是一種基於Chrome的瀏覽器中啟用偵錯程式而開發的協議。它是一個非正式協議,不是一個面向使用者的API,允許您反省瀏覽器。 Puppeteer和Cypress者建立在該協議上,在測試和瀏覽器之間引入一個`network hop`,隨著網路延遲的增加,這種方式會導致測試速度變慢。更復雜的是,由於CDP被設計為一個除錯協議,所以在不同版本之間它可以在沒有任何通知的情況下進行更改。這就是為什麼Puppeter和Cypress與特定版本的瀏覽器繫結在一起,這給作為測試作者的您帶來了一個難題:如何在瀏覽器的多個版本上進行測試?
>
> 儘管如此,使用CDP還是有很多可能性,這就是為什麼我們在Selenium4中增加了對它的支援。事實上,我們的一些新功能是建立在它之上的(儘管我們隱藏了細節!)
程式碼註解的示例:
```py
from selenium import webdriver
from selenium.webdriver.common.bidi.console import Console
dr = webdriver.Chrome()
dr.get("https://www.baidu.com")
with dr.log.add_listener(Console.log) as messages:
dr.execute_script("console.log('I like cheese')")
assert messages["message"] == "I love cheese"
```
## 最後
官方部落格裡還提到了:
* `對網站的身份驗證`:來解決網站的登入問題。
* `攔截網路流量`:來解決網路的穩定性。
官方文件和原始碼中都沒找到例子或API,後續再做