【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里用例运行的界面,以方便调试
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章