浏览器自动化脚本 Selenium WebDriver(Java)常用 API 汇总

 

一、Selenium Webdriver 常用的API

(一)引入依赖

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>

开始:

    public static void main(String[] args) throws InterruptedException {
        ChromeOptions options = new ChromeOptions();
        //允许任何来源的远程连接,这样可以避免一些跨域问题。
        options.addArguments("--remote-allow-origins=*");
        //初始化 chrome 浏览器 driver 对象
        WebDriver webDriver = new ChromeDriver(options);
        // 访问指定网页
        webDriver.get("https://juejin.cn");
        //开始操作页面
        //……
    }

其它浏览器:

WebDriver driver = new FirefoxDriver();  // Firefox浏览器
 
WebDriver driver = new EdgeDriver();  // Edge浏览器
 
WebDriver driver = new InternetExplorerDriver();  // Internet Explorer浏览器

……

(二)元素的定位

要想操作一个对象,首先应该识别这个对象。通过下面的 API,可以获取页面上的标签对象,从而来操作它们。

1.css选择器定位

css选择器定位,在css中有标签选择器、类选择器、id选择器、后代选择器、子选择器、并集选择器……它们对应的语法在在这里也适用。

    public static void main(String[] args) throws InterruptedException {
        
        ChromeOptions options = new ChromeOptions();
        //允许任何来源的远程连接,这样可以避免一些跨域问题。
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        // 访问指定网页
        webDriver.get("https://juejin.cn");
        //css 选择器 方式1:id选择
        WebElement element = webDriver.findElement(By.cssSelector("#elementId"));
        //css 选择器 方式2:类选择
        WebElement element2 = webDriver.findElement(By.cssSelector(".elementClass"));
        //css 选择器 方式3:后代选择
        WebElement element2 = webDriver.findElement(By.cssSelector(".elementClass1 .elementClass2……"));
        //其它方式
        ……
    }

案例:我想要用webDriver在掘金主页搜索框中输入“selenium”并点击搜索。

  1. 先看掘金主页源码中搜索框、搜索按钮的标签属性。

image.png

image.png

  1. 代码
public static void main(String[] args) {
    ChromeOptions options = new ChromeOptions();
    //允许任何来源的远程连接,这样可以避免一些跨域问题。
    options.addArguments("--remote-allow-origins=*");
    WebDriver webDriver = new ChromeDriver(options);
    // 访问指定网页
    webDriver.get("https://juejin.cn");
    //获取搜索框
    WebElement input = webDriver.findElement(By.cssSelector(".search-input"));
    //输入值
    input.sendKeys("java");
    //获取搜索按钮
    WebElement seach = webDriver.findElement(By.cssSelector(".seach-icon-container"));
    //点击该元素
    seach.click();
}

屏幕录制-2023-10-02-185549.gif

为了简洁,文章后面就不放查找标签class属性的截图了,知道怎么查找就行了。

2.id 定位

这个跟 css选择器定位 类似,可以作为它的简便写法

webDriver.findElement(By.id("页面元素的id值"));

3.name 定位

如果这个元素有name属性,并且元素的name命名在整个页面是唯一的,那么我们可以用name来定位这个 元素。

webDriver.findElement(By.name("页面元素的name值"));

4.className、tagName 定位

className就是根据类名字选择,tagName是根据标签名选择。

webDriver.findElement(By.className("class的名字")); 
webDriver.findElement(By.tagName("标签的名字"));
5.linkText定位

对一个文字链接进行定位,我们可以通过链接内容,也就是 link text 来定位。

//获取链接元素

WebElement link = webDriver.findElement(By.linkText("链接文本"));

自动进入首页的“后端”页面

    public static void main(String[] args) {
        ChromeOptions options = new ChromeOptions();
        //允许任何来源的远程连接,这样可以避免一些跨域问题。
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        // 访问指定网页
        webDriver.get("https://juejin.cn");
        //获取链接元素
        WebElement link = webDriver.findElement(By.linkText("后端"));
        //点击元素
        link.click();
    }

