web自动化测试

自动化测试理论

  • UI:User Interface(用户接口-用户界面),主要包括:app、web

  • ui自动化测试:使用工具或代码执行用例的过程

  • 什么样的项目适合做自动化

    1、需要回归测试项目(甲方自营项目、金融、电商)
    2、需求变动不频繁:稳定的模块
    3、项目周期长的项目:(甲方自营项目、6个月以上的外包项目)
    
  • 自动化测试的目的:提高测试效率

自动化测试工具及环境

工具说明

  • 工具
    • QTP:商业、收费、支持UI
    • robot Framework:python扩展库、使用封装好的关键字驱动、半代码水平、支持UI
    • selenium:开源、免费、主流 支持UI
  • selenium介绍

image-20240714125311422

提示:
	1、selenium-grid可以做分布式(批量在不同平台中运行用例),自动化用例较多时、或测试不同浏览器在不同
	平台运行时可以使用。
	2、对页面元素实施自动化测试,主要使用:webdriver

环境搭建

  • 所需环境:python 解释器+pycharm+selenium+浏览器+浏览器驱动

  • selenium

    pip install selenium
    
  • 浏览器驱动

    • chrome:https://registry.npmmirror.com/binary.html?path=chromedriver/
    提示:浏览器驱动大版本必须和浏览器版本一致。
    
  • 使用:

    windows:
    	1、解压下载的驱动,获取到chromedriver.exe
    	2、将chromedriver.exe复制到python.exe所在目录即可(避免再次将chromedriver.exe添加path变量)
    mac:
    	1、解压下载的驱动,获取到chromedriver
    	2、将chromedriver复制到/usr/local/bin目录即可。
    

元素定位

  • 什么是元素定位?

    通过代码调用方法查找元素
    
  • 元素定位方法

    1、id
    2、name
    3、class
    4、tag_name
    5、link_text
    6、partial_link_text
    7、xpath
    8、css
    
  • 步骤

    1、打开谷歌浏览器
    2、输入url
    3、找元素及操作
    4、关闭浏览器
    
    from selenium import webdriver
    from time import sleep
    # 1、打开谷歌浏览器
    driver=webdriver.Chrome()
    # 2、输入url
    driver.get("https://hmshop-test.itheima.net/Home/user/login.html")
    # 3、找元素及操作
    
    # 4、关闭浏览器
    sleep(3)
    driver.quit()
    

id定位

  • 方法:driver.find_element_by_id("id值")

  • 前置:标签必须有id属性

  • 输入方法:元素.send_keys("内容")

  • 示例:

    from selenium import webdriver
    
    from time import sleep
    
    #1、获取浏览器
    driver=webdriver.Chrome()
    #2、打开url
    driver.get("file:///D:/BaiduNetdiskDownload/web%E8%AF%BE%E5%A0%82%E7%B4%A0%E6%9D%90/web/%E6%B3%A8%E5%86%8CA.html")
    #3、查找操作元素
    #用户名->id->driver.find_element_by_id("id")
    #元素.send_keys()输入方法
    driver.find_element_by_id("userA").send_keys("admin")
    #密码
    driver.find_element_by_id("passwordA").send_keys("123456")
    #4、关闭浏览器
    sleep(3)
    driver.quit()
    

name定位

  • 方法:driver.find_element_by_name("name属性值")
  • 前置:标签必须有name属性
  • 特点:当前页面可以重复
  • 提示:由于name属性值可以重复,所以使用时需要查看是否为唯一

class定位

  • 方法:driver.find_element_by_class_name("class属性值")
  • 前置:标签必须有class属性
  • 特点:class属性值可以有多个值

image-20240714164612391

说明:如果标签有多个class值,使用任何一个都可以。如:c11

tag_name定位

  • 说明:根据标签名进行定位
  • 方法:driver.find_element_by_tag_name("标签名")
  • 提示:如果页面存在多个相同标签,默认返回第一个

link_text定位

  • 说明:根据链接文本(a标签)定位
  • 方法:driver.find_element_by_link_name("链接文本")
  • 特点:传入的链接文本,必须全部匹配,不能模糊

