Selenium 设计的目的是为了自动化的操作浏览器,完成自动化 Web 测试任务。当然,Selenium 的能力不止如此,所有浏览器自动化的工作都可以考虑使用 Selenium 完成。Selenium 受大部分浏览器厂家支持如 chrome、firefox,并且在一些平台成为浏览器原生的一部分。Selenium 分为 WebDriver 和 IDE 两部分,如果想创建自动化或测试任务你需要使用 WebDriver,如果目的要记录某个 feature 或者 bug 的重现路径那么需要使用 IDE,本文主要讲述 WebDriver。
首先 Selenium 从实现原理上可以看做是一个驱动程序,为不同厂商封装了统一接口,接口下调用了不同厂商的浏览器实现,从适配器模式的角度理解
Selenium 为 adptor,chromedriver 即为其中的一个 Adaptee, 比较值得一提的是 PhantomJS,PhantomJS 是一个没有 GUI 的浏览器,能够运行 JavaScript 脚本。同时 Selenium 支持 PhantomJS 做为 Adaptee 前端,那么我们便可以结合 PhantomJS 与 Selenium 模拟抓取一些 js 代码比较多的网页,为了直观效果,本文使用 Chrome 作为前端。Selenium 支持多种开发语言,如 Java、C、Ruby 等,下文以 python 为例介绍 Selenium 的一些简单用法。
Selenium 通过 chromedriver 支持对 chrome 的操作,下载 chromedriver 放到执行 PATH 路径中然后通过 pip 安装 Selenium 即可使用。
pip install selenium |
Selenium 是模拟测试工具,在开发基于 Selenium 的 Task 时应该遵循模拟用户的操作这一原则。比如在抓取网络数据时,通常的思路是通过嗅探 header 字段,构造 http 请求并解析返回结果,但是在 Selenium 中需要模拟的是用户的输入、下滑、翻页等操作,然后通过 driver 的 page_source 拿到网页源码然后解析结果。
from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("http://baidu.com") print(driver.title) elem = driver.find_element_by_name("kw") elem.send_keys("heheda") elem.send_keys(Keys.RETURN) print driver.page_source driver.find_element_by_id('su').click() |
driver.get 方法会在页面的 onload 事件触发时立即返回,也就是说如果页面中有很多 ajax 请求的话,driver.get 方法返回时可能页面还没有加载完成。driver 还提供了一些 find_element_by_* 方法方便定位到特定的 DOM 节点进行后续操作。同时 selenium.webdriver.common.keys 模块中提供了一些特定的键值来模拟用户输入操作。driver.quit() 与 driver.close() 提供了关闭浏览器或者浏览器标签的方法。
Selenium 提供了简单的设置或者获取 Cookie 的方法:
# Go to the correct domain driver.get("http://www.example.com") # Now set the cookie. This one's valid for the entire domain cookie = {‘name’ : ‘foo’, ‘value’ : ‘bar’} driver.add_cookie(cookie) //获取 Cookie # Go to the correct domain driver.get("http://www.example.com") # And now output all the available cookies for the current URL driver.get_cookies() |
页面等待
刚才说到 driver.get 方法会在 onload 时立即返回,对于大量使用 ajax 的页面我们可能无法正确获取到目标元素,或者一些页面设置了延时加载策略,针对这种情况我们需要设置一个合理的等待策略,在等待一段时间后再去获取页面元素以避免 ElementNotVisibleException。Selenium 提供了两种不同的等待策略:显式,隐式。
显式策略是指明确的指定一个等待时间,如果在指定时间到达时不能顺利获取元素则抛出异常,其本质就是简单的 time.sleep(),Selenium 为这一情况封装了更为便捷的语法:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("http://somedomain/url_that_delays_loading") try: element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")) ) finally: driver.quit() |
上述代码会抛出 TimeoutException 如果在 10 秒内没有找到相关元素。Selenium 会每格 500 毫秒检测一次 try 中的代码,如果能够顺利获取结果则正常返回。同时 Selenium 已经封装了大多数事件如下,用户不需要重写规则
- title_is
- title_contains
- presence_of_element_located
- visibility_of_element_located
- visibility_of
- presence_of_all_elements_located
- text_to_be_present_in_element
- text_to_be_present_in_element_value
- frame_to_be_available_and_switch_to_it
- invisibility_of_element_located
- element_to_be_clickable
- staleness_of
- element_to_be_selected
- element_located_to_be_selected
- element_selection_state_to_be
- element_located_selection_state_to_be
- alert_is_present
隐式策略则是设置一个固定的等待时间(默认为0),如果在这个时间之内找到元素则返回,如果到时候仍未找到则抛出异常,这个固定的等待时间对 driver 全局有效。
from selenium import webdriver driver = webdriver.Chrome() driver.implicitly_wait(10) # seconds driver.get("http://somedomain/url_that_delays_loading") myDynamicElement = driver.find_element_by_id("myDynamicElement") |
截图
使用 save_screenshot 方法保存网页截图
from selenium import webdriver driver = webdriver.Chrome() driver.get("http://baidu.com") driver.set_window_size(900, 600) driver.save_screenshot('1.png') |
为获取特定元素的截图,可以先从 driver 中获取到该元素,然后取得元素的位置信息,通过图片处理工具截取得到:
element = driver.find_element_by_* left = element.location['x'] top = element.location['y'] right = left + element.size['width'] bottom = top + element.size['height'] im = Image.open('screenshot.png') im_element = im.crop((left, top, right, bottom)) im_element.save('element.png') |
通过上述代码可以轻松的获取到页面中的验证码,二维码等一些结构信息便于后续使用。但是在 driver 的 save_screenshot 中,不同的前端处理方法不同,PhantomJS 可以直接截取整个屏幕的长图,但是 Chrome 只能截取到当前屏幕内容。另外对于一些网页内图片的延时加载问题,可以通过注入一段 js 让 driver 翻滚到在下方的方法加载到。
欢迎加入软件测试交流群~1125760266 共同学习交流~