image.png

6.partialLinkText定位

只用链接的一部分文字进行匹配。

//获取带“text”的链接
WebElement link = webDriver.findElement(By.partialLinkText("text"));
//获取所有的带“text”的链接
List<WebElement> articles =  webDriver.findElements(By.partialLinkText("text"));

注意,这里适用的是findElements,而不是findElement。当获取的元素有多个的时候就使用findElements

7.xpath 定位

xpath表达式:XPath 语法 | 菜鸟教程 (runoob.com)

webDriver.findElement(By.xpath("XPath定位表达式"));

XPath 是一种在 XML 文档中定位元素的语言。因为 HTML 可以看做 XML 的一种实现,所以可以使用这种语言在 web 应用中定位元素。

表达式描述
nodename选取此节点的所有子节点。
/从根节点选取(取子节点)。
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置(取子孙节点)。
.选取当前节点。
..选取当前节点的父节点。
@选取属性。
通配符描述
*匹配任何元素节点。
@*匹配任何属性节点。
node()匹配任何类型的节点。

比如://form//span[1]/input。表示选择文档中所有的 <form> 元素,然后在每个 <form> 元素内部找到第一个 <span> 元素,然后再在这个 <span> 元素内部选择一个 <input> 元素。

可以在页面中快速地获取xpath,就以搜索框为例:

image.png

WebElement element1 = webDriver.findElement(By.xpath("//*[@id=\"juejin\"]/div[1]/div[1]/header/div/nav/ul/ul/li[1]/ul/li[1]/form/input"));

(三)操作测试对象

定位只是第一步,定位之后需要对这个元素进行操作。它们都是 WebElement 接口的方法。

  • sendKeys():模拟键盘向输入框里输入内容。
  • click():用于单击一个元素,前提是它是可以被单击的对象。
  • getSize():返回元素的尺寸。
  • getText():获取元素的文本。
  • getAttribute():获得属性的值。
  • isDisplayed():查看该元素是否用户可见,返回值为布尔值。
  • submit():用于提交表单,前提必须得有<form>标签。
  • clear():用于清除文本输入框中的内容。

(四)元素等待方式

案例:百度搜索,在搜索框中输入“软件测试”,统计当前页显示出来多少词条。

    public static void main(String[] args) {
        ChromeOptions options = new ChromeOptions();
        //允许任何来源的远程连接,这样可以避免一些跨域问题。
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        webDriver.get("https://baidu.com");
        //css 选择器,选择输入框
        WebElement input = webDriver.findElement(By.cssSelector("#kw"));
        //输入软件测试
        input.sendKeys("软件测试");
        //点击搜索按钮
        webDriver.findElement(By.cssSelector("#su")).click();
        //获取词条
        List<WebElement> aEms = webDriver.findElements(By.cssSelector("a em"));
        //查看词条数量
        System.out.println(aEms.size());
    }

结果:

image.png

这里的结果是0,因为程序还没等浏览器页面加载完 就执行完了,下面就是解决办法。

1.使用 sleep()

直接使用Thread.sleep()使当前的线程睡眠。

public static void main(String[] args) throws InterruptedException {
    ChromeOptions options = new ChromeOptions();
    //允许任何来源的远程连接,这样可以避免一些跨域问题。
    options.addArguments("--remote-allow-origins=*");
    WebDriver webDriver = new ChromeDriver(options);
    webDriver.get("https://baidu.com");
    //css 选择器,选择输入框
    WebElement input = webDriver.findElement(By.cssSelector("#kw"));
    //输入软件测试
    input.sendKeys("软件测试");
    //点击搜索按钮
    webDriver.findElement(By.cssSelector("#su")).click();
    //睡眠 1 秒
    Thread.sleep(1000);
    //获取所有的 a em 元素,这里也就是词条
    List<WebElement> aEms = webDriver.findElements(By.cssSelector("a em"));
    System.out.println(aEms.size());
}