partial_link_text定位

  • 说明:根据链接文本(a标签)定位
  • 方法:driver.find_element_by_partial_link_name("链接文本")
  • 特点:传入的链接文本,支持模糊匹配(传入局部文字)

扩展-查找一组元素

  • 说明:返回列表格式,要使用需要添加下标或遍历。
  • 方法:driver.find_elements_by_xxxxx()
  • 提示:八大元素定位方法,都可以使用一组元素定位,如果没有搜索到符合标签,返回空列表。
"""
需求:使用定位一组元素的方法+tag_name 将注册a页面所有信息进行填写
"""
from selenium import webdriver
from time import sleep

#1、获取浏览器
driver=webdriver.Chrome()
#2、打开url
driver.get("file:///D:/BaiduNetdiskDownload/web%E8%AF%BE%E5%A0%82%E7%B4%A0%E6%9D%90/web/%E6%B3%A8%E5%86%8CA.html")
#3、查找操作元素
inputs = driver.find_elements_by_tag_name("input")
inputs[0].send_keys("admin")
inputs[1].send_keys("123456")
inputs[2].send_keys("16612345678")
inputs[3].send_keys("123456@163.com")
#4、关闭浏览器
sleep(3)
driver.quit()
  • 为什么要学习xpath和css?
1、如果标签没有(id\name\class)3个属性,也不是链接标签,只能使用tag_name定位,比较麻烦。
2、方便在工作中查找元素,使用xpath和css比较方便(支持任意属性、层级)来找元素。

Xpath

  • 说明:xpath是xml path简称,使用标签路径来定位。

    • 绝对路径:从根目录开始,逐级查找标签。

    image-20240714210526761

    • 相对路径:从任意层级开始,查找标签。

    image-20240714210543396

  • 策略(方法):

    1、路径
    2、属性
    3、属性与逻辑(多个属性)
    4、属性与层级(路径)
    
  • 方法:driver.find_element_by_xpath("表达式")

  • 练习

    • 需求

      打开注册A.html页面,完成以下操作

      1).使用绝对路径定位用户名输入框,并输入:admin

      2).暂停2s

      3).使用相对路径定位用户名输入框,并输入:123

  • 实现

from selenium import webdriver
from time import sleep

#1、获取浏览器
driver=webdriver.Chrome()
#2、打开url
driver.get("file:///D:/BaiduNetdiskDownload/web%E8%AF%BE%E5%A0%82%E7%B4%A0%E6%9D%90/web/%E6%B3%A8%E5%86%8CA.html")
#3、查找操作元素
#绝对路径
el = driver.find_element_xpath("/html/body/form/div/fieldset/center/p[1]/input")
el.send_keys("admin")
sleep(2)
#清除内容
el.clear()
#相对路径
driver.find_element(By.XPATH,"//p[1]/input").send_keys("123456")
#4、关闭浏览器
sleep(3)
driver.quit()
  • 属性

    • 单属性://*[@属性名="属性值"]
    • 多属性://*[@属性名="属性值" and @属性名="属性值"]
    • 提示:可以使用任何属性。
  • 层级与属性

    • 说明:如果元素现有的属性不能唯一匹配,需要结合层级使用
    • 语法:
      • //父标签/子标签必须为直属子级
      • //父标签[@属性="值"]//后代标签父和后代之间可以跨越元素
    • 扩展
      • 根据显示文本定位://*[text()="文本值"]
      • 属性值模糊匹配://*[contains(@属性名,"属性部分值")]
  • xpath综合练习

image-20240714214201117

from selenium import webdriver
from time import sleep

#1、获取浏览器
driver=webdriver.Chrome()
#2、打开url
driver.get("https://hmshop-test.itheima.net/")
#3、查找操作元素
#点击登录链接 文本
driver.driver.find_element_xpath('//*[text()="登录"]').click()
#输入用户名 属性
driver.driver.find_element_xpath('//*[@placeholder="手机号/邮箱"]').send_keys("13600001111")
#密码 包含
driver.driver.find_element_xpath('//*[contains(@placeholder,"密")]').send_keys("123456")
#验证码 多属性
driver.driver.find_element_xpath('//*[@placeholder="验证码" and @name="verify_code"]').send_keys("8888")
#登录按钮 层级
driver.driver.find_element_xpath("//*[@class='login_bnt']/a").click()

