当前位置: 首页 > news >正文

设计素材网站p网络推广工作怎么样

设计素材网站p,网络推广工作怎么样,wordpress submit 500,wordpress框架视频目录 一、什么是自动化测试 二、Selenium介绍 1、Selenium是什么 2、Selenium的原理 三、了解Selenium的常用API 1、webDriver API 1.1、元素定位 1.1.1、CSS选择器 1.1.2、Xpath元素定位 1.1.3、面试题 1.2、操作测试对象 1.3、添加等待 1.4、打印信息 1.5、浏…

目录

一、什么是自动化测试

二、Selenium介绍

1、Selenium是什么

2、Selenium的原理

三、了解Selenium的常用API

1、webDriver API  

1.1、元素定位

1.1.1、CSS选择器

1.1.2、Xpath元素定位

1.1.3、面试题

 1.2、操作测试对象

1.3、添加等待 

1.4、打印信息

 1.5、浏览器的操作

1.6、键盘事件

1.7、鼠标事件 

1.8、定位一组元素

1.9、多层框架/窗口定位

1.10、下拉框处理

1.11、弹窗处理

1.12、上传文件操作

1.13、关闭浏览器操作

1.14、窗口的切换

1.15、截图 



一、什么是自动化测试

自动化测试指软件测试的自动化,自预设下运行应用程序或者系统,预设条件包括正常和异常,最后评估运行结果。将认为驱动的测试行为转化为机器执行的过程。

 自动化测试包括UI自动化、接口自动化、单元测试自动化。按照这个金字塔模型来进行自动化测试规划,可以产生最佳的自动化测试产出投入比,可以用较少的投入获得很好的收益。

✨单元测试

最大的投入应再单元测试上、单元测试运行的频率也更加高

Java的单元测试框架是Junit

✨接口自动化

接口测试就是API测试,相对于UI自动化API自动化更加容易实现、执行起来也更稳定。

接口自动化有以下特点

  • 可在产品前期,接口完成后介入
  • 用例维护量小
  • 适合接口变动较小,界面变动频繁的项目

✨UI自动化

虽然测试金字塔告诉我们尽量多做API层的自动化测试,但是UI层的自动化测试更加贴近用户的需求和软件系统的实际业务。并且有时候我们不得不进行UI层的测试。

UI自动化的特点

  • 用例维护量大
  • 页面相关性强、必须后期项目页面开发完成之后介入
  • UI测试适合与界面变动较小的项目。

二、Selenium介绍

1、Selenium是什么

Selenium是用来做web自动化测试的框架。Selenium提供了多种编程语言的绑定,包括Python、Java、C#、JavaScript等,使开发人员能够使用自己熟悉的编程语言来编写自动化脚本。它还支持各种浏览器(Edge、Chrome),支持各种平台(Linux、Windows、Mac),具有丰富的API。

2、Selenium的原理

自动化脚本代码、浏览器驱动和浏览器之间的关系是,自动化脚本代码向浏览器驱动发起请求,驱动操控浏览器执行测试步骤,最终浏览器将结果返回给驱动,驱动最终再将结果返回给自动化程序。

三、了解Selenium的常用API

