Selenium框架
Selenium框架
- Selenium是一个自动化测试工具,用于模拟用户在Web应用程序上的操作。它提供了多种编程语言的接口,如Python、Java等,使测试人员能够编写自动化测试脚本。Selenium可以模拟用户在不同浏览器上的操作,包括点击、输入文本等,以验证Web应用程序的功能和性能。它还支持分布式测试和集成到持续集成系统中,使软件开发过程更加高效。
(1)简单操作
[1]初始化浏览器对象
from selenium import webdriver
browser = webdriver.Chrome()
browser.close()
from selenium import webdriver
path = r'./chromedriver'
browser = webdriver.Chrome()
browser.close()
[2]访问页面
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get('https://www.jd.com')
time.sleep(5)
[3]设置浏览器大小
set_window_size()
设置分辨率
from selenium import webdriver
import time
browser = webdriver.Chrome()
# 设置分辨率大小为 500*500
browser.set_window_size(500, 500)
browser.get('https://www.baidu.com')
time.sleep(2)
# 关闭浏览器
browser.close()
maximize_window
设置全屏
from selenium import webdriver
import time
browser = webdriver.Chrome()
# 设置浏览器为全屏
browser.maximize_window()
browser.get('https://www.baidu.com')
time.sleep(2)
# 关闭浏览器
browser.close()
[4]前进后退
forward()
前进back()
后退
from selenium import webdriver
import time
browser = webdriver.Chrome()
# 设置浏览器全屏
browser.maximize_window()
# 打开百度页面
browser.get('https://www.baidu.com')
time.sleep(2)
# 打开bilibili页面 每次打开都会覆盖之前的
browser.get('https://www.bilibili.com/')
time.sleep(2)
# 后退到百度页面
browser.back()
time.sleep(2)
# 前进到bilibili页面
browser.forward()
time.sleep(2)
# 关闭浏览器
browser.close()
[5]获取页面基础属性
browser.title
: 获取网页标题browser.current_url
: 获取当前访问的网址browser.name
: 获取当前浏览器的名称browser.page_source
: 获取当前网页的源码
from selenium import webdriver
# 实例化得到浏览器对象
browser = webdriver.Chrome()
# 访问百度页面
browser.get('https://www.baidu.com')
# 网页标题
print(browser.title)
# 当前网址
print(browser.current_url)
# 浏览器名称
print(browser.name)
# 网页源码
print(browser.page_source)
[6]切换选项卡
browser.window_handles
: 获取聚柄 默认从0开始switch_to.window(聚柄[索引])
: 切换选项卡
from selenium import webdriver
import time
# 创建 Chrome 浏览器的实例
browser = webdriver.Chrome()
# 打开百度网页
browser.get('https://www.baidu.com/')
time.sleep(2)
# 在当前浏览器实例中新开一个选项卡
browser.execute_script('window.open()')
time.sleep(2)
# 获取所有选项卡的聚柄列表
all_handles = browser.window_handles
# 切换到第二个选项卡(下标为1)
browser.switch_to.window(all_handles[1])
time.sleep(2)
# 在第二个选项卡中打开jd网页
browser.get('http://www.jd.com')
time.sleep(2)
# 切换回第一个选项卡(下标为0)
browser.switch_to.window(all_handles[0])
time.sleep(2)
# 在第一个选项卡中打开bilibili网页
browser.get('http://www.bilibili.com')
time.sleep(2)
browser.close()
browser.quit()
(2)定位页面元素
(1)八大选择器介绍
- 通过webdriver对象的 find_element(by=“属性名”, value=“属性值”),主要包括以下这八种。
属性 | 函数 |
---|---|
CLASS | find_element(by=By.CLASS_NAME, value='') |
XPATH | find_element(by=By.XPATH, value='') |
LINK_TEXT | find_element(by=By.LINK_TEXT, value='') |
PARTIAL_LINK_TEXT | find_element(by=By.PARTIAL_LINK_TEXT, value='') |
TAG | find_element(by=By.TAG_NAME, value='') |
CSS | find_element(by=By.CSS_SELECTOR, value='') |
ID | find_element(by=By.ID, value='') |
from selenium.webdriver.common.by import By
(2)示例
[1]ID
- 通过元素的 ID 属性进行定位
element = driver.find_element(By.ID, "element_id")
[2]name
- 通过元素的 Name 属性进行定位
element = bro.find_element(By.NAME, 'element_name')
[3]Class
- 通过元素的 Class 属性进行定位
element = bro.find_element(By.CLASS_NAME, 'element_class')
[4]Tag定位
- 通过标签名进行定位
elements = bro.find_elements(By.TAG_NAME, 'div')
[5]Link文字
- 精确定位
element = bro.find_element(By.LINK_TEXT, 'link_text')
[6]Partial Link文字
- 模糊定位
element = bro.find_element(By.PARTIAL_LINK_TEXT, 'partial_link_text')
[7]XPath
- XPath 表达式进行定位
element = bro.find_element(By.XPATH, 'xpath_expression')
[8]CSS选择器
element = bro.find_element(By.CSS_SELECTOR, 'css_selector')
(3)百度案例
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/s?wd=xpath')
li_list = browser.find_elements(by=By.XPATH,value='/html/body/div[3]/div[5]/div[1]/div[1]/table/tbody/tr/td/div[1]/div[1]/div/section/div[2]/div[1]/div/section[1]/div')
for i in li_list:
print(i.text)
(3)元素操作
[1]向input框内输入内容
send_keys('')
search_input.send_keys('')
[2]清空内容
clear()
search_input.clear()
[3]点击元素操作
click()
search_input.click()
[4]获取元素的属性名对应的属性值
get_attribute(属性名)
search_input.get_attribute(属性名)
[5]提交操作
submit()
search_input.submit()
[2]获取元素的坐标
search_input.location # {'x': 236, 'y': 70}
[6]jd案例输入提交
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.jd.com')
search_input = browser.find_element(By.XPATH, '/html/body/div[1]/div[4]/div/div[2]/div/div[2]/input')
search_input.send_keys('手机')
time.sleep(3)
search_input.clear()
time.sleep(3)
search_input.send_keys('苹果')
time.sleep(3)
submit_btn = browser.find_element(By.XPATH, '/html/body/div[1]/div[4]/div/div[2]/div/div[2]/button')
submit_btn.click()
time.sleep(3)
browser.close()
(4)动作链
(1)模拟鼠标操作
from selenium.webdriver.common.action_chains import ActionChains
操作 | 函数 |
---|---|
鼠标左击 | click() |
鼠标右击 | context_click() |
鼠标双击 | double_click() |
鼠标拖拽 | drag_and_drop |
鼠标悬停 | move_to_element() |
鼠标移动到指定位置 | move_by_offset(xoffset,yoffset) |
鼠标释放 | release() |
鼠标按住不放 | click_and_hold(元素) |
执行 | perform() |
(2)模拟键盘操作
from selenium.webdriver.common.keys import Keys
操作 | 函数 |
---|---|
删除键 | send_keys(Keys.BACK_SPACE) |
空格键 | send_keys(Keys.SPACE) |
制表键 | send_keys(Keys.TAB) |
回退键 | send_keys(Keys.ESCAPE) |
回车 | send_keys(Keys.ENTER) |
全选 | send_keys(Keys.CONTRL,'a') |
复制 | send_keys(Keys.CONTRL,'c') |
剪切 | send_keys(Keys.CONTRL,'x') |
粘贴 | send_keys(Keys.CONTRL,'v') |
(3)jd使用案例
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
browser = webdriver.Chrome()
browser.get('https://www.jd.com')
action = ActionChains(browser)
search_input = browser.find_element(By.XPATH, '/html/body/div[1]/div[4]/div/div[2]/div/div[2]/input')
search_input.send_keys('手机')
time.sleep(3)
search_input.send_keys(Keys.CONTROL, 'a')
time.sleep(3)
search_input.send_keys(Keys.CONTROL, 'c')
time.sleep(3)
search_input.clear()
time.sleep(3)
search_input.send_keys(Keys.CONTROL, 'v')
time.sleep(3)
submit_btn = browser.find_element(By.XPATH, '/html/body/div[1]/div[4]/div/div[2]/div/div[2]/button')
action.drag_and_drop(search_input, submit_btn).click().perform()
time.sleep(3)
browser.close()
(4)iframe拖拽案例
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
browser = webdriver.Chrome()
browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
browser.maximize_window()
browser.switch_to.frame('iframeResult')
old = browser.find_element(By.ID, 'draggable')
target = browser.find_element(By.ID, 'droppable')
# 鼠标按住源元素不放
ActionChains(browser).click_and_hold(old).perform()
# 计算鼠标需要移动的距离
distance = target.location['x'] - old.location['x']
track = 0
while track < distance:
# xoffset 表示水平方向上的偏移量,yoffset 表示垂直方向上的偏移量。
# xoffset:表示相对于当前鼠标位置的水平方向上的移动距离。
# 如果xoffset 为正数,鼠标将向右移动;如果xoffset 为负数,鼠标将向左移动;
# 如果xoffset 为0,则水平方向上不发生移动。
ActionChains(browser).move_by_offset(xoffset=5, yoffset=0).perform()
track += 5
# 松开鼠标
ActionChains(browser).release().perform()
# 等待一段时间,观察效果
time.sleep(10)
browser.close()
(5)执行js代码
execute_script()
selenium并不是万能的,有时候页面上操作无法实现的,这时候就需要借助JS来完成了当页面上的元素超过一屏后,想操作屏幕下方的元素,是不能直接定位到,会报元素不可见的。
当页面上的元素超过一屏后,想操作屏幕下方的元素,是不能直接定位到,会报元素不可见的。
这时候需要借助滚动条来拖动屏幕,使被操作的元素显示在当前的屏幕上。
(1)滚动到页面底部
window.scrollTo(0, document.body.scrollHeight)
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.jd.com/')
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
time.sleep(3)
(2)点击
arguments[0].click();
arguments[0]
表示传递给JavaScript脚本的第一个参数(即element
),通过调用click()
方法实现点击操作。
# 使用JavaScript点击一个按钮
element = browser.find_element(By.ID,'button_id')
browser.execute_script('arguments[0].click();', element)
(3)输入文本
arguments[0].value = arguments[1];
arguments[0]
表示传递给JavaScript脚本的第一个参数(即element
),通过将value
属性设置为arguments[1]
来输入文本。
element = browser.find_element(By.ID,'input_id')
text = 'Hello, World!'
browser.execute_script('arguments[0].value = arguments[1];', element, text)
(4)拖动元素
- 首先,获取源元素和目标元素的位置信息,然后创建鼠标事件并分发到源元素上,模拟鼠标按下、移动和松开的动作,从而实现拖动操作。
# 使用JavaScript拖动一个可拖动的元素到目标位置
source_element = browser.find_element(By.ID,'source_element_id')
target_element = browser.find_element(By.ID,'target_element_id')
browser.execute_script('''
var source = arguments[0], target = arguments[1];
var offsetX = target.getBoundingClientRect().left - source.getBoundingClientRect().left;
var offsetY = target.getBoundingClientRect().top - source.getBoundingClientRect().top;
var event = new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window });
source.dispatchEvent(event);
event = new MouseEvent('mousemove', { bubbles: true, cancelable: true, view: window, clientX: offsetX, clientY: offsetY });
source.dispatchEvent(event);
event = new MouseEvent('mouseup', { bubbles: true, cancelable: true, view: window });
source.dispatchEvent(event);
''', source_element, target_element)
(5)获取元素属性
- 这里使用
getAttribute
方法传递属性名参数来返回对应的属性值。
# 使用JavaScript获取元素的属性值
element = browser.find_element(By.ID,'element_id')
attribute_value = browser.execute_script('return arguments[0].getAttribute("attribute_name");', element)
print(attribute_value)
(6)案例
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
# 初始化WebDriver
browser = webdriver.Chrome()
# 打开京东网页
browser.get('https://www.baidu.com/')
# 获取当前百度热搜所在的标签
top_search = browser.find_element(By.CLASS_NAME, "c-font-medium")
time.sleep(2)
# 获取当前标签的 class 属性值
attribute_value = browser.execute_script('return arguments[0].getAttribute("class");', top_search)
print(attribute_value) # title-text c-font-medium c-color-t
# 获取当前输入框标签
input_text = browser.find_element(By.ID, "kw")
# 定义搜索文本
search_text = "Python"
# 将搜索文本添加到搜索框内
browser.execute_script('arguments[0].value = arguments[1];', input_text, search_text)
time.sleep(2)
# 获取当前搜索框标签
search_btn = browser.find_element(By.ID, "su")
# 点击搜索按钮
browser.execute_script('arguments[0].click();', search_btn)
time.sleep(2)
browser.close()
(6)页面等待
- 如果网站采用了动态html技术,那么页面上的部分元素出现时间便不能确定,
- 这个时候就可以设置一个等待时间,强制等待指定时间
- 等待结束之后进行元素定位,如果还是无法定位到则报错
(1)强制等待
- 也叫线程等待, 通过线程休眠的方式完成的等待
- 如等待5秒: Thread sleep(5000)
- 一般情况下不太使用强制等待,主要应用的场景在于不同系统交互的地方。
import time
time.sleep(n) # 阻塞等待设定的秒数之后再继续往下执行
(2)显式等待
- 也称为智能等待,针对指定元素定位指定等待时间
- 在指定时间范围内进行元素查找,找到元素则直接返回
- 如果在超时还没有找到元素,则抛出异常
- 显示等待是 selenium 当中比较灵活的一种等待方式,他的实现原理其实是通过 while 循环不停的尝试需要进行的操作。
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 设置WebDriver等待时间为最多10秒,每隔0.5秒检查一次
#每隔 0.5s 检查一次(默认就是 0.5s)
# 最多等待 10 秒,否则报错。
#如果定位到元素则直接结束等待
#如果在10秒结束之后仍未定位到元素则报错
wait = WebDriverWait(chrome, 10, 0.5)
# 等待页面中的元素"J_goodsList"出现
wait.until(EC.presence_of_element_located((By.ID, 'J_goodsList'))
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
chrome = webdriver.Chrome()
# 携带 cookie 访问京东
cookies = ""
cookie_dict = {cookie.split("=", 1)[0].strip(): cookie.split("=", 1)[1].strip() for cookie in
[cookie for cookie in cookies.split(";")]}
chrome.get('https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA')
for name, value in cookie_dict.items():
chrome.add_cookie({'name': name, 'value': value})
chrome.get('https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA')
# 设置WebDriver等待时间为最多10秒,每隔0.5秒检查一次
# 每隔 0.5s 检查一次(默认就是 0.5s)
# 最多等待 10 秒,否则报错。
# 如果定位到元素则直接结束等待
# 如果在10秒结束之后仍未定位到元素则报错
wait = WebDriverWait(chrome, 10, 0.5)
# 等待页面中的元素"J_goodsList"出现
wait.until(EC.presence_of_element_located((By.ID, 'J_goodsList')))
(3)隐式等待
- 隐式等待设置之后代码中的所有元素定位都会做隐式等待
- 通过implicitly Wait完成的延时等待,注意这种是针对全局设置的等待
- 如设置超时时间为10秒,使用了implicitlyWait后
- 如果第一次没有找到元素,会在10秒之内不断循环去找元素
- 如果超过10秒还没有找到,则抛出异常
- 隐式等待比较智能,它可以通过全局配置,但是只能用于元素定位
driver.implicitly_wait(10)
# 在指定的n秒内每隔一段时间尝试定位元素,如果n秒结束还未被定位出来则报错
(4)总结
显示等待
原理:显示等待,就是明确要等到某个元素的出现或者是某个元素的可点击等条件,等不到,就一直等,除非在规定的时间之内都没找到,就会跳出异常Exception
(简而言之,就是直到元素出现才去操作,如果超时则报异常)
隐式等待
原理:隐式等待,就是在创建driver时,为浏览器对象创建一个等待时间,这个方法是得不到某个元素就等待一段时间,直到拿到某个元素位置。
注意:在使用隐式等待的时候,实际上浏览器会在你自己设定的时间内部断的刷新页面去寻找我们需要的元素
(7)cookie操作
(1)获取cookie
get_cookies()
tag_url = 'https://dig.chouti.com/'
browser = webdriver.Chrome()
cookies = browser.get_cookies()
(2)添加cookie
add_cookie()
- 用for循环给browser对象添加cookie,然后刷新即登录
def read_cookie():
BASE_DIR = os.path.dirname(__file__)
cookie_path = os.path.join(BASE_DIR, 'cookies.json')
with open(cookie_path, 'r', encoding='utf8') as f:
cookies = json.load(f)
return cookies
# 测试cookie是否有效
def test_cookie():
browser.get(tag_url)
cookie = read_cookie()
for ck in cookie:
browser.add_cookie(ck)
browser.refresh()
time.sleep(3)
(3)删除cookie
delete_cookie(name)
: 删除指定键的cookiedelete_all_cookies()
: 删除所有的cookie
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("https://example.com")
# 删除名为 "cookie_name" 的 cookie
browser.delete_cookie("cookie_name")
browser.quit()
(4)cookie中键名的含义
name cookie的名称
value cookie对应的值,动态生成的
domain 服务器域名
expiry Cookie有效终止日期
path Path属性定义了Web服务器上哪些路径下的页面可获取服务器设置的Cookie
httpOnly 防脚本攻击
secure 在Cookie中标记该变量,表明浏览器和服务器之间的通信协议为加密认证协议。
(8)无头浏览器
- 无头浏览器,即 Headless Browser,是一种没有界面的浏览器。
- 它拥有完整的浏览器内核,包括 JavaScript 解析引擎、渲染引擎等。
- 与普通浏览器最大的不同是,无头浏览器执行过程中看不到运行的界面,但是我们依然可以用 GUI 测试框架的截图功能截取它执行中的页面。
- 无头浏览器主要应用在: GUI 自动化测试、页面监控、网络爬虫以及没有桌面的linux系统中。
(1)浏览器的渲染机制
- 这里总结一下浏览器如何渲染网页,简单的说浏览器的渲染机制可以分为五步:
- 第一步:解析html,构建DOM树
- 第二步:解析CSS,生成CSSOM树
- 第三步:合并dom树和css规则树,生成render渲染树
- 第四步:根据render渲染树进行布局
- 第五步:调用GPU对渲染树进行绘制,合成图层,显示在屏幕上
- 在这里就可以看出,当无头浏览器不做渲染时,速度显然会提升很多!
(2)案例
- 让浏览器在后台跑
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
# 创建 ChromeOptions 实例
chrome_options = Options()
# 指定浏览器分辨率
chrome_options.add_argument('window-size=1920x3000')
# 规避 bug,需要加上这个属性
chrome_options.add_argument('--disable-gpu')
# 隐藏滚动条,应对特殊页面
chrome_options.add_argument('--hide-scrollbars')
chrome_options.add_argument('blink-settings=imagesEnabled=false')
# 不加载图片,提升速度
chrome_options.add_argument('--headless')
# 无头模式,不提供可视化页面。在 Linux 下,如果系统不支持可视化,不加这条会启动失败
# chrome_options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
# 手动指定
# 创建 Chrome WebDriver 实例,并传入配置参数
driver = webdriver.Chrome(options=chrome_options)
driver.get('https://www.baidu.com') # 打开百度首页
# 在页面源代码中查找关键词 'hao123' 并打印结果
print('hao123' in driver.page_source)
# True
driver.close() # 关闭浏览器窗口,释放资源
Selenium框架的更多相关文章
- selenium框架与chrome浏览器的不兼容问题
在一次偶然的情况下,在chrome上用selenium框架去抓取某个id为XX的页面元素,使用WebDriver的findElement().click()方法进行点击,原来在firefox浏览器运行 ...
- 《一头扎进》系列之Python+Selenium框架设计篇1-什么是自动化测试框架-价值好几K的框架,不看别后悔,过时不候
1. 什么是自动化测试框架 在了解什么是自动化测试框架之前,先了解一下什么叫框架?框架是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法:另一种定义认为,框架是可被应用开发者定制的 ...
- 《一头扎进》系列之Python+Selenium框架设计篇3- 价值好几K的框架,狼来了,狼来了....,狼没来,框架真的来了
1. 简介 前边宏哥一边一边的喊框架,就如同一边一边的喊狼来了!狼来了!.....这回是狼没有来,框架真的来了.从本文开始宏哥将会一步一步介绍,如何从无到有地创建自己的第一个自动化测试框架.这一篇,我 ...
- 《一头扎进》系列之Python+Selenium框架设计篇4- 价值好几K的框架,呵!这个框架有点意思啊
1.简介 前面文章,我们实现了框架的一部分功能,包括日志类和浏览器引擎类的封装,今天我们继续封装一个基类和介绍如何实现POM.关于基类,是这样定义的:把一些常见的页面操作的selenium封装到bas ...
- 《一头扎进》系列之Python+Selenium框架设计篇5 - 价值好几K的框架,哎呦!这个框架还真有点料啊!!!
1. 简介 其实,到前面这一篇文章,简单的Python+Selenium自动化测试框架就已经算实现了.接下来的主要是介绍,unittest管理脚本,如何如何加载执行脚本,再就是采用第三方插件,实现输出 ...
- 快速构建一个完整的Selenium框架
今天跟大家细讲如何构建一个完整的selenium框架,当你学会了这一篇你就也可以说自己会selenium自动化测试了. 1.新建项目,结构如图: 注意:整个项目除了最外层的是文件夹,其他的都是包(pa ...
- python3+selenium框架设计04-封装测试基类
在完成了日志类封装之后,那我们就要对测试基类进行实现,在其中对一些请求再次封装,在项目下新建一个framework文件夹,在文件夹下新建Base_Page.py文件,这是用来写测试基类的文件.在项目下 ...
- python3+selenium框架设计02-自动化测试框架需要什么
什么是自动化测试框架 自动化测试框架能够提供便利给用户高效完成一些事情,比如,结构清晰开发脚本,多种方式.平台执行脚本,良好的日志和报告去跟踪脚本执行结果. 关于自动化测试框架的定义有很多,在我大致理 ...
- python3+selenium框架设计01-Page Object
页面对象模型Page Object Modal是一种脚本设计模型,将页面元素,业务操作分割,当实际页面发生变化的时候,只需要修改页面元素文件,业务操作不需要修改. 具体实现需要先写一个页面公共类,里面 ...
- Python+Selenium框架设计之框架内封装基类和实现POM
原文地址https://blog.csdn.net/u011541946/article/details/70269965 作者:Anthony_tester 来源:CSDN 博客地址https ...
随机推荐
- 保姆级教程——手把手教会你如何在Linux上安装Redis
一.Linux系统安装Redis(7.4.0) 注意: 全程是在root底下操作,当然也可以采用sudo 1.1 安装Redis依赖 Redis是基于C语言编写的,因此首先需要安装Redis所需要的g ...
- $.ajax jsonp parsererror
场景重现 通过$.ajax()发起的跨越请求代码如下: $.ajax({ dataType: "JSONP", type: "GET", url: " ...
- mybatis数据的批量插入
1:xml的配置 <insert id="insertUserBatch"> insert into user(username, birthday, sex, add ...
- SpringBoot3整合SpringSecurity6(一)快速入门
大家好,我是晓凡. 写在前面 不知道小伙伴们在学SpringSecurity过程中有没有和我一样的经历和烦恼. ①看完一篇文章或者一个教程,感觉学会了.但是一到实际项目中就不知道怎么用: ②被Spri ...
- eolinker解决两个变量合并成一个变量提供其他接口使用的方法
特别注意:需要使用全局变量或者预处理前务必阅读本链接https://www.cnblogs.com/becks/p/13713278.html 场景描述:提交订单的接口请求中,有一参数是由商品价格+运 ...
- kettle介绍-Step之Abort
Abort中止介绍 中止步骤用于读取指定行数之后停止读取剩余行数,可以用于调试转换 Step Name:步骤的名称,在单一的转换中,名称必须唯一 Abort threshold:指定行数,转换读取到指 ...
- Web前端入门第 44 问:CSS 循环动画 animation 效果演示
相关属性 @keyframes 定义动画的关键帧序列 animation-name 指定 @keyframes 动画的名称 animation-duration 动画单次循环的持续时间(必需属性,否则 ...
- 1K star!这个开源项目让短信集成简单到离谱,开发效率直接翻倍!
嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 "让简单的事情回归简单的本质" -- SMS4J 项目宣言 SMS4J ...
- Tomcat无法启动报错:'Starting Tomcat v9.5 Server at localhost' has encountered a problem
错误提示 控制台提示 严重: A child container failed during start java.util.concurrent.ExecutionException: org.ap ...
- 代码随想录第二十三天 | Leecode 39. 组合总和、40.组合总和II、131. 分割回文串
Leecode 39. 组合总和 题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 ...