结果:

image.png

这时就把当前页面的词条全获取了。但是用sleep有一个缺点,就是无法把握时间点。如果时间短了则元素获取不完整,如果长了就需要阻塞很长时间,效率低下。好在webDriver提供了API来解决这些问题。

2.隐式等待

Web驱动程序在每次查找元素时都等待一定的时间,直到找到元素或者超时为止隐式等待只需要设置一次,就会对整个会话生效。隐式等待的优点是简单易用,缺点是不能针对特定的元素或条件进行灵活的调整。隐式等待可以通过如下代码实现:

……
WebDriver webDriver = new ChromeDriver();
//全局的隐式等待
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
……
    public static void main(String[] args) {
        ChromeOptions options = new ChromeOptions();
        //允许任何来源的远程连接,这样可以避免一些跨域问题。
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        //设置全局隐式等待,最长等待时间为 5 秒
        webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        webDriver.get("https://baidu.com");
        //css 选择器,选择输入框
        WebElement input = webDriver.findElement(By.cssSelector("#kw"));
        //输入软件测试
        input.sendKeys("软件测试");
        //点击搜索按钮
        webDriver.findElement(By.cssSelector("#su")).click();
        //获取元素
        List<WebElement> aEms = webDriver.findElements(By.cssSelector("a em"));
        System.out.println(aEms.size());
    }

结果:

image.png

3.显示等待

显示等待可以对一个元素进行等待,比隐式等待更灵活。

语法:

WebDriver webDriver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(webDriver, 5, 1);
WebElement elem = wait.until(ExpectedConditions.presenceOfElementLocated(/* By选择 */By.id("元素id")));

对于第二行代码:

  • webDriver:浏览器驱动
  • 5:最长超时时间(默认以秒为单位)
  • 1:检测的的间隔时间

第三行代码:

ExpectedConditions 它包含了一系列的预定义条件,用于等待页面上的元素出现或者满足特定的条件。

presenceOfElementLocated方法会等待页面上的一个元素出现,直到它被找到或者超时。这个元素的ID是"元素id"。如果元素被找到,该方法会返回一个WebElement对象,然后这个对象会被赋值给elem变量。这个WebElement对象可以用来执行其他的操作,比如点击、输入文本等等。如果元素没有被找到,该方法会抛出一个TimeoutException异常。

ExpectedConditions的其它方法(部分):

方法描述
presenceOfAllElementsLocatedBy(By locator)等待一组元素根据指定的定位器在页面 DOM 中出现。条件成立,当元素列表至少包含一个元素或元素列表为空时。
elementToBeClickable(By locator)等待元素可以被单击,通常用于等待按钮或链接可点击。
visibilityOfElementLocated(By locator)等待元素在页面上可见,通常用于等待元素可见后执行操作。
invisibilityOfElementLocated(By locator)等待元素在页面上不可见,通常用于等待元素消失后执行操作。
textToBePresentInElement(By locator, String text)等待特定文本出现在元素中。
titleIs(String title)等待页面标题与给定的标题完全匹配。
titleContains(String partialTitle)等待页面标题包含给定的部分标题。
alertIsPresent()等待警告框出现。
frameToBeAvailableAndSwitchToIt(By frameLocator)等待并切换到指定的 iframe。

回到案例:

public static void main(String[] args){
    ChromeOptions options = new ChromeOptions();
    //允许任何来源的远程连接,这样可以避免一些跨域问题。
    options.addArguments("--remote-allow-origins=*");
    WebDriver webDriver = new ChromeDriver(options);
    webDriver.get("https://baidu.com");
    // 初始化显式等待条件
    WebDriverWait wait = new WebDriverWait(webDriver, 5, 1);
    //css 选择器,选择搜索框
    WebElement input = webDriver.findElement(By.cssSelector("#kw"));
    //输入软件测试
    input.sendKeys("软件测试");
    //点击搜索按钮
    webDriver.findElement(By.cssSelector("#su")).click();
    //校验
    //1.找到搜索结果
    List<WebElement> aEms = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("a em")));
    System.out.println(aEms.size());
}