CSS选择器

  • 说明:css选择器是html查找元素的工具

  • 策略:

    1、id选择器
    2、类选择器
    3、标签选择器
    4、属性选择器
    5、层级选择器
    
  • id选择器

    • 语法:#id属性值
    • 前置:标签必须有id属性
  • 类选择器:

    • 语法:.class属性值
    • 前置:标签必须有class属性
  • 标签选择器

    • 语法:标签名
    • 提示:注意标签是否在页面中唯一,否则返回单个或所有
  • 属性选择器

    • 语法:[属性名="属性值"]
    • 属性:标签任意属性都可以
  • 案例

image-20240715085433160

# 用户名 id选择->#id属性值
driver.find_element_by_css_selector("#userA").send_keys("admin")
# 密码 属性选择器->[属性名='属性值']
driver.find_element_by_css_selector("[name='passwordA']").send_keys("123456")
# 电话 类选择器->.class属性值
driver.find_element_by_css_selector(".telA").send_keys("18600000000")
# 确定 标签选择器-标签名
sleep(2)
driver.find_element_by_css_selector("button").click()
  • 层级选择器
    • 父子关系:选择器->选择器如:#p1>input
    • 后代关系:选择器 选择器如:#p1 input
    • 提示:父子关系:选择器使用任何一种css选择器(id选择器、类选择器、属性选择器、标签选择器)都可以

find_element

  • 说明:八种元素定位方法底层使用的查找元素方法都是find_element,通过By不同的值区分定位方式
  • 学习此方法目的:后期为了查找元素方法的封装
  • 示例:
"""
目标:解决find_element使用
场景:后期项目封装中,使用元素查找方法
目的:对后期封装元素查找方法
"""
#3、查找操作元素
driver.find_element(By.ID,"userA").send_keys("admin")
driver.find_element(By.NAME,"passwordA").send_keys("123456")
driver.find_element(By.CLASS_NAME,"telA").send_keys("1360000000")
sleep(2)
driver.find_element(By.TAG_NAME,"button").click()

元素定位总结

image-20240715090845036

结论:
	1、首推css定位,原因执行速度快。
	①如果有ID属性,使用#id
	②没有id属性,使用其他有的属性(能代表唯一的属性)
	③如果属性都代表不了唯一,使用层级
	2、如果css解决不了,使用Xpath

元素操作

1、操作方法
2、获取方法

常用操作方法

元素=driver.find_element()

  • 点击:元素.click()
  • 输入:元素.send_keys(内容)
  • 清空:元素.clear()

获取元素信息

  • 方法

    • 获取大小:元素.size
    • 获取文本元素.text
    • 获取属性:元素.get_attribute('属性名')
    • 元素是否可见:元素.is_displayed()
    • 元素是否可用:元素.is_enabled()
    • 元素是否被选中:元素.is_selected
  • 案例

#获取大小 元素.size
user = driver.find_element(By.CSS_SELECTOR,"#userA").size
print("用户名输入框的大小:",user)
#获取内容 元素.text
a_text=driver.find_element(By.TAG_NAME,"a").text
print("第一个a标签的文本:",a_text)
#获取属性 超链接地址
a_href= driver.find_element(By.TAG_NAME,"a").get_attribute("href")
print("第一个a标签的链接:",a_href)
#判断span标签是否可见 元素.is_displayed
span = driver.find_element(By.TAG_NAME,"span").is_displayed()
print("span是否可见:",span)
#判断取消按钮是否可用 is_enabled
btn_is_enable = driver.find_element(By.CSS_SELECTOR,"#cancelA").is_enabled()
print("取消按钮是否可用:",btn_is_enable)
#旅游是否选中 is_selected
is_selected = driver.find_element(By.CSS_SELECTOR,"#lyA").is_selected()
print("旅游是否被选中:",is_selected)

浏览器操作

浏览器常用api

  • api

