1 介绍

Selenium是一组不同的软件工具,每个工具都有不同的方法来支持自动化测试,Selenium支持多种语言开发,比如 Java、C、Python等。
Selenium有两个版本,Selenium 2 (也叫Selenium WebDriver),它支持WebDriver API和底层技术,以及WebDriver API下的Selenium 1技术,以便在移植测试时具有最大的灵活性。另外,Selenium 2仍然运行Selenium 1的Selenium RC接口,以向后兼容。
Selenium 1是一个很长时间以来的主要的Selenium项目,现在Selenium 1已经被弃用,并且没有得到积极的支持(主要是在维护模式中)。

2 安装

pip方式直接安装

pip install selenium

pycharm安装方式
运维学python之爬虫工具篇(五)Selenium的用法

3 快速开始

3.1 小试牛刀

主要用selenium打开浏览器,获取给定网页:

from selenium import webdriver①

browser = webdriver.Firefox()②
browser.get('http://seleniumhq.org/')③

正常来讲,安装完selenium后,①导入模块是没有问题的,但②步会有报错,错误如下图:
运维学python之爬虫工具篇(五)Selenium的用法
如果遇到这个问题,就是驱动问题,需要我们下载相应浏览器驱动驱动下载,放到浏览器的目录下,然后在系统环境变量中添加浏览器的路径,如下图:
驱动放到浏览器目录中
运维学python之爬虫工具篇(五)Selenium的用法
配置环境变量
运维学python之爬虫工具篇(五)Selenium的用法
好的做完上面我们再执行一下程序试试:
正常应该执行第二步,即browser = webdriver.Firefox()时候就会打开你的火狐浏览器,再输入下一步browser.get('https://www.baidu.com'),浏览器就会跳转到百度页面(火狐会有提示,浏览器被远程控制),见下图
运维学python之爬虫工具篇(五)Selenium的用法

3.2 模拟查询

from selenium import webdriver①
from selenium.webdriver.common.keys import Keys②

browser = webdriver.Firefox()③

browser.get('https://www.baidu.com')④
assert '百度一下' in browser.title⑤

elem = browser.find_element_by_name('wd')  ⑥
elem.send_keys('python' + Keys.RETURN)⑦
print(browser.page_source)⑧
browser.quit()⑨

①和②步骤是导入模块
③打开火狐浏览器
④打开百度网页
⑤确定标题是否含有以上文字,不对会报异常(稍后见下图)
⑥通过F12查看搜索框的name为wd,利用webdriver的方法确定搜索框位置
⑦发送搜索的关键词‘python’,并通过Keys模拟键盘操作Keys模拟的键盘按键
⑧输出 page_source 属性,获取网页渲染后的源代码
⑨退出程序
通过F12查看搜索框name
运维学python之爬虫工具篇(五)Selenium的用法
执行结果:
运维学python之爬虫工具篇(五)Selenium的用法

上面代码还可以分行执行

elem.clear()①
elem.send_keys("pycon")②
elem.send_keys(Keys.RETURN)③
assert "No results found." not in driver.page_source④
browser.close()⑤

①清楚搜索框内容
②发送要搜索的关键词
③通过Keys执行操作
④可以再加一个断言,判断是否有返回结果
⑤关闭

3.3 用selenium去写测试

Selenium主要用于编写测试用例。selenium包本身不提供测试工具/框架。您可以使用Python的unittest模块编写测试用例。

# -*- coding: utf-8 -*-

# 导入相应的模块
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class PythonOrgSearch(unittest.TestCase):
    """
    定义测试用例是继承了unittest.TestCase类,继承这个类表明这是一个测试类
    """

    def setUp(self):
        """
        这个设置是初始化的一部分,这个方法将在测试用例类的每个测试函数之前被调用。
        在这里,您正在创建Firefox WebDriver的实例。
        """
        self.driver = webdriver.Firefox()

    def test_search_in_python_org(self):
        """
        这是测试用例方法。测试用例方法应该始终以test字符开始。
        """
        # 创建了一个本地引用,该引用是在setUp方法中创建的驱动对象。
        driver = self.driver
        # 打开请求页面
        driver.get('http://www.python.org')
        # 设置断言,判断是否有关键字Python
        self.assertIn('Python', driver.title)
        # 查找元素,name=‘q’(也就是搜索框的位置)
        elem = driver.find_element_by_name('q')
        # 发送关键字,类似键盘输入的内容
        elem.send_keys('pycon')
        elem.send_keys(Keys.RETURN)
        # 再次设置断言,判断是否含有一下关键字
        assert "No results found." not in driver.page_source

    def tearDown(self):
        """
        每次测试方法都将调用tearDown方法,关闭浏览器
        """
        self.driver.close()

if __name__ == "__main__":
    # 运行测试用例
    unittest.main()

注释已经很清楚,这里就不多解释了。

3.4 页面交互

仅仅能够去查找一些地方并不是很有用,我们真正想做的是与页面交互,或者更确切地说,是页面中的HTML元素。首先,我们需要找到它,WebDriver提供了多种方法来查找元素。例如:

<input type="text" name="passwd" id="passwd-id" />

可以通过下面的任何一种方式找到他

element = driver.find_element_by_id("passwd-id")
element = driver.find_element_by_name("passwd")
element = driver.find_element_by_xpath("//input[@id='passwd-id']")

你还可以通过它的文本链接来获取,但是要小心,文本必须完全匹配才可以,所以这并不是一个很好的匹配方式。而且你在用 xpath 的时候还需要注意的是,如果有多个元素匹配了 xpath,它只会返回第一个匹配的元素。如果没有找到,那么会抛出 NoSuchElementException 的异常。
获取元素后,您可能想要在文本字段中输入一些文本