(五)浏览器的操作

1.浏览器启动的窗口大小
  • webdriver.manage().window().maximize();窗口最大化
  • webdriver.manage().window().setSize(new Dimension(480, 800));设置窗口宽高
2.浏览器前进后退刷新
  • webdriver.navigate().back(); 后退
  • webdriver.navigate().forward(); 前进
  • webdriver.navigate().refresh(); 刷新
3.关闭浏览器
  • webdriver.quit() 关闭整个浏览器
  • webdriver.close() 关闭当前页面

(六)使用 JS 代码

Selenium 提供了 API 来执行 JS 代码。

JavascriptExecutor js = (JavascriptExecutor) webDriver;
js.executeScript("js代码");
    public static void main(String[] args) throws InterruptedException {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        //窗口最大化
        webDriver.manage().window().maximize();
        //隐式等待
        webDriver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
        //打开百度
        webDriver.get("https://baidu.com");
        //执行 js 代码
        JavascriptExecutor js = (JavascriptExecutor) webDriver;
        js.executeScript("alert('你好')");
    }

image.png

  • 滚动条:
JavascriptExecutor js = (JavascriptExecutor) webDriver;
js.executeScript("document.documentElement.scrollTop= x ");//x 表示文档顶部距离视口顶部的距离
//方式2:
//x 参数表示水平的左间距;
//y 参数表示垂直的上边距。
js.executeScript("window.scrollTo(x,y);");

(七)模拟键盘操作

sendKeys()方法也可以模拟键盘操作,例如 sendKeys(Keys.CONTROL, 'a') 表示按下 Ctrl+A 组合键。

方法描述
Keys.ARROW_DOWN按下向下箭头键。
Keys.ARROW_UP按下向上箭头键。
Keys.ARROW_LEFT按下向左箭头键。
Keys.ARROW_RIGHT按下向右箭头键。
Keys.ENTER按下回车键。
Keys.RETURN按下回车键(与 ENTER 类似)。
Keys.TAB按下制表键。
Keys.ESCAPE按下 ESC 键。
Keys.SPACE按下空格键。
Keys.BACK_SPACE按下退格键。
Keys.DELETE按下删除键。
Keys.HOME按下 Home 键。
Keys.END按下 End 键。
Keys.PAGE_UP按下 Page Up 键。
Keys.PAGE_DOWN按下 Page Down 键。
Keys.CONTROL按下 Ctrl 键。
Keys.SHIFT按下 Shift 键。
Keys.ALT按下 Alt 键。
Keys.F1, Keys.F2, ... Keys.F12按下 F1 到 F12 键。
sendKeys(CharSequence...keysToSend)模拟按下多个键的组合,例如 sendKeys(Keys.CONTROL, "a") 表示按下 Ctrl+A 组合键。
Keys.NULL表示空键,通常用于清除已有的键盘操作。

(八)模拟鼠标操作

Actions类可以帮助我们实现鼠标操作,Actions类的方法是用来创建一系列的操作,但是不会立即执行,而是存放在一个队列中。当调用perform()方法时,队列中的操作才会按顺序执行。

方法说明
click在当前鼠标位置点击
clickAndHold在当前鼠标位置按住左键不放
contextClick在当前鼠标位置右键点击
doubleClick在当前鼠标位置双击
dragAndDrop将一个元素拖拽到另一个元素上
keyDown按下一个修饰键(如Ctrl, Shift, Alt等)
keyUp释放一个修饰键(如Ctrl, Shift, Alt等)
moveToElement将鼠标移动到一个元素的中心点上
pause在两个操作之间暂停一段时间
release释放当前鼠标位置的左键或右键
sendKeys向当前焦点元素或活动元素发送一系列按键