image-20240716080534882

image-20240716080636686

  • 案例
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep

#1、获取浏览器
driver=webdriver.Chrome()
#2、打开url
driver.get("file:///D:/BaiduNetdiskDownload/web%E8%AF%BE%E5%A0%82%E7%B4%A0%E6%9D%90/web/%E6%B3%A8%E5%86%8CA%E9%BB%84%E8%89%B2.html")
#3、查找操作元素
#最大化浏览器
driver.maximize_window()
sleep(3)
#设置窗口大小
driver.set_window_size("500","700")
sleep(3)
#设置窗口位置
driver.set_window_position("0","500")
sleep(3)
#点击新浪
driver.find_element(By.PARTIAL_LINK_TEXT,"新浪").click()
sleep(3)
#后退
driver.back()
sleep(3)
#前进
driver.forward()
sleep(3)
#刷新
driver.refresh()
#4、关闭浏览器
sleep(3)
driver.quit()

浏览器常用获取信息api

  • api

image-20240716081504259

重点:
	1、close关闭当前焦点所在窗口
	2、quit关闭的是浏览器
	3、启动哪个窗口,默认焦点就在哪个窗口,如果需要切换到别的窗口,需要调用api方法切换。

image-20240716081557078

案例

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep

#1、获取浏览器
driver=webdriver.Chrome()
#2、打开url
driver.get("file:///D:/BaiduNetdiskDownload/web%E8%AF%BE%E5%A0%82%E7%B4%A0%E6%9D%90/web/Register.html")
#3、查找操作元素
#最大化浏览器
driver.maximize_window()
#获取当前窗口标题
print("当前窗口title:",driver.title)
#获取当前窗口url
print("当前窗口url:",driver.current_url)
sleep(3)
driver.find_element(By.PARTIAL_LINK_TEXT,"注册A网页").click()
#获取当前窗口标题
print("当前窗口title:",driver.title)
#获取当前窗口url
print("当前窗口url:",driver.current_url)
sleep(3)
#关闭当前窗口
driver.close()
#4、关闭浏览器
sleep(3)
driver.quit()

页面交互操作

下拉框

  • 需求

image-20240716082629957

  • 方式
1、使用css或xpath(推荐)
2、使用专属select类
  • 方式1
# 点击广州
driver.find_element(By.CSS_SELECTOR,"[value='gz']").click()
sleep(2)
# 点击上海
driver.find_element(By.CSS_SELECTOR,"[value='sh']").click()
sleep(2)
# 点击北京
driver.find_element(By.CSS_SELECTOR,"[value='bj']").click()
  • 方式2(了解)
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
#1、获取浏览器
driver=webdriver.Chrome()
#2、打开url
driver.get("file:///D:/BaiduNetdiskDownload/web%E8%AF%BE%E5%A0%82%E7%B4%A0%E6%9D%90/web/%E6%B3%A8%E5%86%8CA%E9%BB%84%E8%89%B2.html")

#使用select类来实现
#1、定位下拉框元素 select
el=driver.find_element(By.CSS_SELECTOR,"#selectA")
#实例化select对象
select = Select(el)
#3、使用下标定位广州
select.select_by_index(2)
sleep(2)
# 使用value定位上海
select.select_by_value("sh")
sleep(2)
#使用文本定位北京
select.select_by_visible_text("A北京")
#4、关闭浏览器
sleep(3)
driver.quit()

弹出框

  • 为什么要处理弹窗?
如果页面操作过程中,有弹窗出现,不处理,无法继续对页面操作。
  • 弹窗类型?
1、js原生弹窗(警告框、输入框、提示框)必须处理
2、开发使用标签自定义弹窗效果(不用处理,正常操作即可。)
  • 如何处理?
1、获取弹窗对象
2、点击同意或取消方法
  • 示例
#点击弹窗
driver.find_element(By.ID,"alerta").click()
sleep(2)
#获取弹窗对象
el = driver.switch_to.alert
#处理弹窗 同意/取消
# el.dismiss()# 取消
print("弹出文本:",el.text)
el.accept() #同意
sleep(2)
#输入用户名
driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")