element.send_keys("some text")

您可以通过使用“keys”类来模拟对箭头键的点击

element.send_keys(" and some", Keys.ARROW_DOWN)

你可以对任何获取到到元素使用 send_keys 方法,就像你在 GMail 里面点击发送键一样。不过这样会导致的结果就是输入的文本不会自动清除。所以输入的文本都会在原来的基础上继续输入。你可以用下面的方法来清除输入文本的内容。

element.clear()

3.5 提交表单

我们已经看到了如何在文本区域或文本字段中输入文本,但其他元素又如何呢?您可以“切换”下拉菜单的状态,您可以使用“setSelected”来设置类似选项标签的选项。

element = driver.find_element_by_xpath("//select[@name='name']")
all_options = element.find_elements_by_tag_name("option")
for option in all_options:
    print("Value is: %s" % option.get_attribute("value"))
    option.click()

这将找到页面上的第一个“select”元素,并依次循环每个选项,打印出它们的值,然后依次选择它们。
正如您所看到的,这不是处理SELECT元素的最有效方法。WebDriver的支持类包括一个称为“Select”的类,它提供了与这些交互的有用的方法:

from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)

WebDriver还提供了取消选择所有选项的功能:

select = Select(driver.find_element_by_id('id'))
select.deselect_all()

假设在一个测试中,我们需要所有默认选择的选项的列表,选择class提供一个返回列表的属性方法:

select = Select(driver.find_element_by_xpath("xpath"))
all_selected_options = select.all_selected_options

获得所有可用的选项:

options = select.options

一旦填写完表单,您可能需要提交它。一种方法是找到“提交”按钮并点击它

# 假设按钮的id是‘submit’
driver.find_element_by_id("submit").click()

或者可以直接使用

element.submit()

3.6 元素拖拽

您可以使用拖放,或者将元素移动到另一个元素上:

# 要拖动元素
element = driver.find_element_by_name("source")
# 目标元素
target = driver.find_element_by_name("target")

from selenium.webdriver import ActionChains
action_chains = ActionChains(driver)
action_chains.drag_and_drop(element, target).perform()

3.7 窗口切换

WebDriver支持使用“切换窗口”方法在命名窗口之间移动。

driver.switch_to_window("windowName")

现在,所有对驱动程序的调用都将被解释为指向特定的窗口。但是你怎么知道窗口的名字呢?看看打开它的javascript或链接:

<a href="somewhere.html" target="windowName">Click here to open a new window</a>

或者,您可以将一个“window handle”传递给“switch_to_window()”方法。知道了这一点,就可以像这样迭代每一个打开的窗口

for handle in driver.window_handles:
    driver.switch_to_window(handle)

也可以通过索引来指定

driver.switch_to_frame("frameName.0.child")

3.8 弹窗

Selenium WebDriver内置了对弹出对话框的支持。当你触发了一个弹出窗口的动作之后,你可以用下面的提示来访问这个弹窗:

alert = driver.switch_to_alert()

这将返回当前打开的alert对象。有了这个对象,您现在可以接受、撤销、读取它的内容,甚至可以输入提示符。该接口在alter、确认、提示等方面都能很好地工作。

3.9 历史记录

在浏览器的历史记录中,后退和前进:

driver.forward()
driver.back()

3.10 Cookies

为页面添加cookie

# 打开正确的域名
driver.get("http://www.example.com")

# 设置域名
cookie = {‘name’ : ‘foo’, ‘value’ : ‘bar’}
driver.add_cookie(cookie)

# 然后输出当前URL的所有可用cookie
driver.get_cookies()

3.11 查找数组元素

在页面中找到元素的方法有很多。你可以用最适合你的例子。Selenium提供了以下方法来定位页面中的元素:

* find_element_by_id
* find_element_by_name
* find_element_by_xpath
* find_element_by_link_text
* find_element_by_partial_link_text
* find_element_by_tag_name
* find_element_by_class_name
* find_element_by_css_selector

要找到多个元素(这些方法将返回一个列表):

* find_elements_by_name
* find_elements_by_xpath
* find_elements_by_link_text
* find_elements_by_partial_link_text
* find_elements_by_tag_name
* find_elements_by_class_name
* find_elements_by_css_selector

除了上面给出的公共方法之外,还有两种私有方法可能对页面对象中的定位器很有用。

from selenium.webdriver.common.by import By

driver.find_element(By.XPATH, '//button[text()="Some text"]')
driver.find_elements(By.XPATH, '//button')

这些是类可以使用的属性:

ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"

更多方法和例子可以查看官网

3.12

Selenium Webdriver提供了两种类型的等待——隐式和显式。显式等待使WebDriver等待某个条件发生,然后继续执行。隐式等待使WebDriver在尝试查找元素时,在一定时间内对DOM进行轮询。
显示等待
显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,那么便会抛出异常了。

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.Firefox()
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秒,除非它在10秒内找到返回的元素。在默认情况下,webdriver等待的时间是500毫秒,直到它成功返回。更多内置的条件
隐式的等待
隐式等待告诉WebDriver在尝试查找任何元素(或元素)不立即可用时,在一定的时间内对DOM进行轮询。默认设置为0。一旦设置好了,就为WebDriver对象的生命设置了隐式等待。

from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

以上就是 Selenium 的基本用法。内容有些多,可以以后实际使用后再翻回来看看。