(九)多层框架定位

frame 是一个 HTML 元素,它定义了一个特定区域,另一个 HTML 文档可以在里面展示。比如:

<html>
    <frameset cols="25%,50%,25%">
      <frame src="frame_a.htm" />
      <frame src="frame_b.htm" />
      <frame src="frame_c.htm" />
    </frameset>
</html>

一个页面里面嵌了三个页面,但是selenium定位的时候默认只能定位到最外面一层的页面,如果想要切换页面(访问下层页面)可以使用如下API:

  • Frame标签包含 frameset、frame、iframe 三种。
  • Frameset 和普通的标签一样,不会影响正常的定位,可以使用 index、id、name 等任意种方式定位。
  • 而 frame 与 iframe 对 selenium 定位而言是一样的。selenium 有一组方法对 frame 进行操作。
webdriver.switchTo().frame(x);//切换到 id 为 x 的fram下
//后面可以定位到该 frame 中的元素
webdriver.findElement(By.id("id"));
……
//如果frame没有标签,可以使用索引来定位
webdriver.switchTo().frame(index);//索引从 1 开始。webdriver.switchTo().frame(1)表示切换到该页面下的第一个frame。

(十)下拉框处理

有如下的页面:

<html>
<body>
    <select id="ShippingMethod" onchange="updateShipping(options[selectedIndex]);" name="ShippingMethod">
        <option value="12.51">UPS Next Day Air ==> $12.51</option>
        <option value="11.61">UPS Next Day Air Saver ==> $11.61</option>
        <option value="10.69">UPS 3 Day Select ==> $10.69</option>
        <option value="9.03">UPS 2nd Day Air ==> $9.03</option>
        <option value="8.34">UPS Ground ==> $8.34</option>
        <option value="9.25">USPS Priority Mail Insured ==> $9.25</option>
        <option value="7.45">USPS Priority Mail ==> $7.45</option>
        <option value="3.20" selected="">USPS First Class ==> $3.20</option>
    </select>
</body>
</html>
// 定位 <select> 标签下拉框
WebElement selectElem = webDriver.findElement(By.cssSelector("#ShippingMethod"));
// Select 类用于定位 select 标签
Select select = new Select(selectElem);
//方式1:通过下标选择:从 1 开始计数
select.selectByIndex(1);
//方式2:通过 value 属性的值选择
select.selectByValue("11.61");

(十一)弹窗处理

WebDriver 中处理 alertconfirm 以及 prompt 时,先用switchTo() 方法定位到弹窗,然后使用一些方法进行操作。

//假设点击后弹出弹窗
webDriver.findElement(By.cssSelector("button")).click();
//切换到弹窗上
Alert alert = webDriver.switchTo().alert();
//弹窗取消
alert.dismiss();
//弹窗接受
alert.accept();
//输入数据
alert.sendKeys("数据");
//获取弹窗里的文字
alert.getText();

(十二)上传文件

上传文件也是用 sendKeys() 方法。有如下页面:

<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <title>upload_file</title>
</head>
<body>
    <div class="row-fluid">
        <div class="span6 well">
            <h3>upload_file</h3>
            <input type="file" name="file" />
        </div>
    </div>
</body>
</html>
//定位上传按钮,然后上传文件
webDriver.findElement(By.cssSelector("input")).sendKeys("D:\\text.txt");

(十三)浏览器窗口切换

如果想要操作其它页面,需要先跳到其它页面:

