Selenium 是一个 Web 的自动化测试工具,最初是为网站自动化测试而开发的,Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器。因为 Selenium 可以控制浏览器发送请求,并获取网页数据,因此可以应用于爬虫领域。Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。Selenium Python bindings 提供了一个简单的 API,让你使用 Python 和 Selenium WebDriver 来编写功能/校验测试。 以下为我在学习和实战练习过程中所做的笔记,可供参考。
一、Selenium 概述
Selenium 支持多平台、多浏览器、多语言去实现自动化测试,是一个开源和可移植的 Web 测试框架,支持并行测试执行,从而减少了时间并提高了测试效率。利用它,我们可以编写相关的自动化程序,让程序完全像人一样在浏览器里面操作 Web 界面,比如模拟鼠标点击、模拟键盘输入等等。不但能够操作 Web 界面,还能从 Web 中获取信息,并且相对来说,使用 Selenium 来获取信息更加简单,它的基本原理是我们编写自动化程序之后利用浏览器驱动直接对浏览器进行操作,只要我们用户能在浏览器上获得的信息使用 Selenium 都可以获得。
安装 Selenium:
1 | pip install selenium==3.3.1 4 |
二、浏览器驱动
Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。浏览器驱动用于使用 selenium 操控本地浏览器执行自动化操作。根据本地电脑 Chrome 的版本需要下载对应的 ChromeDriver,否则无法操控 Chrome 浏览器使用 Selenium 启动。其他浏览器也可以下载对应的驱动包,例如:新版 Edge 驱动,Firefox 驱动。
驱动包不需要安装,只需要解压到 /usr/local/bin
目录,后续会在代码中调用:
1 | mv ~/Downloads/msedgedriver /usr/local/bin |
由于 Safari 浏览器本身已经集成了 safaridriver
,只要勾选 Safari - 开发 - 允许远程自动化并在终端输入开启即可:
1 | safaridriver --enable |
三、控制浏览器自动网页
控制 Safari 浏览器打开网页:
1 | # 导入 webdriver |
当然也可以调用 Chrome 驱动,控制 Chrome 浏览器打开网页:
1 | # 导入 webdriver |
四、常用操作
元素定位
获取单个元素:
1 | driver.find_element(By.ID,"inputOriginal") |
- 如果找不到相应的元素会报错:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: xx
。
获取多个元素:
1 | driver.find_elements(By.ID,"inputOriginal") |
访问有道翻译网站,输入单词,并获取翻译后的内容:
1 | from selenium import webdriver |
内容获取
size
:返回元素大小;text
:获取元素的文本(<div>hello</div>
);title
:获取页面title
;current_url
:获取当前页面URL
;get_attribute()
:获取属性值(<a href="xxxx">百度</a>
);is_display()
:判断元素是否可见;is_enabled()
:判断元素是否可用。
1 | driver = webdriver.Chrome("./chromedriver.exe") |
窗口操作
maximize_window()
:模拟浏览器最大化按钮;set_window_size(100,100)
:设置浏览器大小(宽、高像素点);set_window_position(300,200)
:设置浏览器位置;back()
:模拟浏览器后退按钮;forward()
:模拟浏览器前进按钮;refresh()
:模拟浏览器 F5 刷新;close()
:模拟浏览器关闭按钮(关闭单个窗口);quit()
:关闭所有 WebDriver 启动的窗口。
五、元素等待
例如对于程序翻页获取每页元素:
1 | from selenium import webdriver |
现在的网页越来越多采用了 Ajax
技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个 dom
元素还没出来,但是你的代码直接使用了这个 WebElement
,那么就会抛出 NullPointer
的异常。
为了避免这种元素定位困难而且会提高产生 ElementNotVisibleException
的概率。所以 Selenium
提供了两种等待方式,一种是隐式等待,一种是显式等待。隐式等待是等待特定的时间,显式等待是指定某一条件直到这个条件成立时继续执行。
显式等待
显式等待使用 WebDriverWait
完成,指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,那么便会抛出异常了:
1 | WebDriverWait(driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None) |
driver
:所创建的浏览器 driver;timeout
:最长时间长度(默认单位:秒);poll_frequency
:间隔检测时长(每)默认 0.5 秒;ignored_exceptions
:方法调用中忽略的异常,默认只抛出找不到元素的异常。
显式等待基础格式:webDriverWait
+ until
+(判断条件)。
until
:直到调用的方法返回值为 True:1
2
3until(method, message=’’)
# method:expected_conditions 库中定义的方法
# message:自定义报错信息判断条件:
- 判断当前页面标题是否为
title
:title_is(title)
- 判断当前页面标题是否包含
title
:title_contains(title)
- 判断此定位的元素是否存在:
presence_of_element_located(locator)
- 判断页面网址中是否包含
url
:url_contains(url)
- 判断此定位的元素是否可见:
visibility_of_element_located(locator)
- 判断此元素是否可见:
visibility_of(element)
- 判断此定位的一组元素是否至少存在一个:
presence_of_all_elements_located(locator)
- 判断此定位的一组元素至少有一个可见:
visibility_of_any_elements_located(locator)
- 判断此定位的一组元素全部可见:
visibility_of_all_elements_located(locator)
- 判断此定位中是否包含
text_
的内容:text_to_be_present_in_element(locator, text_)
_ - 判断此定位中的
value
属性中是否包含text_
的内容:text_to_be_present_in_element_value(locator, text_)
- 判断定位的元素是否为
frame
,并直接切换到这个frame
中:frame_to_be_available_and_switch_to_it(locator)
- 判断定位的元素是否不可见:
invisibility_of_element_located(locator)
- 判断此元素是否不可见:
invisibility_of_element(element)
- 判断所定位的元素是否可见且可点击:
element_to_be_clickable(locator)
- 判断此元素是否不可用:
staleness_of(element)
- 判断该元素是否被选中:
element_to_be_selected(element)
- 判断定位的元素是否被选中:
element_located_to_be_selected(locator)
element
:所获得的元素locator
:元素的定位信息text_
:期望的文本信息
- 判断当前页面标题是否为
示例程序:
1 | from selenium.webdriver.support.ui import WebDriverWait |
隐式等待
隐式等待比较简单,就是设置全局元素查找的超时时间:
1 | implicitly_wait(time_to_wait) |
设置的时间单位为秒,例如 implicitly_wait(30)
,意思是超过 30 秒没有定位到一个元素,程序就会报错抛出异常,期间会一直轮询查找定位元素。
六、页面操作和动作链
鼠标及键盘操作
鼠标操作:
context_click()
:此方法模拟鼠标右键点击效果;double_click()
:此方法模拟双标双击效果;drag_and_drop()
:此方法模拟双标拖动效果;move_to_element()
:此方法模拟鼠标悬停效果;perform()
:此方法用来触发执行以上的鼠标方法。
1 | #导入动作链 |
键盘操作:
send_keys(Keys.BACK_SPACE)
:删除键(BackSpace) ;send_keys(Keys.SPACE)
:空格键(Space);send_keys(Keys.TAB)
:制表键(Tab);send_keys(Keys.ESCAPE)
:回退键(Esc);send_keys(Keys.ENTER)
:回车键(Enter) ;send_keys(Keys.CONTROL,'a')
:全选(Ctrl+A);send_keys(Keys.CONTROL,'c')
:复制(Ctrl+C);driver.forward()
:前进;driver.back()
:后退。
1 | from selenium.webdriver.common.keys import Keys |
滚动条操作
在 HTML 页面中,由于前端技术框架的原因,页面元素为动态显示,元素根据滚动条的下拉而被加载:
1 | #1. 设置 JavaScritp 脚本控制滚动条(左边距:0;上边距:1000) |
窗口截图
自动化脚本是由程序去执行的,因此有时候打印的错误信息并不是十分明确。如果在执行出错的时候对当前窗口截图保存,那么通过图片就可以非常直观地看到出错的原因:
1 | # 截取当前窗口 |
七、存储数据
将数据写入 CSV 文件:
1 | # 读写CSV文件 |
使用 pymysql 将数据写入至 MySQL:
1 | pip3 install pymysql |
1 | import pymysql |
八、下载页面上的图片
可以借助 requests
库来完成图片的保存,通过 selenium
获取图片的地址,再通过 requests
来将图片保存到本地。
1 | pip3 install requests |
1 | from selenium import webdriver |