先来看一个完整的浏览器搜索框的测试

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;import java.util.List;import static java.lang.Thread.sleep;public class Main {public static void main(String[] args) throws InterruptedException {int flag = 0;//创建ChromeOptions对象,用于配置Chrome浏览器启动选项ChromeOptions options = new ChromeOptions();//允许所有请求options.addArguments("--remote-allow-origins=*");//创建Chrome引擎对象WebDriver webDriver = new ChromeDriver();//打开百度首页webDriver.get("https://www.baidu.com");//找到百度搜索输入框WebElement element = webDriver.findElement(By.xpath("//*[@id=\"kw\"]"));//输入"软件测试(要搜索的内容)"element.sendKeys("软件测试");//找到百度一下按钮,实现点击webDriver.findElement(By.cssSelector("#su")).click();//这里添加休眠函数是为了更清楚的观察sleep(3000);//校验//找到搜索结果List<WebElement> elements = webDriver.findElements(By.cssSelector("a em"));for(int i = 0;i < elements.size();i++){//如果返回的结果有软件测试,证明测试通过,否则测试不通过if(elements.get(i).getText().equals("软件测试")){flag = 1;System.out.println("测试通过");break;}}if(flag == 0){System.out.println("测试不通过");}}
}

 这里getText()方法表示获取特定元素的文本内容。get().getText(),返回你所选择的元素的纯文本内容,不包括HTML标签。

1、webDriver API  

1.1、元素定位

1.1.1、CSS选择器

✨使用到的方法

方法作用
findElement()找到一个元素
findElements()找到一批元素
By.cssSelector()表示通过css选择器查找元素,这个方法用在findElement()方法中作为参数。
sendKeys()模拟用户在输入框中输入文本、按键、组合键等操作。参数可以是字符串、键盘按键、键盘组合键等。
getText()获取特定元素的文本内容

获取class属性值可以通过浏览器的f12键找到一个页面的源码

1️⃣上述是通过class的方式复制内容。

2️⃣我们也可以点到输入框的源码位置,单击鼠标右键,使用css选择器的方式定位输入框,这里复制到的内容是id属性的值。两种方式获取的属性值是不同的,是通过不同的方式(属性)定位到输入框的。

 程序

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;public class Test {public static void main(String[] args) {//启动ChromeChromeOptions options = new ChromeOptions();//允许所有请求options.addArguments("--remote-allow-origins=*");WebDriver webDriver = new ChromeDriver(options);//打开百度首页webDriver.get("https://www.baidu.com");//找到百度搜索输入框(通过css选择器找到输入框,这里是通过class属性值定位到的)WebElement element = webDriver.findElement(By.cssSelector(".s_ipt"));//输入软件测试element.sendKeys("软件测试");}
}

 结果

1.1.2、Xpath元素定位
WebElement element = webDriver.findElement(By.xpath("//*[@id=\"kw\"]"));

结果:

1.1.3、面试题

1、css选择器和Xpath选择器的常见语法有哪些? 

✨CSS选择器

  1. 标签选择器:通过标签名来进行定位。语法格式为“标签名”。例如"input"。
  2. id选择器:通过元素的id属性值来定位对应的元素。语法格式"#id值",例如"#kw".
  3. 类选择器:通过元素的class属性值来定位对应的元素。语法格式".class值",例如:".s_ipt"。
  4. 后代选择器:通过空格分隔的两个元素标签来定位对应的元素。语法格式"父级选择器 子级选择器"。例如:"form input".

✨Xpath选择器:

  1. 绝对路径/html/head/title(绝对路径的效率非常低,所以不常用)
  2. 相对路径
  • 相对路径+索引//form[索引值]/span[索引值]/input (这里的索引如果不写,默认是从1开始。一个页面中存在多个相同的标签,这个时候使用索引,表示路径中的标签是页面中的第几个,或者是某个标签(form)下的第几个标签(input)).
  • 相对路径+属性值//input[@calss="s_ipt"]
  • 相对路径+通配符//*[@*=s_ipt]。表示将所有标签下的所有属性值为s_ipt的属性找到。
  • 相对路径+文本匹配//a[text()="新闻"]

 2、css选择器和Xpath选择器你觉得那个更好?

CSS选择器和Xpath选择器都有各自的优点,没有绝对的好会之分,二者在不同的场景下各有优势

  • CSS选择器在Chrome、火狐等浏览器中查找速度快、效率高,语法更简洁,在处理简单元素的查找时更推荐使用。
  • Xpath选择器功能更强大,可以通过包括和排除操作符进行元素集合运算,也可以选择元素的足心和后代,还支持正则表达式和序列运算。

 1.2、操作测试对象

方法作用
click

点击对象

sendKeys模拟用户在输入框中输入文本、按键、组合键等操作
submit提交
text用于获取元素的文本信息
getAttribute获取属性
clear清楚对象输入的文本内容

✨sendKeys、click和clear方法的使用

    private static void test01() throws InterruptedException {ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");WebDriver webDriver = new ChromeDriver(options);webDriver.get("http://www.baidu.com/");sleep(2000);//找到百度输入框,输入"美食"webDriver.findElement(By.cssSelector("#kw")).sendKeys("美食");sleep(2000);//点击百度一下按钮webDriver.findElement(By.cssSelector("#su")).click();sleep(2000);//清空百度搜索输入框webDriver.findElement(By.cssSelector("#kw")).clear();}

由于这里的操作是连续的,小编不会插入动图,这里就展示最终的效果。

✨submit的使用

在上述代码中可以将click方法替换成submit方法,最终实现的效果是相同的。

webDriver.findElement(By.cssSelector("#su")).submit();

但是使用submit方法,存在一定的条件。如果点击的元素放在form标签中,此时使用submit实现的效果click是一样的,如果点击的元素放在非form标签中,此时使用submit会报错

 ✨getAttribute方法的使用

    private static void test03(){ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");WebDriver webDriver = new ChromeDriver(options);webDriver.get("https://www.baidu.com/");String button_value = webDriver.findElement(By.cssSelector("#su")).getAttribute("value");if(button_value.equals("百度一下")){System.out.println("测试通过");}else{System.out.println(button_value);System.out.println("测试不通过");}}

这里获取到了"百度一下"这个文本信息,但是有的老铁就会产生疑问使用getText()方法也可以得到文本信息,为什么使用getAttribute来获取。

 我们使用getText()方法获取文本信息,只能是获取标签中间的文本信息。

1.3、添加等待 

1、强制等待(sleep)

2、智能等待(隐式等待、显示等待)

假设设置等待时间为3天

强制等待就会一直等待,等待时间为3天

隐式等待,最长等待3天时间,如果在三天之内获取页面上的元素,此时就会执行下面的程序,如果等待三天还是没有找到这个元素,就会报错。

强制等待:

隐式等待:

private static void test01() throws InterruptedException {ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");WebDriver webDriver = new ChromeDriver(options);webDriver.get("https://www.baidu.com/");sleep(2000);//找到百度输入框,输入"美食"webDriver.findElement(By.cssSelector("#kw")).sendKeys("美食");//点击百度一下按钮webDriver.findElement(By.cssSelector("#su")).submit();//隐式等待webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.DAYS);//清空百度搜索输入框webDriver.findElement(By.cssSelector("#kw")).clear();}

 显示等待:

  private static void test04(){ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");WebDriver webDriver = new ChromeDriver(options);webDriver.get("https://www.baidu.com/");//等待2秒,等待页面加载完成WebDriverWait wait = new WebDriverWait(webDriver,2);//等待元素加载完成并执行操作wait.until(ExpectedConditions.titleIs("百度一下,你就知道"));}

显示等待和隐式等待的区别

1、作用范围:隐式等待是全局性的等待设置,适用于整体页面的元素定位操作;显示等待是针对特定元素或条件的等待设置,更具体、可定制性更强。

2、等待时间:隐式等待直选哟设置一次,并适用于所有元素的定位操作;显示等待可以根据不同情况设定不同的等待时间。

3、等待条件:隐式等待没有明确的等待条件,只要在规定的时间内找到元素即可;显示等待可以指定等待元素可见、可点击等待特定条件。

4、操作方式:隐式等待是自动等待的,不需要再代码中显示调用;显示等待需要再代码中显示调用等待方法。

1.4、打印信息

打印title和url

    private static void test05() {ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");WebDriver webDriver = new ChromeDriver(options);webDriver.get("https://www.baidu.com/");String url = webDriver.getCurrentUrl();String title = webDriver.getTitle();if(url.equals("https://www.baidu.com/")&&title.equals("百度一下,你就知道")){System.out.println("当前页面url:"+url+",当前页面title:"+title);System.out.println("测试通过");}else{System.out.println("测试不通过");}}

 1.5、浏览器的操作

操作说明
browser.maxmize_window()浏览器窗口最大化
browser.set_window_size(width,hight)设置浏览器宽、高
browser.forward()浏览器的前进
browser.back()浏览器的后退
document.documentElement.scrollTop=0将浏览器滚动条滑动到最顶端
document.documentElement.scrollTop=10000将浏览器滚动条滑动到最低端

 这个代码演示了浏览器的前进、后退、刷新操作。但是介于小编不会使用动图,所以就不添加执行结果了。

    private static void test07() throws InterruptedException {WebDriver webDriver = new ChromeDriver();//打开百度首页webDriver.get("https://www.baidu.com/");//搜索521webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");//点击百度一下webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);//浏览器后退webDriver.navigate().back();//强制等待3秒sleep(3000);//浏览器刷新webDriver.navigate().refresh();//浏览器前进sleep(3000);webDriver.navigate().forward();}

浏览器的滚动条

private static void test08() throws InterruptedException {WebDriver webDriver = new ChromeDriver();//打开百度首页webDriver.get("https://www.baidu.com/");//搜索521webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");//点击百度一下webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);webDriver.navigate().forward();sleep(3000);//滚动条到结尾 ((JavascriptExecutor)webDriver).executeScript("document.documentElement.scrollTop=10000");}

 窗口的最大化、窗口的全屏化、设置窗口大小

    private static void test08() throws InterruptedException {WebDriver webDriver = new ChromeDriver();//打开百度首页webDriver.get("https://www.baidu.com/");//搜索521webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");//点击百度一下webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);((JavascriptExecutor)webDriver).executeScript("document.documentElement.scrollTop=10000");sleep(3000);//浏览器窗口最大化webDriver.manage().window().maximize();sleep(3000);//浏览器全屏化webDriver.manage().window().fullscreen();sleep(3000);//设置浏览器窗口大小webDriver.manage().window().setSize(new Dimension(600,800));}

1.6、键盘事件

操作说明
sendKeys(Keys.TAB)#TAB
sendKeys(Keys.ENTER)#回车
sendKeys(Keys.SPACE)#空格键
sendKeys(Keys.ESCAPE)#回退键(ESC)
sendKeys(Keys.CONTROL,'a')

#全选(Ctrl+A)

sendKeys(Keys.CONTROL,'c')#复制(Ctrl+C)
sendKeys(Keys.CONTROL,'x')#剪切(Ctrl+x)
sendKeys(Keys.CONTROL,'v')#粘贴(Ctrl+v)
    private static void test09() throws InterruptedException {WebDriver webDriver = new ChromeDriver();//打开百度首页webDriver.get("https://www.baidu.com/");//搜索521webDriver.findElement(By.cssSelector("#kw")).sendKeys("521");//ctrl+awebDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"a");sleep(3000);//ctrl+xwebDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"x");sleep(3000);//ctrl+vwebDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"v");sleep(3000);}

1.7、鼠标事件 

操作说明
context_click()右击
double_dlick()双击
drag_and_drop()拖动
move_to_element()移动
    private static void test09() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("https://www.baidu.com/");webDriver.findElement(By.cssSelector("#kw")).sendKeys("520");webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);// 找到图片按钮WebElement webElement = webDriver.findElement(By.cssSelector("#s_tab > div > a.s-tab-item.s-tab-item_1CwH-.s-tab-pic_p4Uej.s-tab-pic"));// 鼠标右击出现框Actions actions = new Actions(webDriver);sleep(3000);//contextClick()右击鼠标actions.moveToElement(webElement).contextClick().perform();}

1.8、定位一组元素

findElements示例,将页面上所有的checkbox都勾选上。

    private static void page01() {WebDriver webDriver = new ChromeDriver();webDriver.get("http://localhost:63342/_20230925testcode/src/main/Page/test01.html?_ijt=hk3glm0bcb2222roak6kf4826i&_ij_reload=RELOAD_ON_SAVE");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.DAYS);List<WebElement> webElements = webDriver.findElements(By.cssSelector("input"));for(int i = 0; i < webElements.size(); i++) {// 如果每个元素type值等于checkbox进行点击// getAttribute获取页面上的元素属性值,里面的type是当前元素属性if(webElements.get(i).getAttribute("type").equals("checkbox")){webElements.get(i).click();} else {// 否则什么也不操作;}}}

1.9、多层框架/窗口定位

对于一个web应用,经常会出现框架或窗口的应用,这也就给我们的定位带来了一定的困难。

  • 定位一个frame:switch_to.frame(name_or_id_or_frame_element)
  • 定位一个窗口window:switch_to.window(name_or_id_or_frame_element)
    private static void page02() {WebDriver webDriver = new ChromeDriver();webDriver.get("http://localhost:63342/_20230925testcode/src/main/Page/test02.html?_ijt=sdck9iv3t1f7l8bv2khvu2k87t&_ij_reload=RELOAD_ON_SAVE");webDriver.switchTo().frame("f1");webDriver.findElement(By.cssSelector("body > div > div > a")).click();}

1.10、下拉框处理

通过IndexValue来选择演示:

    private static void page03() {WebDriver webDriver = new ChromeDriver();webDriver.get("http://localhost:63342/_20230925testcode/src/main/Page/test03.html?_ijt=ibu1q228hs9l4q026vbbfjp8r3&_ij_reload=RELOAD_ON_SAVE");WebElement webElement = webDriver.findElement(By.cssSelector("#ShippingMethod"));Select select = new Select(webElement);//通过下标来选择
//        select.selectByIndex(3);//通过value值来选择select.selectByValue("12.51");}

1.11、弹窗处理

    private static void test10() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("http://localhost:63342/_20230925testcode/src/main/Page/test04.html?_ijt=bv9np3tl8gm9kv04oam7i2sfij&_ij_reload=RELOAD_ON_SAVE");webDriver.findElement(By.cssSelector("button")).click();sleep(3000);//alert弹窗取消webDriver.switchTo().alert().dismiss();sleep(3000);//点击按钮webDriver.findElement(By.cssSelector("button")).click();//在alert弹窗中输入”张三“webDriver.switchTo().alert().sendKeys("张三");//alert弹窗确认sleep(3000);webDriver.switchTo().alert().accept();}

1.12、上传文件操作

    private static void test11() {WebDriver webDriver = new ChromeDriver();webDriver.get("http://localhost:63342/_20230925testcode/src/main/Page/test05.html?_ijt=16g56va44mth0ok9g9lfkdqj32&_ij_reload=RELOAD_ON_SAVE");webDriver.findElement(By.cssSelector("input")).sendKeys("E:\\360MoveData\\Users\\26542\\Desktop\\图片");}

1.13、关闭浏览器操作

关闭浏览器的操作有两种,quit()方法和close()方法

quit方法:我们以百度的新闻连接为例,进行说明

    private static void test12() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("https:www.baidu.com");webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();sleep(4000);webDriver.quit();}

close()方法:还是以百度的新闻连接为例,进行说明

    private static void test12() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("https:www.baidu.com");webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();sleep(4000);webDriver.close();
}

 新闻页打开之后,之前get方法打开的百度首页被关闭。

注意:两个方法quit()和close()之间的区别

  • quit方法关闭了整个浏览器,close关闭当前页面。(这里的当前页面是指被操作的页面。)
  • quit方法会清空缓存、close不会清空缓存

1.14、窗口的切换

先来看一下错误的代码示范

    private static void test13() throws InterruptedException {WebDriver webDriver = new ChromeDriver();//打开百度首页webDriver.get("https://baidu.com/");//跳转到新闻连接的页面webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();sleep(3000);//找到新闻页面中的搜索框,然后输入"新闻联播"webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");//在新闻页面中找到点一下按钮,点击webDriver.findElement(By.cssSelector("#s_btn_wr")).click();}

这是因为现在的代码默认获取get方法打开的页面中的这些元素,我们在这里要获取的是另一个页面的元素,所以就会获取不到。就会报错。

这个时候我们就需要使用getWindowHandles方法来获取所有窗口的句柄。

方法说明
getWindowHandles()方法获取所有窗口的句柄
getWindowHandles()方法获取get打开的页面窗口句柄
    private static void test13() throws InterruptedException {WebDriver webDriver = new ChromeDriver();webDriver.get("https://baidu.com/");webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();sleep(3000);//获取所有页面的窗口句柄Set<String> handles = webDriver.getWindowHandles();String target_handle = "";for (String handle:handles){target_handle = handle;}//拿到当前窗口的句柄webDriver.switchTo().window(target_handle);sleep(3000);webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");webDriver.findElement(By.cssSelector("#s_btn_wr")).click();}

1.15、截图 

这里首先需要引入一个依赖

        <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency>
    private static void test15() throws InterruptedException, IOException {WebDriver webDriver = new ChromeDriver();webDriver.get("https://www.baidu.com/");webDriver.findElement(By.cssSelector("#kw")).sendKeys("软件测试");webDriver.findElement(By.cssSelector("#su")).click();sleep(3000);//强转成截图对象File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);//将截图好的图片存储到E://20231005jietu.png路径下FileUtils.copyFile(file, new File("E:\\12\\20230521.png"));}

http://www.hrbkazy.com/news/3858.html

相关文章:

  • 在网上做国际快递淘宝网站今日新闻头条大事
  • seo快速提高网站转化率青岛网站建设维护
  • 安徽建设工程协会网站推广app的营销方案
  • 网站官网建设注意怎么做网络推广最有效
  • 漳州做网站有什么平台可以发广告
  • 做热图的网站口碑营销案例2022
  • wordpress中文企业主题 下载seo工具优化软件
  • 找装修公司网站深圳seo博客
  • www.网站建设seo搜索引擎招聘
  • 做网站建设的前景太原做网站哪家好
  • 泰安市两学一做网站长尾关键词是什么
  • 微信公众号可以做微网站网络推广是什么职位
  • 网站建设优化网站排名各城市首轮感染高峰期预测
  • 网站制作费用明细网页快速收录
  • 上海昆山网站公司哪家好企拓客软件多少钱
  • 国外营销企业网站logo设计
  • 济南网站建设和网络推广哪个好网站seo综合诊断
  • 襄阳市建设局网站短视频seo排名加盟
  • 深圳汇网网站建设google seo是什么意思
  • 郑州市政府网站的建设与发展优化大师下载电脑版
  • 重庆网站建设只选承越阳江seo
  • 多久可以做网站合肥网站建设优化
  • wordpress 4.4 优化百度移动端关键词优化
  • wordpress站点标题副标题换行友情链接也称为
  • 网站模板 免费玄幻小说百度风云榜
  • 常用的做网站的工具都有哪些域名注册费用
  • 免费推广方案短视频矩阵seo系统源码
  • 网站怎么添加二级域名营销方式和渠道有哪些
  • 北京专业网站维护公司搜索引擎营销的五大特点
  • java web 网站开发基础新余seo