文章目录
前言
在当今快速发展的互联网时代,自动化测试和网络爬虫技术已经成为开发者和测试工程师不可或缺的技能。Python 作为一门简洁、高效的编程语言,凭借其丰富的生态库和易用性,成为了自动化测试和爬虫开发的首选工具之一。而 Selenium,作为一款强大的浏览器自动化工具,不仅能够模拟用户操作,还能处理动态加载的网页内容,为开发者提供了极大的便利。
无论是进行 Web 应用的自动化测试,还是从复杂的网站中抓取数据,Selenium 都能胜任。它支持多种浏览器(如 Chrome、Firefox、Edge 等),并提供了灵活的 API,使得开发者可以轻松实现页面元素的定位、交互和验证。此外,结合 Python 的简洁语法,Selenium 让自动化任务的编写变得更加高效和直观。
本文将带你深入探索 Python 与 Selenium 的结合使用,从基础的环境搭建到高级的实战技巧,帮助你快速掌握这一强大工具。无论你是刚入门的新手,还是希望进一步提升技能的开发者,相信本文都能为你提供有价值的参考和启发。
一、初识selenium
- 自动化测试:快速完成重复性网页测试,提高效率
- 处理动态内容:完美支持JavaScript渲染的现代网页
- 跨浏览器支持:Chrome/Firefox/Edge等主流浏览器都兼容
- Python绝配:配合Requests/BeautifulSoup等库更强大
- 数据采集:解决普通爬虫无法处理的交互式网站
- 就业优势:Web自动化的必备技能,提升职场竞争力
简而言之:Selenium让网页自动化变得简单高效!
二、安装selenium
注意: 这里所有的举例都采用chrome浏览器。对于其他浏览器大致步骤一致。
2.1 查看chrome版本并禁止chrome自动更新
2.1.1 查看chrome版本
步骤: 设置
➡ ➡ 关于chrome
➡ ➡ 查看版本
2.1.2 禁止chrome更新自动更新
chrome自动更新会导致chrome驱动出现失效问题,因而需要禁止自动更新。
详细步骤:
Win+ R 打开输入services.msc
找到所有关于Google更新的相关程序,双击打开改为禁用即可
重新打开chrome 出现该效果即表示成功
2.2 安装对应版本的驱动程序
网址:
https://storage.googleapis.com/chrome-for-testing-public/你的版本号/win64/chromedriver-win64.zip
安装好对应的zip包之后,将其解压,复制一份chromedriver.exe程序
2.3安装selenium包
安装方式:通过之前安装(lxml,jsonpath等)操作来安装selenium,这里不再介绍。
三、selenium关于浏览器的使用
3.1 创建浏览器、设置、打开
注意:第一步先将复制的文件粘贴到对应的项目下面
测试:
# 用于操作浏览器
# from selenium import webdriver
# 用于设置谷歌浏览器
# from selenium.webdriver.chrome.options import Options
# 用于管理谷歌驱动
# from selenium.webdriver.chrome.service import Service
# (1)导包
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
# 创建浏览器对象
options = Options()
# 禁用沙盒模式(增加兼容性)--- 如果没有出现秒闪退问题,可以不填入
options.add_argument('--no-sandbox')
# 保持浏览器打开状态(默认执行完之后会自动关闭)
options.add_experimental_option("detach", True)
# 创建并启动浏览器
browse = webdriver.Chrome(service=Service('chromedriver.exe'),options=options)
3.2 打开/关闭网页及浏览器
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
import time
# 封装
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'),options=options)
return browser
browser = setup()
# 打开指定的网址
browser.get('https://www.baidu.com')
# 打印源码
print(browser.page_source)
time.sleep(3)
# 关闭当前的标签页
browser.close()
# 退出浏览器并释放驱动
browser.quit()
3.3 浏览器的最大/小化
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'),options=options)
return browser
browser = setup()
browser.get('https://www.baidu.com')
time.sleep(2)
# 浏览器最大化
browser.maximize_window()
time.sleep(2)
# 浏览器最小化
browser.minimize_window()
time.sleep(2)
# 重新返回最大化
browser.maximize_window()
time.sleep(2)
# 关闭浏览器
browser.quit()
3.4 浏览器打开位置、尺寸
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
def setup():
options = Options()
options.add_experimental_option('detach', True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
return browser
browser = setup()
# 单位均为像素
# 设置浏览器打开的位置(相对于左上角)
browser.set_window_position(100,100)
# 设置宽高px
browser.set_window_size(800,600)
# 关闭浏览器
browser.quit()
3.5 浏览器截图、网页刷新
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
import time
def setup():
options = Options()
options.add_experimental_option('detach', True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
return browser
browser = setup()
browser.get('https://www.baidu.com')
# 浏览器截图(尽量保存为png的格式)
browser.get_screenshot_as_file('baidu.png')
time.sleep(3)
# 刷新当前页
browser.refresh()
time.sleep(3)
# 关闭
browser.quit()
四、selenium关于元素的使用
4.1 元素定位
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
def setup():
options = Options()
options.add_experimental_option('detach', True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
return browser
browser = setup()
browser.get('https://www.baidu.com')
# 使用元素定位需要先导入对应的包
# from selenium.webdriver.common.by import By
# 例如根据ID查找百度首页的输入框
# <input id="kw" name="wd">
# find_element用来查找一个元素时使用
# 找不到时会直接报错
# 类似于根据id查找的,使用该方法即可,id是元素的唯一标识
input = browser.find_element(By.ID, 'kw')
# 获取class
print(input.get_attribute('class'))
# 获取标签名
print(input.tag_name)
# find_elements用来查找多个元素时使用
# 返回的是列表,找不到时不会报错会返回一个空列表
inputs = browser.find_elements(By.ID, 'kw')
print(inputs)
# 提示一下:也可以在浏览器的控制台输入
# document.getElementById('kw') 来先查找一下
# 关闭浏览器
browser.quit()
4.2 元素交互操作
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
def setup():
options = Options()
options.add_experimental_option('detach',True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'),options=options)
return browser
browser = setup()
# 获取指定的网址
browser.get('https://www.baidu.com')
input = browser.find_element(By.ID,'kw')
# 元素输入
input.send_keys('fasgfagasgasg')
time.sleep(3)
# 元素清空
input.clear()
time.sleep(2)
# 元素再次输入
input.send_keys('古诗文')
time.sleep(2)
# 获取搜索按钮
button = browser.find_element(By.ID,'su')
# 调用按钮的点击方法
button.click()
time.sleep(2)
# 关闭浏览器
browser.quit()
4.3 元素八种定位方式
4.3.1 元素定位-ID
通过id定位元素结果基本上就是我们想要的元素,准确性比较高。
input = browser.find_element(By.ID, 'kw')
4.3.2 元素定位-NAME
通过name属性来获取元素,也是比较精准的。
input = browser.find_element(By.ID, 'kw')
4.3.3 元素定位-CLASS_NAME
使用class属性来查找元素,容易出现多个元素,因而往往需要用切片处理方式
注意:如果class属性值中包含空格是无法正常获取的
element = browser.find_element(By.CLASS_NAME, 'bg s_btn')
4.3.4 元素定位-TAG_NAME
通过tag标签来查找元素,缺点是获取的元素比较多,需要切片找到需要的元素
element = browser.find_element(By.TAG_NAME, 'input')
4.3.5 元素定位-LINK_TEXT
只标识a标签中的链接文字,根据链接文字查找元素
element = browser.find_element(By.LINK_TEXT, '新闻')
4.3.6 元素定位-PARTIAL_LINK_TEXT
与LINK_TEXT区别是,虽然都是通过链接文本获取元素,但是PARTIAL_LINK_TEXT是在LINK_TEXT的基础上增加了模糊匹配
element = browser.find_element(By.PARTIAL_LINK_TEXT, '地')
4.3.7 元素定位-CSS_SELECTOR
# 通过id等位
element = browser.find_element(By.CSS_SELECTOR, '#kw')
# 通过class定位
element = browser.find_element(By.CSS_SELECTOR, '.s_ipt')
# 不加修饰符(输入标签名)
element = browser.find_element(By.CSS_SELECTOR, 'input')
# 通过任意类型定位
# 精确匹配
element = browser.find_element(By.CSS_SELECTOR, '[value="百度一下"]')
# 模糊匹配
element = browser.find_element(By.CSS_SELECTOR, '[value*="百度"]')
# 匹配开头
element = browser.find_element(By.CSS_SELECTOR, '[value^="百"]')
# 匹配结尾
element = browser.find_element(By.CSS_SELECTOR, '[value$="一下"]')
以上都属于理论定位法,可以直接通过谷歌浏览器复制唯一的selector来确定元素
element = browser.find_element(By.CSS_SELECTOR, '#su')
4.3.8 元素定位-XPATH
打开谷歌浏览器,直接复制该元素的XPATH即可,与上述操作基本一致
当一个无法获取到指定元素的时候,采用第二个完整xpath
写法
# Xpath
element = browser.find_element(By.XPATH, '//*[@id="su"]')
# 完成Xpath
element = browser.find_element(By.XPATH, '/html/body/div[1]/div[1]/div[5]/div/div/form/span[2]/input')
4.4 元素定位的隐式等待
隐式等待的作用是为了防止,当我们进入到一个页面时,该元素未第一时间加载出来,到底找不到元素而引发的报错。
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'),options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get(r'本地文件的绝对路径')
# time.sleep(4)
div = browser.find_element(By.CSS_SELECTOR,'#delayed-element')
print(div)
对应的html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>隐式等待测试页面</title>
</head>
<body>
<h1>隐式等待测试</h1>
<div id="immediate-element">这个元素是立即存在的</div>
<script>
// 5秒后动态添加一个元素
setTimeout(function() {
let newElement = document.createElement("div");
newElement.id = "delayed-element";
newElement.textContent = "这个元素是5秒后出现的";
document.body.appendChild(newElement);
}, 3000);
</script>
</body>
</html>
案例一: 获取表单元素并修改
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get(r'HTML文件绝对路径')
# 单选
browser.find_element(By.XPATH, '/html/body/form/div[1]/label[2]').click()
# 多选
browser.find_element(By.XPATH, '/html/body/form/div[2]/label[1]').click()
browser.find_element(By.XPATH, '/html/body/form/div[2]/label[2]').click()
browser.find_element(By.XPATH, '/html/body/form/div[2]/label[3]').click()
# 下拉
browser.find_element(By.XPATH, '/html/body/form/div[3]/select/option[2]').click()
# 日期框
browser.find_element(By.XPATH, '/html/body/form/div[4]/div/input').send_keys('20210912')
# 上传文件
browser.find_element(By.XPATH, '/html/body/form/div[5]/input').send_keys(r'D:\Python-learning\pythonProject\02-homework\12-test\baidu.png')
# 提交
browser.find_element(By.XPATH, '/html/body/form/button').click()
对应的HTML文件
test.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表单示例</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.form-group {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}
.form-group h3 {
margin-top: 0;
margin-bottom: 15px;
}
.rating {
display: flex;
flex-direction: column;
gap: 10px;
}
.rating-item {
display: flex;
align-items: center;
}
.rating-label {
width: 100px;
}
.date-input {
display: flex;
align-items: center;
}
.date-input input {
width: 120px;
margin-right: 10px;
}
.date-format {
color: #666;
}
</style>
</head>
<body>
<form action="ok.html" method="post">
<!-- 单选框 -->
<div class="form-group">
<h3>单选框</h3>
<label>
<input type="radio" name="language" value="Python" checked> Python
</label><br>
<label>
<input type="radio" name="language" value="Java"> Java
</label><br>
<label>
<input type="radio" name="language" value="C++"> C++
</label>
</div>
<!-- 多选框 -->
<div class="form-group">
<h3>多选框</h3>
<label>
<input type="checkbox" name="device" value="手机"> 手机
</label><br>
<label>
<input type="checkbox" name="device" value="电脑"> 电脑
</label><br>
<label>
<input type="checkbox" name="device" value="网页"> 网页
</label>
</div>
<!-- 下拉菜单 -->
<div class="form-group">
<h3>下拉</h3>
<select name="city">
<option value="北京" selected>北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
</select>
</div>
<!-- 日期选择 -->
<div class="form-group">
<h3>日期</h3>
<div class="date-input">
<input type="text" id="dateInput" placeholder="输入年月日如20240521" maxlength="8">
<span id="dateDisplay" class="date-format">年 / 月 / 日</span>
</div>
<input type="hidden" id="formattedDate" name="date">
</div>
<!-- 附件上传 -->
<div class="form-group">
<h3>附件</h3>
<input type="file" name="attachment">
</div>
<!-- 提交按钮 -->
<button type="submit">提交</button>
</form>
<script>
document.getElementById('dateInput').addEventListener('input', function(e) {
let value = e.target.value.replace(/\D/g, ''); // 移除非数字字符
if (value.length > 8) {
value = value.substring(0, 8); // 限制最大长度为8
}
e.target.value = value; // 更新输入框值
if (value.length === 8) {
// 格式化为YYYY/MM/DD
const year = value.substring(0, 4);
const month = value.substring(4, 6);
const day = value.substring(6, 8);
// 验证月份和日期是否有效
const validMonth = parseInt(month) >= 1 && parseInt(month) <= 12;
const validDay = parseInt(day) >= 1 && parseInt(day) <= 31;
if (validMonth && validDay) {
const formattedDate = `${year}/年${month}/月${day}日`;
document.getElementById('dateDisplay').textContent = formattedDate;
document.getElementById('formattedDate').value = formattedDate;
} else {
document.getElementById('dateDisplay').textContent = '日期无效';
document.getElementById('formattedDate').value = '';
}
} else {
document.getElementById('dateDisplay').textContent = '年 / 月 / 日';
document.getElementById('formattedDate').value = '';
}
});
</script>
</body>
</html>
ok.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>提交成功!!!</h1>
<a href="./test.html" target="_blank">跳转到填写页面</a>
</body>
</html>
案例二:重复填写表单
提示:需要使用到句柄
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get(r'HTML文件绝对路径')
# 循环重复
for x in range(2):
time.sleep(2)
# 单选
browser.find_element(By.XPATH, '/html/body/form/div[1]/label[2]').click()
# 多选
browser.find_element(By.XPATH, '/html/body/form/div[2]/label[1]').click()
browser.find_element(By.XPATH, '/html/body/form/div[2]/label[2]').click()
browser.find_element(By.XPATH, '/html/body/form/div[2]/label[3]').click()
# 下拉
browser.find_element(By.XPATH, '/html/body/form/div[3]/select/option[2]').click()
# 日期框
browser.find_element(By.XPATH, '/html/body/form/div[4]/div/input').send_keys('20210912')
# 上传文件
browser.find_element(By.XPATH, '/html/body/form/div[5]/input').send_keys(r'上传文件绝对路径')
time.sleep(2)
# 提交
browser.find_element(By.XPATH, '/html/body/form/button').click()
# 点击返回
browser.find_element(By.XPATH, '/html/body/a').click()
# 打开了新页面之后,我们要获取到全部的句柄(也就是所有的标签页)
handles = browser.window_handles
# print(handles)
# 关闭之前的标签页
browser.close()
# 通过句柄切换到新的标签页
browser.switch_to.window(handles[1])
# 获取当前页句柄
# print(browser.current_window_handle)
五、三种浏览器获取框(警告框、确认框、提示框)
➡➡➡测试网址
5.1 警告框
示例代码:
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get('https://sahitest.com/demo/alertTest.htm')
# 清空输入框的默认值
browser.find_element(By.XPATH,"/html/body/form/input[1]").clear()
time.sleep(2)
# 修改输入框的值
browser.find_element(By.XPATH,"/html/body/form/input[1]").send_keys('大家一起学Python')
# 点击按钮
browser.find_element(By.XPATH,"/html/body/form/input[2]").click()
# 获取弹窗的内容
print(browser.switch_to.alert.text)
time.sleep(2)
# 点击确认按钮
browser.switch_to.alert.accept()
5.2 确认框
➡➡➡测试网址
5.3 提示框
示例代码
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get('https://sahitest.com/demo/confirmTest.htm')
# 点击按钮
browser.find_element(By.XPATH,'/html/body/form/input[1]').click()
time.sleep(2)
# 点击确认按钮
# browser.switch_to.alert.accept()
# 点击取消按钮
browser.switch_to.alert.dismiss()
➡➡➡测试网址
示例代码:
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get('https://sahitest.com/demo/promptTest.htm')
# 点击按钮
browser.find_element(By.XPATH,'/html/body/form/input[1]').click()
time.sleep(2)
# 输入内容
browser.switch_to.alert.send_keys("123456")
time.sleep(2)
# 点击确认按钮
browser.switch_to.alert.accept()
六、 iframe嵌套网页内部元素获取
➡➡➡测试网址
示例代码:
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get('https://sahitest.com/demo/iframesTest.htm')
# iframe嵌套网页 里面的元素 不能够直接获取 因为不在同一个框架里面
# 1. 获取iframe元素
iframe = browser.find_element(By.XPATH, '/html/body/iframe')
# 2. 进入到iframe里面
browser.switch_to.frame(iframe)
# 获取元素并点击
browser.find_element(By.XPATH, '/html/body/table/tbody/tr/td[1]/a[1]').click()
time.sleep(2)
# 此时如果想要获取原页面中的元素就必须退出iframe
browser.switch_to.default_content()
time.sleep(2)
# 获取原页面元素
browser.find_element(By.XPATH, '/html/body/input[2]').click()
七、获取元素以及判断可见性
selenium提供了一些基础的爬虫方式。
示例代码:
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get('https://content-static.cctvnews.cctv.com/snow-book/video.html?item_id=932400080038356852')
# 获取元素内容 text
content = browser.find_element(By.XPATH,"/html/body/div/div/div/div[2]/div[1]/div[1]/div/div[5]/div/article/p[1]").text
print(content)
# 获取元素可见性
# 简单来说 就是判断这个元素我们能否在页面上看见
flag = browser.find_element(By.XPATH,"/html/head/meta[2]").is_displayed()
print(flag)
八、 网页前进、后退
示例代码:
def setup():
options = Options()
options.add_experimental_option("detach", True)
browser = webdriver.Chrome(service=Service('chromedriver.exe'), options=options)
# 设置性代码,只要获取元素都会先等待10s 10s之后才会出现异常
# 并且只需要设置一次即可
browser.implicitly_wait(10)
return browser
browser = setup()
browser.get('https://www.baidu.com')
input = browser.find_element(By.ID, 'kw')
input.send_keys('selenium')
button = browser.find_element(By.ID, 'su')
button.click()
time.sleep(3)
# 网页后退
browser.back()
time.sleep(2)
# 网页前进
browser.forward()
time.sleep(2)
# 关闭
browser.quit()
总结
通过本文的学习,我们系统地了解了 Python 与 Selenium 的结合使用,涵盖了从基础配置到实际应用的多个方面。Selenium 不仅简化了 Web 自动化测试的流程,还为数据采集和动态网页交互提供了强大的支持。借助 Python 的灵活性和 Selenium 的丰富功能,开发者能够高效地完成复杂的任务,无论是自动化测试、爬虫开发,还是网页监控。
当然,Selenium 的强大功能也伴随着一定的学习曲线,尤其是在处理动态内容、反爬机制或复杂的页面结构时,可能需要更多的技巧和经验积累。但只要你掌握了核心的定位与交互方法,并学会利用等待机制、多窗口切换等高级功能,就能应对绝大多数场景的需求。
希望本文能为你打开 Selenium 世界的大门,让你在自动化测试或数据抓取的道路上更加得心应手。技术的进步永无止境,不断实践和探索,你将发现更多 Selenium 与 Python 结合的奇妙用法。继续加油,愿你在自动化的世界中创造更多可能!