【Selenium】docker-chrome執行wap模式的問題與解決方法

背景

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版本之上就行,所以我的問題解決

總結

  1. selenium可以支持各種形式的瀏覽器,實體機、虛擬機、容器;
  2. docker版本的瀏覽器,不限於chrome,還有firefox;
  3. 推薦使用自定義模式去處理wap模式的自動化;
  4. docker-chrome,selenium官方給的容器裏有裝VNC的服務,你可以在本機使用VNC Viewer去訪問容器的5900端口,來查看docke裏用例運行的界面,以方便調試
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章