文章目录
环境配置
- 安装selenium
pip install selenium - 安装webdriver
webdriver需要和对应的浏览器版本对应,将webdriver.exe文件复制到python的安装目录下即可。
操作浏览器
启动浏览器
普通启动
from selenium import webdriver
bro = webdriver.Chrome()
bro.get('http://www.baidu.com/')
Headless启动
Headless Chrome是Chrome浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有Chrome支持的特性。相比现代浏览器,Headless Chrome更加方便测试web应用,获得网站的截图,做爬虫抓取信息等。相比于较早的PhantomJS、slimerJS等,其更贴近浏览器环境。
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
# 使用headless无界面浏览器模式
chrome_options.add_argument('--headless') # 增加无界面选项
chrome_options.add_argument('--disable-gpu') # 如果不加这个选项,有时定位会出现问题
# 启动浏览器,获取源代码
browser = webdriver.Chrome(chrome_options=chrome_options)
mainUrl = 'https://www.baidu.com/'
browser.get(mainUrl)
print(f'browser text={browser.page_source}')
browser.quit()
加载配置启动浏览器
用Chrome地址栏输入chrome://version/
,查看自己的“个人资料路径”,然后在浏览器启动时,调用这个配置文件。
from selenium import webdriver
option = webdriver.ChromeOptions()
option.add_argument(r'--user-data-dir=C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default')
driver = webdriver.Chrome(chrome_options=option)
元素定位
- webdriver提供的对象定位方法:
id定位:find_element_by_id()
name定位:find_element_by_name()
class定位:find_element_by_class_name()
link定位:find_element_by_link_text()
partial link定位:find_element_by_partial_link_text()
tag定位:find_element_by_tag_name()
xpath定位:find_element_by_xpath()
css定位:find_element_by_css_selector()
import time
from selenium import webdriver
bro = webdriver.Chrome()
bro.get('http://www.baidu.com')
# 百度输入框的定位方式
# 通过id定位
bro.find_element_by_id('kw').send_keys('selenium')
# 通过name方式定位
bro.find_element_by_name('wd').send_keys('selenium')
# 通过class定位
bro.find_element_by_class_name('s_ipt').send_keys('selenium')
# 通过css定位
bro.find_element_by_css_selector('#kw').send_keys('selenium')
# 通过xpath定位
bro.find_element_by_xpath('//input[@id=\'kw\']').send_keys('selenium')
# 点击“百度一下”
bro.find_element_by_id('su').click()
# 获取页面快照
time.sleep(3)
bro.save_screenshot('selenium.png')
time.sleep(3)
# close()关闭当前页面,如果只有一个页面,会关闭浏览器;quit关闭浏览器
bro.quit()
- 页面元素定位不到问题解决方法
- class含有空格时解决方法
在实际进行元素定位时,经常发现class name是有多个class组合的复合类,中间以空格隔开,如果直接进行定位会出现报错,可以通过以下方式处理:
1)选择class中属性唯一的那一个
2)若空格隔开的class不唯一,可以通过索引进行定位
3)通过css方法直接定位(空格以’.'代替)
from selenium import webdriver
bro = webdriver.Chrome()
bro.get('http://mail.126.com/')
bro.implicitly_wait(10)
# 切换iframe(iframe是内嵌的网页元素,也可以说是内嵌的框架)
# 126.com不能用selenium定位是因为iframe框架包装了,并且id是动态变化的,所以使用xpath定位iframe
bro.switch_to.frame(bro.find_element_by_xpath('//iframe[@scrolling="no"]'))
# bro.switch_to.frame(bro.find_elements_by_tag_name('iframe')[0]) # 或者使用tag定位
# 方法1)
bro.find_element_by_class_name('dlemail').send_keys('123@126.com')
bro.find_element_by_class_name('dlpwd').send_keys('123456')
# 方法2)定位一组取下标定位
bro.find_elements_by_class_name("j-inputtext")[0].send_keys('123@126.com')
bro.find_elements_by_class_name("j-inputtext")[1].send_keys('123456')
# 方法3)css定位
bro.find_element_by_css_selector('.j-inputtext.dlemail').send_keys('123@126.com')
bro.find_element_by_css_selector('.j-inputtext.dlpwd').send_keys('123456')
# 方法4)直接包含空格的CSS属性定位大法
bro.find_element_by_css_selector("[class='j-inputtext dlemail j-nameforslide']").send_keys('123@126.com')
三种等待方式
强制等待
导入‘time’模块,强制等待sleep(x),这种等待方式太死板,严重影响程序的执行速度。
隐式等待
通过添加implicitly_wait(x)方法就可以方便的实现智能等待,隐式等待设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截止然后执行下一步。隐式等待对driver的整个周期都起作用,所以只要设置一次即可,不需要像sleep那样处处使用实现等待。
隐式等待存在一个弊端,那就是程序会一直等待整个页面加载完成,也就是一般情况下看到浏览器标签栏的那个小圈不再转,才会执行下一步,但有时页面想要的元素早就加载完了,但是因为个别js之类的特别慢,仍要等到页面全部完成才执行下一步,这时selenium提供了另一种等待方式——显式等待wait。
显式等待
显式等待WebDriverWait,配合该类的until()和until_not()方法,就能够根据判断条件而进行灵活的等待了。当隐式等待和显式等待都存在时,超时时间取二者中较大的。
调用方法: WebDriverWait(driver,超时时长,调用频率,忽略异常).until(可执行方法,超时返回的信息)
until在等待时,每隔一段时间(即调用频率,默认0.5s),调用可执行方法,直到返回值为True则继续执行;until_not与until相反。
可执行方法必须是可调用方法,不能传入WebElement对象,否则会抛出异常。这里可以使用expected_conditions模块中的方法,也可以使用WebElement的is_displayed()、is_enabled()、is_selected()方法等。
Expected_Conditions一般直接在断言中使用,或者与WebDriver配合使用,动态等待页面上元素出现或者消失。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('http://www.baidu.com')
# 判断title,返回布尔值
WebDriverWait(driver, 10).until(EC.title_is(u'百度一下,你就知道'))
WebDriverWait(driver, 10).until(EC.title_contains(u'百度一下'))
# 判断某个元素是否被加到dom树中,并不代表该元素一定可见,如果定位到就返回WebElement
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'kw')))
# 判断某个元素是否被添加到dom树中并且可见,可见代表元素可显示且高宽都大于0
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, 'su')))
# 判断某个元素是否可见,如果可见则返回这个元素
WebDriverWait(driver, 10).until(EC.visibility_of(driver.find_element(by=By.ID,value='kw')))
# 判断是否至少有一个元素存在于dom树中,如果定位到就返回列表
WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.mnav')))
# 判断指定的元素中是否包含了预期的字符串,返回布尔值
WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element((By.XPATH, "//*[@id='u1']/span"), u'设置'))
# 判断指定元素的属性值中是否包含了预期的字符串,返回布尔值
WebDriverWait(driver,10).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR,'#su'),u'百度一下'))
# 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False
# WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it((By.ID,'kw')),'该页面无frame')
# 判断某个元素是否存在与dom或不可见,如果可见返回False,不可见返回True
WebDriverWait(driver, 10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR, '#swfEveryCookieWrap')))
# 判断某个元素是否可见并且是enable的,代表可点击
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//*[@id='u1']/span"))).click()
# 判断某个元素是否被选中了, 一般用在下拉列表中
# WebDriverWait(driver, 10).until(EC.element_to_be_selected(driver.find_element(By.XPATH,"//*[@id='nr']/option[1]")))
# 判断页面上是否存在alert,如果有就切换到alert并返回alert的内容
# instance = WebDriverWait(driver,10).until(EC.alert_is_present())
# print(instance.text)
# instance.accept()
driver.close()
浏览器显示
- 浏览器最大化、最小化显示,设置窗口大小
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('http://www.baidu.com')
# 窗口最大化
driver.maximize_window()
time.sleep(3)
# 窗口最小化
driver.minimize_window()
time.sleep(3)
# 设置窗口大小
driver.set_window_size(480,800)
time.sleep(3)
driver.close()
- 浏览器前进后退
driver.forward()
driver.back()
操作对象
一般来说,webdriver中比较常用的操作对象的方法有下面几个:
- click 点击对象
- send_keys 在对象上模拟按键输入
- clear 清除对象的内容,如果可以的话
- submit 提交对象的内容,如果可以的话
- text 用于获取元素的文本信息
- select处理下拉框
<select id="status" class="form-control valid" onchange="" name="status">
<option value=""></option>
<option value="0">未审核</option>
<option value="1">初审通过</option>
<option value="2">复审通过</option>
<option value="3">审核不通过</option>
</select>
# 导入 Select 类
from selenium.webdriver.support.ui import Select
# 找到 name 的选项卡
select = Select(driver.find_element_by_name('status'))
select.select_by_index(1)
select.select_by_value("0")
select.select_by_visible_text(u"未审核")
三种选择下拉框的方式:
index索引从0开始
value是option标签的一个属性值,并不是显示在下拉框中的值
visible_text是在option标签文本的值,显示在下拉框的值
全部取消选择:select.deselect_all()
键盘事件
要想调用键盘按键操作需要引入keys包:from selenium.webdriver.common.keys import Keys
通过send_keys调用按键:
send_keys(Keys.TAB)
,send_keys(Keys.ENTER)
,send_keys(Keys.CONTROL,'a')
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
bro = webdriver.Chrome()
bro.get('http://mail.126.com/')
bro.implicitly_wait(10)
bro.switch_to.frame(bro.find_element_by_xpath('//iframe[@scrolling="no"]'))
# 全屏显示
bro.maximize_window()
bro.find_element_by_class_name('dlemail').clear()
bro.find_element_by_class_name('dlemail').send_keys('123')
# tab的定位相当于清楚了密码框的默认提示信息,等同于上面的clear()
bro.find_element_by_class_name('dlpwd').send_keys(Keys.TAB)
bro.find_element_by_class_name('dlpwd').send_keys('123456')
# 通过定位密码框,回车代替登录按钮
# bro.find_element_by_class_name('dlpwd').send_keys(Keys.ENTER)
# 或者直接定位登录按钮,click点击或者用Keys.ENTER代替
bro.find_element_by_id('dologin').click()
time.sleep(3)
bro.quit()
鼠标事件
鼠标事件一般包括鼠标左右键、双击、拖动、移动鼠标到某个元素上等。
引入ActionChains类:from selenium.webdriver.common.action_chains import ActionChains
常用方法:
perform() 执行所有ActionsChains中存储的行为
context_click() 右击
double_blick() 双击
drag_and_drop() 拖动
move_to_element 鼠标悬停
click_and_hold 点击并保持,可以用于滑块验证
- 鼠标双击示例
# 定位要双击的元素
dc = driver.find_element_by_xpath('xxx')
# 对定位到的元素执行鼠标双击操作
ActionChains(driver).double_click(dc).preform()
- 鼠标拖放示例
# 定位元素的原位置
element = driver.find_element_by_name('xxx')
# 定位元素要移动到的目标位置
target = driver.find_element_by_name('xxxx')
# 执行元素的移动操作
ActionChains(driver).drag_and_drop(element,target).perform()