滚动条

  • 为什么要操作滚动条?
有些页面场景,必须滚动条拉到最底下才能做某事
如:注册页面,阅读完需求,协议才能勾选,此时就必须拖到滚动条。
  • 步骤
1、定义js语句
2、调用执行JS方法
  • 示例
#设置窗口大小
driver.set_window_size(500,500)
sleep(2)
#js->向下滑动10000像素
# js_down="window.scrollTo(0,10000)"
#动态执行滑到底部 向下滑动滚动条高度
#js(0,10000)第1个0为水平滚动条
js_down="window.scrollTo(0,document.body.scrollHeight)"
#执行js方法
driver.execute_script(js_down)
sleep(2)
#js->向上
js_top="window.scrollTo(0,0)"
driver.execute_script(js_top)

鼠标操作

  • 方法

image-20240716215405016

1、双击方法
2、右击方法
3、悬停
4、拖拽
  • 示例

image-20240716215609507

from selenium.webdriver import ActionChains
#获取ActionChains对象
action =ActionChains(driver)
#练习1
#查找注册按钮
el= driver.find_element(By.CSS_SELECTOR,"button")
sleep(2)
#调用悬停方法
action.move_to_element(el).perform()

#练习2
username =driver.find_element(By.CSS_SELECTOR,"#userA")
#右击
action.context_click(username).perform()

#练习3
driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")
sleep(3)
#双击
action.double_click(username).perform()
#拖拽
#获取ActionChains对象
action = ActionChains(driver)
div1 = driver.find_element(By.CSS_SELECTOR,"#div1")
div2 = driver.find_element(By.CSS_SELECTOR,"#div2")
action.drag_and_drop(div1,div2).perform()

其他重要API

  • 什么是等待?
代码执行过程中,第一次未找到元素,先不抛出异常。激活等待时间,在等待过程中如果找到元素就执行。
  • 为什么要等待?
由于网络或配置原因,导致元素未加载出来,而代码已执行,会触发异常。
  • 元素等待类型
1、隐式等待
2、显式等待
3、强制等待--->time.sleep(秒)

隐式等待

  • 说明:针对全部元素生效
  • 方法:driver.implicitly_wait(秒)
  • 提示:在项目中,如果未封装自动化框架时,推荐使用。

显式等待

  • 说明:针对单个元素生效,可用修改查找频率和超时时间
  • 特点:查找并返回元素
  • 用法
from selenium.webdriver.support.wait import WebDriverWait
#2、显式等待->返回查找到的元素
el = WebDriverWait(driver,10,0.5).until(lambda x:x.find_element(By.CSS_SELECTOR,"#userA"))
el.send_keys("admin")

强制等待

  • 语法:sleep(10)
  • 提示:执行到这句必须等待10s,不灵活。
  • 示例:
from time import sleep
sleep(10)

等待对比

image-20240716222538626

操作frame框架的元素

  • frame(iframe) 标签作用–是什么

    在页面中加载另一个页面
    
  • 为什么处理iframe(frame)?

image-20240717085758153

焦点默认在启动页面,如果不处理iframe,无法操作iframe嵌入的页面元素。
  • 如何处理?

    • 步骤
    1、切换到iframe  driver.switch_to.frame(iframe元素)
    2、操作元素
    3、回到默认页面 driver.switch_to.default_content()
    
  • 示例

image-20240717090037812

#获取注册A iframe元素
A = driver.find_element(By.CSS_SELECTOR,"#idframe1")
#1、切换到A
driver.switch_to.frame(A)
#2、注册A操作
driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")

#3、回到默认目录,注册实例.html
driver.switch_to.default_content()

#4、获取注册B iframe元素
B = driver.find_element(By.CSS_SELECTOR,"#idframe2")
#5、切换到B
driver.switch_to.frame(B)

#注册B操作
driver.find_element(By.CSS_SELECTOR,"#userB").send_keys("admin")

切换多窗口

  • 什么是多窗口?

image-20240717091354395

通过a链接,如果打开方式新窗口打开,那么就会出现多窗口。
  • 为什么要切换?
