背景
selenium進行項目UI自動化設計,會使用多個客戶端的各種瀏覽器去執行用例,在既定的有限資源裏,總數沒法滿足多個bu去使用,所以希望有比較節約資源的方案,在selenium官方的方案裏提供了docker版本的瀏覽器容器,供UI自動化使用。正常情況下,我們會使用瀏覽器去執行web網頁自動化,也會去執行wap模式的用例(F12下的手機模式,調試H5的,Mobile Emulation只有在chrome 32版本之後纔有),所以希望即使在docker容器下也同樣支持web和wap的運行方式(當讓handless模式也要支持)
selenium: 3.0
pc: selenium-server-standalone-2.53.1.jar
docker: selenium/standalone-chrome-debug-zh:2.53.1
問題
代碼:(use chrome deviceName)
chrome_options = Options()
d = DesiredCapabilities.CHROME.copy()
# 使用默認的device去訪問,構造
chrome_options.add_experimental_option("mobileEmulation", {"deviceName": "iPhone 6"})
d.update(chrome_options.to_capabilities())
# 設置chrome 瀏覽器的驅動環境變量
os.environ["webdriver.chrome.driver"] = self.properties.browserdriver
# 設置chrome 的二進制可執行文件: 啓動不在默認安裝路徑的firefox瀏覽器
driver = webdriver.Chrome(executable_path=self.properties.browserdriver, desired_capabilities=d)
driver.maximize_window()
self.get(driver, self.properties.baseURL, 3)
這裏使用options.add_experimental_option("mobileEmulation", {"deviceName": "Nexus 5X"})
來觸發chrome瀏覽器的手機模式,在正常的window和mac客戶端執行、甚至window虛擬機執行都沒有問題,但在docker-chome上執行就會出現,下面錯誤:
unknown error: cannot parse capability: chromeOptions
from unknown error: cannot parse mobileEmulation
from unknown error: 'iPhone 6' must be a valid device
from unknown error: must be a valid device
(Driver info: chromedriver=2.24.417424 (c5c5ea873213ee72e3d0929b47482681555340c3),
platform=Linux 3.10.0-693.el7.x86_64 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 37 milliseconds
Build info: version: '2.53.1', revision: 'a36b8b1', time: '2016-06-30 17:37:03'
System info: host: '065486cae03a', ip: '172.18.0.6', os.name: 'Linux', os.arch: 'amd64',
os.version: '3.10.0-693.el7.x86_64', java.version: '1.8.0_91'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command duration or timeout: 85 milliseconds
Build info: version: '2.53.1', revision: 'a36b8b1cd5757287168e54b817830adce9b0158d', time: '2016-06-30 19:26:09'
System info: host: 'N/A', ip: 'N/A', os.name: 'Linux', os.arch: 'amd64', os.version: '3.10.0-229.el7.x86_64',
java.version: '1.7.0_79'
Driver info: org.openqa.selenium.remote.RemoteWebDriver
由錯誤信息裏可以看到cannot parse capability
錯誤,這個說是解析出錯,也就是遠程的docker中webdriver驅動解析這個chromeOptions
參數時,無法識別,且無法識別的是deviceName
的值iPhone 6
。
分析
無法識別? 從系統上分析,一個window一個linux,那麼第一個可能的問題就是docker下chrome的驅動有一定的限制或差異,無法去處理;還有就是docker-chrome中就沒有iPhone 6
這個deviceName;應該是這個使用方式的問題 。
經過排查,docker-chrome裏的device list裏有且當前版本的mobile emulation都有
那麼剩下的問題就是驅動層面了,我覺得就沒必要去花時間去研究驅動了,你去改dockerFile,一頓搞還不一定有效。在chromeWebdriver官網提供三種使用方式,所以可以嘗試其他方法。
官方提供方法
先啓動Selenium客戶端, 比如命令:java -jar selenium-server-standalone-XXX.jar。
一、chrome選項裏模擬設備(比如iPhone 6)(docker方案下不生效
):
from selenium import webdriver
mobile_emulation = { "deviceName": "iPhone 6" }
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Remote(command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities = chrome_options.to_capabilities())
注意
:ChromeDriver的已知設備列表是從DevTools Emulation面板中的設備生成的。但是,可以針對具有較新或較舊設備列表的Chrome版本使用ChromeDriver版本。如果您嘗試使用ChromeDriver無法識別的設備名稱,您會看到錯誤:“<您的設備名稱>必須是有效設備。”要模擬ChromeDriver不知道的設備,請啓用移動仿真功能單個設備指標.
二、chrome選項裏邊沒有想要模擬設備,可以自定義
:
from selenium import webdriver
mobile_emulation = {
"deviceMetrics": { "width": 414, "height": 736, "pixelRatio": 3.0 },
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1" }
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome(chrome_options = chrome_options)
指定單個設備屬性
:通過指定各個屬性來啓用移動仿真。要以這種方式啓用Mobile Emulation,“mobileEmulation”字典可以包含“deviceMetrics”字典和“userAgent”字符串。必須在“deviceMetrics”字典中指定以下設備指標:
“width” - 設備屏幕的寬度(以像素爲單位)
“height” - 設備屏幕的高度(以像素爲單位)
“pixelRatio” - 設備的像素比率
“touch” - 是否模擬觸摸事件(默認爲true,通常不需要設置)
三、修改瀏覽器的User-Agent來僞裝你的瀏覽器訪問手機m站:
這個和第二個方案很像,區別還是有的,在哪呢?主要是執行是展示的頁面樣式,是全瀏覽器(會有拉伸的效果),而第二種方式給設置了寬和高及分辨率,樣式同手機.
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1')
driver = webdriver.Chrome(chrome_options = chrome_options)
實踐
通過三種方式的對比,我們選擇第二種方案來解決這個問題,先去找所需的UA
小米8
"mobileEmulation", {
"deviceMetrics": {"width": 414, "height": 736, "pixelRatio": 3.0},
"userAgent": "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; MI 8 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.2 Mobile Safari/537.36"
}
iphone x
"mobileEmulation", {
"deviceMetrics": {"width": 414, "height": 736, "pixelRatio": 3.0},
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_1_2 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0 Mobile/15B202 Safari/604.1"
}
代碼:
chrome_options = Options()
d = DesiredCapabilities.CHROME.copy()
chrome_options.add_argument("--disable-extensions")
# 忽略掉這個警告提示語
chrome_options.add_argument('--disable-infobars')
chrome_options.add_argument('--log-level=0')
# 使用ua去打造手機模式的訪問
chrome_options.add_experimental_option("mobileEmulation", {"deviceMetrics": {"width": 414, "height": 736, "pixelRatio": 3.0},
"userAgent": "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; MI 8 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.2 Mobile Safari/537.36" })
d.update(chrome_options.to_capabilities())
if self.properties.type == '0':
remote = self.properties.remoteProfile.pop('url')
d.update(self.properties.remoteProfile)
d.update(chrome_options.to_capabilities())
driver = webdriver.Remote(command_executor=remote, desired_capabilities=d)
elif self.properties.type == '1':
# 設置chrome 瀏覽器的驅動環境變量
os.environ["webdriver.chrome.driver"] = self.properties.browserdriver
# 設置chrome 的二進制可執行文件: 啓動不在默認安裝路徑的firefox瀏覽器
driver = webdriver.Chrome(executable_path=self.properties.browserdriver, desired_capabilities=d)
driver.set_page_load_timeout(self.pageLoadTimeout)
driver.implicitly_wait(self.waitTimeout)
driver.set_script_timeout(self.scriptTimeout)
driver.maximize_window()
self.get(driver, self.properties.baseURL, 3)
實驗結果
:這種方式支持所有形式的瀏覽器,且不會存在平臺上的差異,只要是chrome瀏覽器在32版本之上就行,所以我的問題解決
;
總結
- selenium可以支持各種形式的瀏覽器,實體機、虛擬機、容器;
- docker版本的瀏覽器,不限於chrome,還有firefox;
- 推薦使用自定義模式去處理wap模式的自動化;
- docker-chrome,selenium官方給的容器裏有裝VNC的服務,你可以在本機使用
VNC Viewer
去訪問容器的5900
端口,來查看docke裏用例運行的界面,以方便調試