selenium从0到掌握
简介
Selenium 是最广泛使用的开源 Web UI(用户界面)自动化测试套件之一。Selenium 支持的语言包括C#,Java,Perl,PHP,Python 和 Ruby。目前,Selenium Web 驱动程序最受 Python 和 C#欢迎。 Selenium 测试脚本可以使用任何支持的编程语言进行编码,并且可以直接在大多数现代 Web 浏览器中运行。在爬虫领域 selenium 同样是一把利器,能够解决大部分的网页的反爬问题。下面就进入正式的 study 阶段。
安装
打开cmd命令,输入:
pip install -i https://pypi.douban.com/simple selenium
安装相应的浏览器驱动
针对不同的浏览器,需要安装不同的驱动。下面列举了常见的浏览器与对应的驱动程序下载链接,部分网址需要 “科学上网” 才能打开哦(dddd)。
Firefox 浏览器驱动:Firefox
Chrome 浏览器驱动:Chrome
IE 浏览器驱动:IE
Edge 浏览器驱动:Edge
PhantomJS 浏览器驱动:PhantomJS
Opera 浏览器驱动:Opera
不自动关闭浏览器
from selenium import webdriver
# chrom 浏览器
driver = webdriver.Chrome(r".\101.0.4951.41驱动\chromedriver.exe")
# 不自动关闭浏览器
option = webdriver.ChromeOptions()
option.add_experimental_option("detach", True)
# 将option作为参数添加到Chrome中
driver = webdriver.Chrome(chrome_options=option)
定位语法
单个元素element
多个元素elements
多一个s
id定位
标签的id具有唯一性
,就像人的身份证,假设有如下标签:
<input id="toolbar-search-input" autocomplete="off" type="text" value="" placeholder="C++难在哪里?">
我们可以通过 id
定位到它,由于id的唯一性,我们可以不管其他的内容:
driver.find_element_by_id("toolbar-search-input")
name 定位
name
指定标签的名称,在页面中不唯一,如下:
<meta name="keywords" content="优快云博客,优快云学院,优快云论坛,优快云直播">
我们可以使用 find_element_by_name
来定位
driver.find_element_by_name("keywords")
class 定位
class
指定标签的类名,在页面中不唯一,如下:
<div class="toolbar-search-container">
我们可以使用find_element_by_class_name
来定位:
driver.find_element_by_class_name("toolbar-search-container")
tag 定位(标签)
每个 tag
往往来定义一类功能,所以通过tag
来识别某个元素的成功率很低,每个页面都用很多的tag
,比如:div ,input,比如:
<div class="toolbar-search-container">
我们可以使用 find_element_tag_name
定位到div标签
css定位
css
使用选择器来为页面绑定属性,它比较较为灵活的选择控件的任意属性
方法 | 例子 | 描述 |
---|---|---|
.class | .a | 选择class=’a‘的所有元素 |
#id | #a | 选择id=‘a’的所有元素 |
* | * | 选择所有元素 |
element | input | 选择所有的 input元素 ,也可以是其他自定义元素 |
element > element | div>input | 选择父元素为div的所有input元素 |
element+element | div+input | 选择同一级中在 div 之后的所有 input 元素 |
[attribute = value] | 通过属性选择元素 | [ type = ‘password’] 选择type属性为password的元素 |
[attribute] | [type] | 选择具有type属性的元素 |
a:link ,a:visited | 选择未被访问 、已被访问的元素 | |
p:empty | 选择没有子元素的p元素 |
通过find_element_by_css_selector
访问:
driver.find_element_by_css_selector('#a')
driver.find_element_by_css_selector('html>body>div>div>div>div>div>div>input')
link
link专门用来定位文本链接
,也就是根据超链接的全匹配文本,找到对应的超链接如:
<div class="practice-box" data-v-04f46969="">百度地图</div>
我们可以使用find_element_by_link_text
来定位,如:
//找到百度地图的超链接文本,并单击
driver.find_element_by_link_text("百度地图").click()
partial_link 定位
partial_link
翻译过来就是"部分链接",有些时候有些文本比较长,我们就可以指定部分的文本,如:
<div class="practice-box" data-v-04f46969="">加入!每日一练</div>
我们可以使用 find_element_partial_link_text
来定位,如:
driver.find_element_by_partial_link_text("加入")
by类定位
导入类
from selenium.webdriver.common.by import By
具体语法
# 1. 通过元素的id属性进行定位。
find_element(By.ID, "id属性值")
# 2. 通过元素的name属性进行定位。
find_element(By.NAME, "name属性值")
# 3. 通过元素的class属性进行定位。
find_element(By.CLASS_NAME, "class属性值")
# 4.通过元素标签进行定位。
find_element(By.TAG_NAME, "标签名")
# 5. 通过超链接中全部文字定位超链接。
find_element(By.LINK_TEXT, "完整超链接文本")
# 6. 通过超链接中部分连续文字定位超链接。
find_element(By.PARTIAL_LINK_TEXT, "部分超链接文本")
# 7. 通过XPath定位元素。
find_element(By.XPATH, "XPath路径表达式")
# 8. 通过css选择器定位元素。
find_element(By.CSS_SELECTOR, "css选择器定位策略")
By定位与8种基本定位方法类比
浏览器控制
修改浏览器窗口大小
webdriver
提供了set_window_size()
方法来修改浏览器窗口的大小(宽高)
如:
driver.set_window_size(600,800)
也可以使用maximize_window()
方法,实现让浏览器全屏幕显示,如:
driver.maximize_window()
浏览器的前进、后退
webdriver提供back
和forward
方法来实现页面的后退
和前进
,如:
from selenium import webdriver
# chrom 浏览器
driver = webdriver.Chrome(r".\101.0.4951.41驱动\chromedriver.exe")
driver.maximize_window()
driver.get("https://www.baidu.com/")
xinxi = driver.find_element_by_link_text("地图").click()
# 回到百度首页
driver.back()
#在前进到 地图页面
driver.forward()
如果想要再次打开网页的时候,不是在原来窗口上访问,也就是在新的窗口上打开新的链接,我们需要用js
来打开新的标签,如:
js= "window.open('网址')"
driver.execute_script(js)
浏览器刷新
在一些特殊的情况下,我们需要刷新我们的页面才能获取数据,这时我们可以使用refresh
来刷新我们的页面,如:
driver.refresh()
浏览器窗口切换
在很多时候我们都需要用到窗口切换,比如:当我们点击注册按钮的时候,它一般都会打开一个新的标签,但是我们本身并没有跳转过去。
我们先获取窗口的句柄
,这些信息存放顺序都是按照时间
来的,最新打开的窗口就在末尾,这时候我们就可以定位到我们最后打开的窗口,如:
#获取当前页面的句柄
driver.current_window_handle
#获取打开的多个窗口句柄
window = driver.window_handles
# 打开顺序中最后一个窗口
driver.switch_to.window(window[-1])
webdriver 常见操作
方法 | 描述 |
---|---|
send_keys() | 模拟输入指定的内容 |
clear() | 清除文本内容 |
is_displayed() | 判断该元素是否可见 |
get_attribute() | 获取标签属性值 |
size | 返回元素的尺寸 |
text | 返回元素的文本 |
例子
# -*- coding: utf-8 -*-
# @Time : 2022/5/25 17:31
# @Author : FleChazo
# @Email : 1963855603@qq.com
from time import sleep
from selenium import webdriver
# chrome 浏览器
driver = webdriver.Chrome(r".\101.0.4951.41驱动\chromedriver.exe")
driver.get('https://www.youkuaiyun.com/')
sleep(2)
# 定位搜索输入框
text_label = driver.find_element_by_xpath('//*[@id="toolbar-search-input"]')
# 在搜索框中输入 Dream丶Killer
text_label.send_keys('Dream丶Killer')
sleep(2)
# 清除搜索框中的内容
text_label.clear()
# 输出搜索框元素是否可见
print(text_label.is_displayed())
# 输出placeholder的值
print(text_label.get_attribute('placeholder'))
# 定位搜索按钮
button = driver.find_element_by_xpath('//*[@id="toolbar-search-button"]/span')
# 输出按钮的大小
print(button.size)
# 输出按钮上的文本
print(button.text)
'''输出内容
True
数据可视化工具
{'height': 32, 'width': 28}
搜索
'''
鼠标控制
常见方法
在webdriver中,鼠标的操作都封装在ActionChains类中
方法 | 描述 |
---|---|
click() | 单击鼠标左键 |
context_click() | 单击鼠标右键 |
duoble_click() | 双击 |
drag_and_drop() | 拖动 |
move_to_element() | 鼠标悬停 |
perform() | 执行所有ActionChains中存储的动作 |
单击左键
左键不需要用到Actionchains
# 定位搜索按钮
button = driver.find_element_by_xpath('//*[@id="toolbar-search-button"]/span')
# 执行单击操作
button.click()
右击
需要用到 ActionChains类
导入
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.action_chains import ActionChains
# 定位搜索按钮
button = driver.find_element_by_xpath('//*[@id="toolbar-search-button"]/span')
# 右键搜索按钮
ActionChains(driver).context_click(button).perform()
双击
也需要用到Actionchains类
导入 from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).double_click(driver.find_element_by_link_text("地图")).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('//*[@id="csdn-toolbar"]/div/div/div[3]/div/div[3]/a')
# 悬停至收藏标签处
ActionChains(driver).move_to_element(collect).perform()
键盘控制
定义
webdriver
中的keys
类几乎包含了键盘上的所有按键,我们也可以使用send_keys+keys
实现键盘上的组合键,ctrl+c,ctrl+v等,如:
导入类
import 后面是大写的K
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.keys import Keys
# 定位输入框并输入文本
driver.find_element_by_id('xxx').send_keys('Dream丶killer')
# 模拟回车键进行跳转(输入内容后)
driver.find_element_by_id('xxx').send_keys(Keys.ENTER)
# 使用 Backspace 来删除一个字符
driver.find_element_by_id('xxx').send_keys(Keys.BACK_SPACE)
# Ctrl + A 全选输入框中内容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'a')
# Ctrl + C 复制输入框中内容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'c')
# Ctrl + V 粘贴输入框中内容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'v')
常见的操作
都是大写K,Keys
操作 | 描述 |
---|---|
Keys.F1 | F1键 |
Keys.SPACE | 空格 |
Keys.BACK_SPACE | 删除键 |
Keys.TAB | tab键 |
Keys.ESCAPE | esc键 |
Keys.ALT | alt键位 |
Keys.SHIFT | shift键 |
Keys.ARROW_DOWN | 向下箭头 |
Keys.ARROW_UP | 向上箭头 |
Keys.ARROW_LEFT | 向左箭头 |
Keys.ARROW_RIGHT | 向右箭头 |
Keys类
上面我列举了常用的操作,下面是 Keys类中的属性:
class Keys(object):
"""
Set of special keys codes.
"""
NULL = '\ue000'
CANCEL = '\ue001' # ^break
HELP = '\ue002'
BACKSPACE = '\ue003'
BACK_SPACE = BACKSPACE # 删除键
TAB = '\ue004' # TAB键
CLEAR = '\ue005'
RETURN = '\ue006'
ENTER = '\ue007' # 回车键
SHIFT = '\ue008' # Shift键
LEFT_SHIFT = SHIFT # Shift键
CONTROL = '\ue009'
LEFT_CONTROL = CONTROL # Ctrl键
ALT = '\ue00a' # Alt键
LEFT_ALT = ALT
PAUSE = '\ue00b'
ESCAPE = '\ue00c' # ECS键
SPACE = '\ue00d' # 空格键
PAGE_UP = '\ue00e' # PgUp
PAGE_DOWN = '\ue00f' # PgDn
END = '\ue010' # End
HOME = '\ue011' # Home
LEFT = '\ue012' # ← 键
ARROW_LEFT = LEFT
UP = '\ue013' # ↑ 键
ARROW_UP = UP
RIGHT = '\ue014' # → 键
ARROW_RIGHT = RIGHT
DOWN = '\ue015' # ↓ 键
ARROW_DOWN = DOWN
INSERT = '\ue016' # insert键
DELETE = '\ue017' # Del键
SEMICOLON = '\ue018' # ;键
EQUALS = '\ue019' # = 键
NUMPAD0 = '\ue01a' # 数字小键盘
NUMPAD1 = '\ue01b'
NUMPAD2 = '\ue01c'
NUMPAD3 = '\ue01d'
NUMPAD4 = '\ue01e'
NUMPAD5 = '\ue01f'
NUMPAD6 = '\ue020'
NUMPAD7 = '\ue021'
NUMPAD8 = '\ue022'
NUMPAD9 = '\ue023'
MULTIPLY = '\ue024' # * 键
ADD = '\ue025' # + 键
SEPARATOR = '\ue026' # , 键
SUBTRACT = '\ue027' # - 键
DECIMAL = '\ue028' # . 键
DIVIDE = '\ue029' # / 键
F1 = '\ue031' # F1
F2 = '\ue032'
F3 = '\ue033'
F4 = '\ue034'
F5 = '\ue035'
F6 = '\ue036'
F7 = '\ue037'
F8 = '\ue038'
F9 = '\ue039'
F10 = '\ue03a'
F11 = '\ue03b'
F12 = '\ue03c'
META = '\ue03d'
COMMAND = '\ue03d'
设置元素等待
定义
很多页面都采用ajax
技术,页面的元素不是同时全部都被加载出来的,所以我们为了避免元素没加载出来的报错,可以这是元素来增加脚本的稳定性。webdriver
中的等待分为显式等待
、隐式等待
、强制等待
expected_conditions(配合显式等待的模块)
导入类
from selenium.webdriver.support import expected_conditions as EC
常用方式
显式等待
显式等待:设置一个超时时间
,每隔一段时间
就去检查一次该元素是否存在
- 条件成立就执行下面的代码
- 条件不成立就抛出异常
WebDriverWait对象
包、语法
from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
- driver : 浏览器对象
- timeout : 超时时间,单位
秒
- poll_frequency:每次检测的间隔时间,默认为0.5秒
- ignored_exceptions:指定忽略的异常,如果在调用util或者util_not方法时,抛出忽略的异常,则不中断代码,默认忽略的只有
NoSuchElementException
(异常详细解析)
而显式等待通常是和until
和until_not
一起使用,expected_conditions
类配合使用,也就是这几步:
- 声明一个driverwait对象,指定等待的时间和每次间隔多少时间检查元素
- 再通过 util 或者 util_not 方法,达到返回结果和抛出异常的解决方法
- 在上面的方法里面,通过expected_conditions 进行元素的判断
util、util_not方法
语法
util(method,message='')
util_not(method,message='')
详解
- method:指定预期条件的判断方法,在等待期间,每隔一段时间调用该方法,判断元素是否存在,如果超过了设置的时间,就会抛出TimeoutException异常
- message:如果超时,就会抛出
TimeoutException
异常,然后显示我们自定义message的消息
混合使用的例子
# -*- coding: utf-8 -*-
# @Time : 2022/5/25 17:31
# @Author : FleChazo
# @Email : 1963855603@qq.com
from time import sleep
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait
# chrome 浏览器
driver = webdriver.Chrome(r".\101.0.4951.41驱动\chromedriver.exe")
driver.get('https://www.baidu.com/')
# baidu = driver.find_element_by_xpath("//*[@id='kw']")
element = WebDriverWait(driver, 1, 0.5).until(
ec.presence_of_element_located( (By.ID, 'dadada') ),
message='超时啦!')
隐式等待
隐式等待也是有一个超时时间的,超时就会抛出NosuchElementException异常,除了抛出的异常不一样之外,还有一点:
- 隐式等待是全局性的,即在运行过程中,如果元素可以被定位到,则不影响程序的进行,如果定位不到,则会以
轮询
的方式不断的访问元素,若超过了指定的时间,则会抛出异常。 - 我们使用
implicitly_wait()
来实现隐式等待,示例:
from selenium import webdriver
from time import time
driver = webdriver.Chrome()
driver.get('https://blog.youkuaiyun.com/qq_43965708')
start = time()
#设置隐式等待 5秒
driver.implicitly_wait(5)
try:
#当进行寻找元素的操作时 触发隐式等待
driver.find_element_by_id('kw')
except Exception as e:
#如果超出了等待的时间 则抛出异常
print(e)
print(f'耗时:{time()-start}')
结果:
强制等待
使用time.sleep()
强制等待,设置固定的休眠时间,对于代码的效率会有影响,例如:
from selenium import webdriver
from time import time, sleep
driver = webdriver.Chrome()
driver.get('https://blog.youkuaiyun.com/qq_43965708')
start = time()
sleep(5)
try:
driver.find_element_by_id('kw')
except Exception as e:
print(e)
print(f'耗时:{time()-start}')
结果:
当查找不到元素的时候,隐式等待和强制等待并没有什么不同,但是如果元素过了两秒(反正只要被加载出来)之后,隐式只会等待两秒,但是强制等待,会等待5秒
表单切换
定义
很多页面都会带frame/iframe
表单嵌套,对于这种内嵌的页面selenium是不可以直接定位
的,需要使用switch_to.frame()
方法将当前操作的对象切换为frame/iframe
内嵌的页面。(frame/iframe详解)
switch_to.frame()
默认可以是用id
或者name
属性直接定位,但是没有id和name属性,这时候就要用到xath定位
,如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div p {
color: #red;
animation: change 2s infinite;
}
@keyframes change {
from {
color: red;
}
to {
color: blue;
}
}
</style>
</head>
<body>
<div>
<p>名字:惊鸿</p>
<p>优快云:惊鸿</p>
</div>
<!--<iframe src="https://blog.youkuaiyun.com/qq_40608132?spm=1018.2226.3001.5343" width="400" height="200"></iframe>-->
<iframe id="优快云_info" name="jh" src="https://blog.youkuaiyun.com/qq_40608132?spm=1018.2226.3001.5343" width="100%" height="100%"></iframe>
</body>
</html>
我们点击红框中的csdn按钮就可以跳转到csdn页面:
# -*- coding: utf-8 -*-
# @Time : 2022/5/27 17:06
# @Author : FleChazo
# @Email : 1963855603@qq.com
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome(r".\101.0.4951.41驱动\chromedriver.exe")# "file:///
driver.get("file:///D:/专业文件/Vue/简单测试/index.html")
# driver.switch_to.frame("优快云_info")
# 1.通过id定位
driver.switch_to.frame('优快云_info')
# 2.通过name定位
# driver.switch_to.frame('jh')
# 通过xpath定位
# 3.iframe_label = driver.find_element_by_xpath('/html/body/iframe')
driver.implicitly_wait(3)
driver.find_element(By.XPATH,"/html/body/div[1]/div/div/div[1]/div/a/img").click()
弹窗处理
HTML的弹窗类型
- 警告消息框(alert)
警告消息框提供了一个’确定‘按钮让用户关闭消息框,并且该消息框是模式对话框,也就是说用户必须关闭消息框之后才能进行操作
- 确认消息框(confrim)
确认消息框像用户提示一个’是’与’否‘的问题,用户可以点击确定和取消按钮
- 提示消息对话(prompt)
提示消息框提供了一个文本提示,用户可以在此输入一个答案来响应你的提示
该消息框有一个确定和取消按钮,点击按钮都会分别显示相应的提示信息
因为这种弹窗是不属于HTML的元素的,它是属于浏览器自带的弹窗(是由JavaScript生成的),所以用定位元素的方法是定位不了的(这类元素在使用F12选择元素时,是选择不到的)
在selenium中,提供了switch_to.alert()
方法来定位到各种弹窗
- 先定位弹窗(
switch_to.alert,自动定位当前弹窗
) - 在使用下方相应的方法进行操作
方法 | 描述 |
---|---|
text | 获取弹窗中的文字 |
accept | 相当于点击确定 |
dismiss 相当于点击取消 | |
send_keys | 输入值(只能在prompt弹窗中使用) |
例子
confirm弹窗
自己写的一个demo:
<html>
<head>
<script type="text/javascript">
function show_confirm()
{
var r=confirm("请问:您是否关注了我的博客?");
}
</script>
</head>
<body>
<center>
<input id="anjing" type="button" onclick="show_confirm()" value="点我,点我有惊喜!" />
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
</center>
</body>
</html>
# -*- coding: utf-8 -*-
# @Time : 2022/5/27 17:06
# @Author : FleChazo
# @Email : 1963855603@qq.com
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome(r".\101.0.4951.41驱动\chromedriver.exe")# "file:///
driver.get("file:///D:/专业文件/Vue/简单测试/index.html")
# 点击按钮并弹出对话框
driver.find_element_by_id("anjing").click()
time.sleep(1)
# 定位对话框
alter = driver.switch_to.alert
print(alter)
# 打印对话框内容
print(alter.text)
# 点击对话框[确定]按钮以关闭对话框
# alter.accept()
# 点击对话框[取消]按钮以关闭对话框
alter.dismiss()
time.sleep(1)
# 关闭对话框后继续操作页面
driver.find_element_by_id("kw").send_keys("不怕猫的耗子A")
"""
<selenium.webdriver.common.alert.Alert object at 0x0000028242C68DA0>
请问:您是否关注了我的博客?
"""
commpt弹窗
<html>
<head>
<script type="text/javascript">
function disp_prompt()
{
var name=prompt("请问:您关注我的博客了吗?")
}
</script>
</head>
<body>
<center>
<input id="mouse" type="button" onclick="disp_prompt()" value="点我,点我有惊喜" />
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
</center>
</body>
</html>
代码:
# -*- coding: utf-8 -*-
# @Time : 2022/5/27 17:06
# @Author : FleChazo
# @Email : 1963855603@qq.com
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
# driver = webdriver.Chrome(r".\101.0.4951.41驱动\chromedriver.exe")# "file:///
driver = webdriver.Firefox(executable_path=r"E:\PythoRUANJIAN\worspase\untitled\爬虫\selenium\二次学习\火狐2022.4\geckodriver.exe")# "file:///
driver.get("file:///D:/专业文件/Vue/简单测试/index.html")
from time import sleep
sleep(2)
# 点击alert按钮
driver.find_element_by_xpath('//*[@id="alert"]').click()
sleep(1)
alert = driver.switch_to.alert
# 打印alert弹窗的文本
print(alert.text)
# 确认
alert.accept()
sleep(2)
# 点击confirm按钮
driver.find_element_by_xpath('//*[@id="confirm"]').click()
sleep(1)
confirm = driver.switch_to.alert
print(confirm.text)
# 取消
confirm.dismiss()
sleep(2)
# 点击confirm按钮
driver.find_element_by_xpath('//*[@id="prompt"]').click()
sleep(1)
prompt = driver.switch_to.alert
print(prompt.text)
# 向prompt的输入框中传入文本
prompt.send_keys("prompt测试输入")
sleep(2)
prompt.accept()
'''输出
alert框
confirm框
prompt框
'''
上传、下载文件
上传
常见的web页面的上传,一般用input
标签或(JavaScript、Ajax),对于input
标签的上传,可以直接使用send_keys(文件路径)
来进行上传
自己的写的demo:
在这里插入代码片