selenium默认启动时,所有焦点都在启动窗口,那么意味着无法操作其他窗口的标签。
  • 如何切换?

    • 步骤:

      1、获取窗口句柄 driver.window_handles
      2、使用句柄切换窗口driver.switch_to.window(handle)
      句柄:窗口的唯一标识符
      
    • 示例:

      """
      为什么要处理多窗口?--selenium默认焦点在启动窗口,要操作其他窗口必须处理。
      需求:1、打开注册示例页面
           2、点击注册A网页链接
           3、填写注册A网页内容
      """
      print("操作之前所有窗口的句柄:",driver.window_handles)
      driver.find_element(By.LINK_TEXT,"注册A网页").click()
      handles=driver.window_handles
      print("操作之后所有窗口的句柄:",driver.window_handles)
      #重点:切换窗口
      driver.switch_to.window(handles[1])
      #填写注册A网页 用户名
      driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")
      
  • 多窗口之间切换工具封装

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
#1、获取浏览器
driver=webdriver.Chrome()
#2、打开url
driver.get("file:///D:/BaiduNetdiskDownload/web%E8%AF%BE%E5%A0%82%E7%B4%A0%E6%9D%90/web/Register.html")

"""
为什么要处理多窗口?--selenium默认焦点在启动窗口,要操作其他窗口必须处理。
需求:
    如何随心所欲切换窗口?
思路:
    1、获取所有窗口句柄
    2、切换窗口
    3、获取当前所在窗口的title
    4、判断title是否为需要的窗口
    5、执行代码
需求:
    1、打开注册示例页面
    2、点击注册A页面 注册B页面
    3、在A网页和B网页中,输入admin
"""
def switch_window(title):
    #1、获取所有窗口句柄
    handles = driver.window_handles
    #2、遍历句柄进行切换
    for handle in handles:
        #操作
        driver.switch_to.window(handle)
        #获取当前窗口title,并且判断是否自己需要的窗口
        if driver.title == title:
            #操作代码
            return "已经找到{}窗口,并且已切换成功".format(title)

title_A = "注册A"
title_B = "注册B"
#打开注册A网页和B网页
driver.find_element(By.LINK_TEXT,"注册A网页").click()
driver.find_element(By.LINK_TEXT,"注册B网页").click()
#填写注册A网页 用户名
switch_window(title_A)
driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")
#填写注册B网页 用户名
switch_window(title_B)
driver.find_element(By.CSS_SELECTOR,"#userB").send_keys("admin")

sleep(13)
driver.quit()
  • 小结

如果定位不到元素怎么办?

image-20240717221143173

截图

  • 什么是截图?
当前ui页面,截图保存
  • 为什么要截图?
出错后,方便查看直观错误原因。
  • 如何截图?
driver.get_screenshot_as_file("XXX.png")
  • 扩展-图片命名添加时间戳

image-20240717222234423

driver.get_screenshot_as_file("error_{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")))
  • 示例:
driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")
driver.find_element(By.CSS_SELECTOR,"#passwordA").send_keys("123456")
driver.find_element(By.CSS_SELECTOR,"#telA").send_keys("166123456")
driver.find_element(By.CSS_SELECTOR,"#emailA").send_keys("123@qq.com")
#截图
driver.get_screenshot_as_file("register.png")
driver.get_screenshot_as_file("error_{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")))

验证码处理

  • 处理方式:
1、去除验证码
2、使用万能验证码
3、使用图片识别技术(识别效率低)
4、使用cookie
  • cookie
  • 说明:由服务器生成,存储在客户端的登录凭证。
  • 使用:
1、获取cookie # 获取所有driver.get_cookies()
2、添加cookie # driver.add_cookie(data)
  • 示例
from selenium import webdriver
from time import sleep

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
driver.maximize_window()
#添加cookie
data={"name":"BDUSS","value":"QzeEJKQVV3lZ5anh1QlNDWG43YjltjD5rnUyt4yAOdgmGbnYJhmQ1"}
driver.add_cookie(data)
#暂停5秒
sleep(5)
#刷新
driver.refresh()
sleep(3)
driver.quit()
  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值