Selenium
简介
Selenium 是最广泛使用的开源 Web UI(用户界面)自动化测试套件之一。Selenium 支持的语言包括C#,Java,Perl,PHP,Python 和 Ruby。目前,Selenium Web 驱动程序最受 Python 和 C#欢迎。Selenium测试脚本可以使用任何支持的编程语言进行编码,并且可以直接在大多数现代 Web 浏览器中运行。在爬虫领域 selenium 同样是一把利器,能够解决大部分的网页的反爬问题。主要用于自动化测试、爬虫模拟人操作浏览器。
安装
安装Python的执行库
pip install selenium -i https://pypi.douban.com/simple
同样还需要根据浏览器安装WebDriver
FireFOx:github.com/mozilla/gec…
Chrome:chromedriver.storage.googleapis.com/index.html
IE:selenium-release.storage.googleapis.com/index.html
Edge:developer.microsoft.com/en-us/micro…
PhantomJS:phantomjs.org/
Opera:github.com/operasoftwa…
启动浏览器
正常启动浏览器
from selenium import webdriver
browser = webdriver.Chrome()
启动webdriver的Debug模式,接管浏览器
首先需要在Chrome的启动方式中添加 --remote-debugging-port=9623 --user-data-dir= # (port为调试Debug的端口号,需要和代码当中一致)
在代码当中添加Debug模式
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9623")
browser = webdriver.Chrome(options=chrome_options)
WebDriver中Debug的使用场景:
1.在对网页元素定位时可以使用;
2.在某些操作需要人工干预时,接合开发使用;
3.在对网页项目开发时,分块开发时可以使用。
元素定位
使用Selenium首先需要定位到网页页面当中的标签所在位置,才能对页面进行操作。
| 查找方式 | 返回值类型 |
|---|---|
find_eletment | 返回一个标签元素值,返回值为网页的dom对象。 |
find_eletments | 返回一个列表,列表当中的值由复合查找条件筛选出来的元素标签元素值。 |
对于Selenium来说,主要有8种定位方式:ID定位、name定位、class定位、tag定位、xpath定位、css定位、link定位、partial_link 定位。
| 定位方式 | 描述 | 代码执行方式 |
|---|---|---|
ID定位 | 通过网页标签当中的唯一标识提取定位网页元素。 | browser.find_element(By.ID,'标签ID') |
name定位 | 通过标签name寻找网页元素,在页面当中可能不唯一,找到多个(用find_element返回找到的第一个,用find_elements返回一个元素标签的列表)。 | browser.find_element(By.NAME, '标签名字') browser.find_elements(By.NAME,'标签名字') |
class定位 | 通过标签的class寻找网页元素,在页面中可能存在多个相同class值的元素。 | browser.find_element(By.CLASS_NAME,'标签class值) browser.find_elements(By.CLASS_NAME,'标签class值') |
tag定位 | 通过标签的TAG标签,来寻找网页当中复合查找条件的标签。 | browser.find_element(By.TAG_NAME, '标签') browser.find_elements(By.TAG_NAME, '标签') |
xpath定位 | 通过Xpath表达式来查找页面当中的元素。 | browser.find_element(By.XPATH, 'XPATH表达式') |
css定位 | 使用选择器来为页面元素绑定属性,它可以较为灵活的选择控件的任意属性,一般定位速度比Xpath要快,但使用起来略有难度。 | browser.find_element(By.CSS_SELECTOR, 'CSS表达式') |
link定位 | link专门用来定位文本链接 | browser.find_element_by_link_text("加入!每日一练") |
partial_link定位 | 定位文本当中的部分,然后定位文本所在的标签(link的子集) | browser.find_element_by_partial_link_text("加入") |
CSS选择器常用语法:
| 方法 | 例子 | 描述 |
|---|---|---|
.class | .toolbar-search-container | 选择 class = 'toolbar-search-container' 的所有元素 |
#id | #toolbar-search-input | 选择 id = 'toolbar-search-input' 的元素 |
* | * | 选择所有元素 |
element | input | 选择所有 <input\> 元素 |
element>element | div>input | 选择父元素为 <div\> 的所有 <input\> 元素 |
element+element | div+input | 选择同一级中在 <div\> 之后的所有 <input\> 元素 |
[attribute=value] | type='text' | 选择 type = 'text' 的所有元素 |
浏览器的控制
修改浏览器窗口大小
通过webdriver的set_window_size()方法修改浏览器窗口的大小。
browser.set_window_size(宽,高)
通过方法设置浏览器页面为maximsize_window()全屏显示
browser.maximize_window()
浏览器前进/后退/刷新
浏览器的前进
browser.forward() (需要先有一步后退操作才有前进)
浏览器的后退
browser.back()
浏览器的刷新
browser.refresh()
浏览器的窗口切换
在使用浏览器时,若有页面切换的需要先对页面进行缓存(踩过的坑)
通过页面的标题切换。
获取浏览器的标题
borwser.title
获取浏览器页面的句柄(返回的为每一个页面组成的一个列表)
browser.window_handles
根据网页的标题组成一个字典,后续切换网页页面可以根据字典取值
webTags = {}
for item in browser.window_handles:
browser.switch_to.window(item)
webTags[browser.title] = browser.current_window_handle
通过网页的标题切换网页
browser.switch_to.window(webTags['首页'])
浏览器的常见操作
在调用常用方法时,首先需要找到网页的元素,在元素上调用方法。
| 方法 | 描述 |
|---|---|
send_keys() | 模拟输入指定内容 |
click() | 模拟点击元素 |
is_displayed() | 判断元素是否可见 |
get_attribute() | 获取标签当中的属性值 |
size | 返回元素的尺寸 |
text | 返回元素文本 |
浏览器当中的鼠标控制
在webdriver 中,鼠标操作都封装在ActionChains类中。
| 方法 | 描述 |
|---|---|
click() | 单击左键 |
context_click() | 单击右键 |
double_click() | 双击 |
drag_and_drop() | 拖动 |
move_to_element() | 鼠标悬停 |
perform() | 执行所有ActionChains中存储的动作 |
单击右键
鼠标右击的操作与左击有很大不同,需要使用 ActionChains 。
# 定位搜索按钮
button = driver.find_element(By.XPATH, 'XXX')
# 右键搜索按钮
ActionChains(driver).context_click(button).perform()
双击
# 定位搜索按钮
button = driver.find_element(By.XPATH, XXX)
# 执行双击动作
ActionChains(driver).double_click(button).perform()
拖拽
模拟拖拽需要两个参数,一个为需要拖动的元素,另一个为拖拽至的目标元素
source:鼠标拖动的元素
target`:鼠标拖至并释放的目标元素
# 定位要拖动的元素
source = driver.find_element(By.XPATH, 'xxx')
# 定位目标元素
target = driver.find_element(By.XPATH, 'xxx')
# 执行拖动动作
ActionChains(driver).drag_and_drop(source, target).perform()
鼠标悬停
# 定位收藏栏
collect = driver.find_element(By.XPATH, 'XXX')
# 悬停至收藏标签处
ActionChains(driver).move_to_element(collect).perform()
键盘控制
通过send_keys + keys 实线输出键盘上的组合键。如“Ctrl+A”、“Ctrl+V”、“Ctrl+C”等。
from selenium.webdriver.common.keys import Keys
# 模拟回车键进行跳转(输入内容后)
driver.find_element(By.XPATH, 'xxx').send_keys(Keys.ENTER)
# 使用 Backspace 来删除一个字符
driver.find_element(By.XPATH, 'xxx').send_keys(Keys.BACK_SPACE)
# Ctrl + A 全选输入框中内容
driver.find_element(By.XPATH, 'xxx').send_keys(Keys.CONTROL, 'a')
# Ctrl + C 复制输入框中内容
driver.find_element(By.XPATH, 'xxx').send_keys(Keys.CONTROL, 'c')
# Ctrl + V 粘贴输入框中内容
driver.find_element(By.XPATH, 'xxx').send_keys(Keys.CONTROL, 'v')
其他常见键盘操作
| 操作 | 描述 |
|---|---|
Keys.F1 | F1键 |
Keys.SPACE | 空格 |
Keys.TAB | TAB键 |
Keys.ESCAPE | ESC键 |
Keys.ALT | ALT键 |
Keys.SHIFT | Shift键 |
Keys.ARROW_DOWN | 向下按键 |
Keys.ARROW_LEFT | 向左按键 |
Keys.ARROW_RIGHT | 向右按键 |
Keys.ARROW_UP | 向上按键 |
元素等待
因为某些网页当中需要等待某个元素加载出来,才能够找到后续页面当中的元素。为这种情况Selenium当中可以通过方法来等待网页加载。在WebDriver当中的等待方式分为显示等待和隐式等待。
显示等待
显示等待:设置一个最长的等待时间,设置检测周期,每个周期去检测一次网页当中的元素是否已加载出现或消失。超出了最大等待时间,则会抛出异常(TimeoutException)。显示等待需要使用WebDriverWait配合其对象当中的until和until_not使用。
WebDriverWait(browser, timeout, poll_frequency=0.5, ignored_exceptions=None)
参数解释:
browser:浏览器驱动
timeout:超出时间/最大等待时间,单位为秒
poll_frequency:检测的间隔周期,默认为0.5秒
ignored_exceptions:指定忽略的异常,如果在调用 until 或 until_not 的过程中抛出指定忽略的异常,则不中断代码,默认忽略的只有 NoSuchElementException 。
在until和until_not 当中 有两个参数
until(method, message=’ ‘)
until_not(method, message=’ ')
参数解释:
method:指定预期条件的判断方法,在等待期间,每隔一段时间调用该方法,判断元素是否存在或不存在,直到元素出现。
message:如果超时,抛出 TimeoutException ,并显示 message 中的内容。
method当中的预期判断条件是有expected_conditions 提供的,例如:
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 通过xpath定位到某一个元素,等待这个元素在10秒之内是否加载出来,加载出来则继续向下执行代码,未出现则抛出超时的异常
WebDriverWait(browser, 10, 1).until(EC.presence_of_element_located((By.XPATH, 'XXX')))
expected_conditions 当中有一些常用的判断方法:
| 方法 | 描述 |
|---|---|
title_is(‘百度一下’) | 判断当前页面的 title 是否等于预期 |
title_contains(‘百度’) | 判断当前页面的 title 是否包含预期字符串 |
presence_of_element_located(locator) | 判断元素是否被加到了 dom 树里,并不代表该元素一定可见 |
visibility_of_element_located(locator) | 判断元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0 |
visibility_of(element) | 跟上一个方法作用相同,但传入参数为 element |
text_to_be_present_in_element(locator , ‘百度’) | 判断元素中的 text 是否包含了预期的字符串 |
text_to_be_present_in_element_value(locator , ‘某值’) | 判断元素中的 value 属性是否包含了预期的字符串 |
frame_to_be_available_and_switch_to_it(locator) | 判断该 frame 是否可以 switch 进去,True 则 switch 进去,反之 False |
invisibility_of_element_located(locator) | 判断元素中是否不存在于 dom 树或不可见 |
element_to_be_clickable(locator) | 判断元素中是否可见并且是可点击的 |
staleness_of(element) | 等待元素从 dom 树中移除 |
element_to_be_selected(element) | 判断元素是否被选中,一般用在下拉列表 |
element_selection_state_to_be(element, True) | 判断元素的选中状态是否符合预期,参数 element,第二个参数为 True/False |
element_located_selection_state_to_be(locator, True) | 跟上一个方法作用相同,但传入参数为 locator |
alert_is_present() | 判断页面上是否存在 alert |
隐式等待
隐式等待也是指定一个最长的等待时间,如果超过了这个等待时间,元素还没有加载出来,就会抛出NoSuchElementException 异常。
特点:隐式等到是全局性的,在运行过程中,如果元素可以定位到,它不会影响代码运行,但如果定位不到元素,则会以轮询的方式不断地访问元素直到元素被找到,若超出最长的等待时间,就会抛出异常。
使用implicitly_wait()来实现隐式等待
例如
browser.implicitly_wait(5)
browser.find_element(By.XPATH, 'XXX')
在设置好了隐式等待时间后,在下一条查找元素的代码当中就会触发,若在5S内未查询到元素,则会抛出异常。
表单切换
在有些网页当中,会有frame/iframe的表单嵌套,对于这种嵌套的表单,Selenium不能直接定位到,需要先切换到表单当中,需要使用到switch_to.frame()。
switch_to.frame()方法默认可以使用id或者name属性直接定位到,但如果iframe没有id和name属性,需要使用到XPATH定位到表单,再切换到表单当中。