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
:https://github.com/mozilla/geckodriver/releases
Chrome
:https://chromedriver.storage.googleapis.com/index.html
IE
:http://selenium-release.storage.googleapis.com/index.html
Edge
:https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
PhantomJS
:https://phantomjs.org/
Opera
:https://github.com/operasoftware/operachromiumdriver/releases
正常启动浏览器
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)
使用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 |
选择所有 元素 |
element>element |
div>input |
选择父元素为
|
element+element |
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
定位到表单,再切换到表单当中。