webDriver.getWindowHandle():获得当前浏览器窗口的句柄。
webDriver.getWindowHandles():返回所有浏览器窗口的句柄。
webDriver.switchTo().window(handle):用于切换到相应的浏览器窗口。
    private static void main(String[] args) throws InterruptedException {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.baidu.com");
        //等待时间
        webDriver.manage().timeouts().implicitlyWait(5,TimeUnit.SECONDS);
        //放大窗口,让登录按钮显示出来
        webDriver.manage().window().maximize();
        //获取登录按钮,并点击
        webDriver.findElement(By.cssSelector("#s-top-loginbtn")).click();
        //点击“立即注册”,打开注册页面
        webDriver.findElement(By.cssSelector("#TANGRAM__PSP_11__regLink")).click();
        //获取当前页面的句柄,此时是首页
        String handle = webDriver.getWindowHandle();
        //获取所有的页面的句柄(这时一共两个句柄)
        Set<String> handles = webDriver.getWindowHandles();
        //for 循环遍历句柄
        for(String tmp : handles){
            //比较是不是注册页面
            if(!handle.equals(tmp)){
                //切换到注册页面
                webDriver.switchTo().window(tmp);
                //输入用户名
                webDriver.findElement(By.cssSelector("#TANGRAM__PSP_4__userName")).sendKeys("会飞的喵喵123123123");
                //输入手机号
                webDriver.findElement(By.cssSelector("#TANGRAM__PSP_4__phone")).sendKeys("13220333333");
                //输入密码
                webDriver.findElement(By.cssSelector("#TANGRAM__PSP_4__password")).sendKeys("123456");
                //睡眠3秒
                Thread.sleep(3000);
                //关闭当前页面
                webDriver.close();
            }
        }
    }

屏幕录制-2023-10-03-225822_1.gif

(十四)获取窗口截图

添加依赖:添加这个依赖是为了使用FileUtils类,它能方便操作文件

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.14.0</version>
</dependency>
//截图
File srcFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
//将截图保存到 D 盘
FileUtils.copyFile(srcFile,new File("D:\\test.png"));
    private static void main(String[] args) throws IOException, InterruptedException {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.baidu.com");
        //等待时间
        webDriver.manage().timeouts().implicitlyWait(5,TimeUnit.SECONDS);
        //放大窗口,让登录按钮显示出来
        webDriver.manage().window().maximize();
        //获取登录按钮,并点击
        webDriver.findElement(By.cssSelector("#s-top-loginbtn")).click();
        Thread.sleep(1000);
        //截图
        File srcFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
        //将截图保存到 D 盘
        FileUtils.copyFile(srcFile,new File("D:\\test.png"));
    }

最后:下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Selenium WebDriver 是一种用于自动化Web应用程序测试的工具,它提供了一系列的API,用于操作浏览器来模拟用户的行为。它是基于Java编写的,因此可以使用Java语言来编写测试脚本Selenium WebDriver API 提供了一些常用方法来控制浏览器,如打开网址、在输入框中输入文本、点击按钮等。这些方法可以让我们对页面上的元素进行定位和操作,以模拟用户在浏览器中的行为。 使用 Selenium WebDriver API,我们可以使用多种定位方式来找到页面上的元素,如通过id、name、class等属性进行定位,也可以通过XPath和CSS选择器来定位。定位到元素后,我们可以对其执行一系列的操作,如获取元素的文本、获取元素的属性、点击元素等。 Selenium WebDriver API 还提供了一些常用的操作方法,如切换窗口、切换到iframe、执行JavaScript等。这些方法可以帮助我们处理一些特殊的页面场景,如弹窗、嵌套的iframe等。 使用 Selenium WebDriver API,我们可以编写可维护和可扩展的测试脚本。通过使用Java语言的面向对象特性,我们可以将测试代码进行模块化,使其更加易读和易于维护。此外,Selenium WebDriver 还支持多种浏览器,如Chrome、Firefox等,我们可以轻松地在不同的浏览器上运行测试脚本。 总之,Selenium WebDriver API 提供了丰富的功能和强大的灵活性,使得我们可以编写高效和可靠的自动化测试脚本。无论是对于新手还是有经验的测试人员来说,掌握这些API是非常重要的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值