selenium(一)基于java、元素定位

news2024/9/20 16:44:27

Selenium自动化

Selenium是一个用于Web应用程序的自动化测试工具。它直接运行在浏览器中,可以模拟用户在浏览器上面的行为操作。

chrome下载

https://www.google.com/chrome/ 

下载的结果是 “ChromeSetup.exe”,双击该文件,安装程序会自动启动。

默认安装位置:C:\Program Files\Google\Chrome\Application\chrome.exe

结果我的在:C:\Users\91073\AppData\Local\Google\Chrome\Application\chrome.exe

。。。为啥?


下载驱动

最新版:Chrome for Testing availability

查看谷歌浏览器版本

谷歌浏览器输入网址的地方输入:chrome://version

下载与浏览器对应(或相近)版本的浏览器驱动:http://chromedriver.storage.googleapis.com/index.html

 备用地址:CNPM Binaries Mirror

解压后得到一个chromedriver.exe驱动文件


禁用自动升级

关闭自动升级方法:

1.右键单击【计算机】——【管理】——【计算机管理本地】——【系统工具】——【任务计划程序】——【任务计划程序库】——这里找到两个和Google自动更新相关的任务计划【GoogleUpdateTaskMachineCore】与【GoogleUpdateTaskMachineUA】,把这两个选项禁用。

2.在【服务和应用程序】——【服务】,这里找到了两个和Google更新相关的服务【Google更新服务(gupdate)】、【Google更新服务(gupdatem)】,右键——选择属性——启动类型禁用即可;


卸载谷歌浏览器

在卸载当前版本之前,建议备份你的书签、扩展、密码等资料。

  1. 通过Windows + R快捷键调出“运行”对话框。
  2. 键入APPWIZ.CPL和命中输入。

这将带您到所有已安装应用程序的列表。从列表中选择Google Chrome,然后点击卸载 命令。


降级版本

版本报错

Caused by: org.openqa.selenium.SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 114
Current browser version is 116.0.5845.97 with binary path C:\Users\91073\AppData\Local\Google\Chrome\Application\chrome.exe

Google浏览器历史版本下载地址

Download older versions of Google Chrome for Windows, Linux and Mac

按住alt键,双击桌面的谷歌浏览器桌面图标

拷贝目标路径:C:\Users\lenovo\AppData\Local\Google\Chrome\Application\chrome.exe

打开命令提示符,输入如下并回车键;

cd C:\Users\lenovo\AppData\Local\Google\Chrome\Application

输入“chrome.exe--disable-remote-words-auto-upgrade--version=版本号”,然后按回车键。在这里,请将“版本号”替换为所需的版本号。


Selenium入门

maven坐标

打开selenium的仓库地址 :https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java

直接拷贝到pom文件吧,,

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

<!-- 测试工具testng-->
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.14.3</version>
    <scope>test</scope>
</dependency>

入门案例

如果浏览器驱动未加入环境变量,那么创建浏览器驱动的时候,需要指定浏览器驱动的路径

public class Client {

    public static void main(String[] args) throws InterruptedException {
        //配置浏览器驱动地址
        System.setProperty("webdriver.chrome.driver", "D:\\tools\\chrome\\driver113\\chromedriver.exe");
        //打开Chrome浏览器
        WebDriver webDriver = new ChromeDriver();
        TimeUnit.SECONDS.sleep(5);
        //打开百度网站
        webDriver.get("https://www.baidu.com");
        TimeUnit.SECONDS.sleep(2);
        //输入框输入搜索关键词 selenium 中文官网
        webDriver.findElement(By.id("kw")).sendKeys("selenium 中文官网");
        TimeUnit.SECONDS.sleep(2);
        //点击百度一下按钮
        webDriver.findElement(By.id("su")).submit();
        TimeUnit.SECONDS.sleep(2);
        //查询所有搜索的结果
        List<WebElement> resultElements = webDriver.findElements(By.className("result"));
        if (!resultElements.isEmpty()) {
            //找到第一条结果的第一个链接
            List<WebElement> aTagElements = resultElements.get(0).findElements(By.tagName("a"));
            if (!aTagElements.isEmpty()) {
                //新开一个窗口打开此链接
                String href = aTagElements.get(0).getAttribute("href");
                System.out.println(href);
                ((JavascriptExecutor) webDriver).executeScript(String.format("window.open('%s')", href));
            }
        }
        TimeUnit.SECONDS.sleep(10);
        //关闭浏览器
        webDriver.quit();
    }
}

结果,很神奇的哦


命令行打开浏览器

new ChromeDriver(options);

如果希望Chrome 浏览器启动时附带启动参数,可通过addArguments 方式加载。

希望测试某个浏览器插件,可通过addExtensions方式提前加载以.crx 为扩展名的插件

感觉上和addArguments有点类似,不过setExperimentalOption是设置实验选项ChromeDriver选项尚未通过ChromeOptions API公开),这个方法我比较经常用来设置浏览器默认下载路径

对于一台机器上安装了多个版本的Chrome浏览器,可以使用setBinary 指定待测试Chrome。

让 selenium 连接我们手动打开的浏览器

打开浏览器有两种方式:图标点击和命令行运行。

图标点击不用多说,我们经常使用这种方式打开浏览器。命令行方式允许我啰嗦一句,找到浏览器的安装目录,在安装目录中输入 chrome.exe 就可以了。 比如我的 chrome 浏览器安装在

C:\Users\91073\AppData\Local\Google\Chrome\Application

这个路径,则在这个目录下打开 cmd 命令行,输入 chrome.exe,就可以打开一个浏览器

在浏览器打开的时候设置额外的参数,为它提供不同的功能。 通过 selenium 连接浏览器,需要用到两个参数 --remote-debugging-port 和 --user-data-dir

  • --remote-debugging-port 这个参数允许我们通过远程的方式连接,selenium 当然也可以。
  • --user-data-dir 这个参数指定一个独立的目录存放产生的用户数据,在连接时也要设置,否则会失效。
chrome.exe --remote-debugging-port=9222 --user-data-dir="F:\selenium\ChromeProfile"

有了远程调试地址,selenium 连接浏览器就变的很简单,只需要加 2 行代码。 创建一个选项,绑定debuggerAddress 远程调试地址。 此时就可以用 selenium 控制之前手工打开的浏览器了。

            //配置浏览器驱动地址
            System.setProperty("webdriver.chrome.driver", "F:\\webrpaTest\\RPA\\RoboticProcessAutomation\\browser\\driver\\chrome\\121\\chromedriver.exe");
            ChromeOptions options = new ChromeOptions();
            options.setBinary("C:\\Users\\91073\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe");
            //设置 Chrome 的远程调试端口地址
            options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
//            WebDriver driver = new ChromeDriver(ChromeDriverService.createDefaultService(), options);
            WebDriver driver = new ChromeDriver(options);
            System.out.println(driver.getTitle());

WebDriver 实例化参数

Chome浏览器部分

executable_path:浏览器驱动程序路径,如果没有制定,则默认使用环境变量PATH中设置的路径

options:启动选项 (Options对象通常位于各浏览器的 WebDriver 模块下,列如:from selenium.webdriver.浏览器名称.options import Options),建议优先使用options 参数来设置浏览器(options 基于 capabilities,在实例化某个浏览器的Options对象时会自动写入该浏览器预设的 capabilities)

  • service_log_path:驱动程序存放日志文件的位置

  • keep_alive:表示在与 ChromeDriver 进行链接时,是否带上 HTTP 请求头Connection: keep-alive,既是否使用长链接,布尔类型参数,默认值为True

  • service_args:浏览器驱动程序的参数,根据所使用的浏览器驱动不同,参数也有可能不同。

Edge浏览器部分

  • executable_path:浏览器驱动程序路径,如果没有制定,则默认使用环境变量PATH中设置的路径
  • capabilities:非浏览器特定的字典对象,传入浏览器启动参数时需要使用到
    port:驱动程序启用的端口号,如果不填写,则自动使用任意闲置的端口号,默认参数为0
    verbose:是否在服务中设置详细日志记录
    service_log_path:驱动程序存放日志文件的位置
    log_path:不推荐使用的 service_log_path 参数
    keep_alive:表示在与 EdgeDriver 进行链接时,是否带上 HTTP 请求头Connection: keep-alive,既是否使用长链接,布尔类型参数,默认值为True


元素定位

web自动化的难点和重点之一,就是如何 选择 我们想要操作的web页面元素。

id定位

id 定位 driver.findElement(By.id(“id的值”));

如果元素有id属性 ,这个id 必须是当前html中唯一的。所以如果元素有id, 根据id选择元素是最简单高效的方式。

  1. 使用WebDriver对象的findElement函数定义一个Web页面元素
  2. 使用findElements函数可以定位页面的多个元素

使用 find_elements 选择的是符合条件的 所有 元素, 如果没有符合条件的元素, 返回空列表

List<WebElement> listOfElements = driver.findElements(By.xpath("//div"));
webElement.findElements(By.tagName("tr"));
  • 如果没有匹配条件的元素,Find Elements命令将返回一个空列表

使用 find_element 选择的是符合条件的 第一个 元素, 如果没有符合条件的元素, 抛出 NoSuchElementException 异常

定位的页面元素需要使用WebElement对象来存储,以便后续使用


class定位

class 定位    driver.findElement(By.className(“class属性”));

 //企查查
 webDriver.get("https://www.qcc.com/");
 TimeUnit.SECONDS.sleep(2);
 //查企业 查老板 查风险 查招标 找关系
 List<WebElement> elements = webDriver.findElements(By.className("search-type"));

class 属性通常用于指向样式表的类

在html中,class规定元素的类名,语法格式为“<元素名称 class="value">”。class属性大多数时候用于指向样式表中的类(class)。

html标签是允许定义多个class类名的。比如:

<div class = "exp1 exp2"></div>

上边这个div就用到了exp1、exp2这两个class类,对于个数是没有限制,只需每个类名之间用空格隔开就好。


tag 名 定位

TagName 标签名称定位    driver.findElement(By.tagName(“标签名称”));

选择所有的tag名为 div的元素,如下所示


name定位

name定位    driver.findElement(By.name(“name的值”));

css定位

CSS定位为的优势在于定位速度比Xpath定位快,且比Xpath定位更加稳定

css 方式定位    driver.findElement(By.cssSelector(“css表达式”));

Xpath定位

xpath定位方式

xpath 是XML Path的简称, 用于在XML文档中选择文档中的节点。基于XML树状文档结构,Xpath语言可以在整棵树中寻找指定的节点。

xpath 方式定位
driver.findElement(By.xpath(“xpath表达式”));

xpath 有两种表示方法,绝对路径和相对路径,

绝对路径是指从根开始,以/开始,如/html/body/div,

相对路径是指在一个路径下,另外的路径以这个路径作为参照,以//开始。从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。

  • XPath表达式中的//表示在HTML文档的全部层级位置进行查找

举例如下:

//百度一下
webDriver.get("https://www.baidu.com");
WebElement element = webDriver.findElement(By.xpath("//*[@id='su']"));

这里为啥是//*[@] 呢?

  • //表示从任意位置去查找
  • *是标签名
  • @是属性定位

强烈建议使用相对路径和属性值结合的定位方式来编写xpath定位表达式。如

By.xpath("//*[@id='su']")

xpath获取

xpath获取技巧:网页的html是一种特殊的XML文档。使用浏览器调试工具,可以直接获取xpath语句

右键-检查(或者F12),然后点击这个箭头,就可以在浏览器上选择元素了

使用Chrome 来直接获取元素的XPath.

通过层级关系和索引定位(索引从1开始):

//*[@id="content"]/div/div[2]/div[4]/div[2]/h2/div[2]/form/div

标签+属性定位

XPath通过idnameclass属性定位。语法如下:

//标签名[@属性名='属性值']
//用XPath通过id属性定位  
element1 = driver.find_element_by_xpath("//input[@id='kw']")

//用XPath通过name属性定位  
element2 = driver.find_element_by_xpath("//input[@name='wd']")

//用XPath通过class属性定位  
element3 = driver.find_element_by_xpath("//*[@class='s_ipt']")

总结

  1. 如果不想制定标签名称,可以用*号表示任意标签。
  2. 有时候同一个属性,同名的比较多,这时候可以通过标签筛选下,定位更准一点。
  3. 如果想制定具体某个标签,就可以直接写标签名称

List pageUl = ar.driver.findElements(By.xpath("//ul[@class='bfe-pager']"));//获取页数


层级定位

通过层级关系定位,注意:最终定位的是子标签....语法如下:

 //父标签名[@父标签属性名='属性值']/子标签

在页面中,定位下面代码片段中的<input>标签

<p id="p1">
    <label for="userA">账号A</label>
    <input required="" value="">
</p>

答案如下:

driver.find_element_by_xpath("//p[@id='p1']/input")

索引定位

索引定位元素,语法如下:

//父标签名[@父标签属性名='属性值']/子标签[索引值]   索引从1开始

比如我要定位如下图片的“京东家电连接”

答案是:

//*[@id=\"navitems-group1\"]/li[2]/a

用id="navitems-group1"定位到如下图片这里,这些是一些li标签

//*[@id="navitems-group1"]/li[1]/a

//*[@id="navitems-group1"]/li/a

注意:如果是第一个元素,索引值可以不加。因为不加索引值会选取ul下的全部li标签
而我们用的是单数定位形式,默认选择第一个。


文本定位

//标签名[text()=‘文本’]

xpath定位时,定位某一元素不好定时,可以定位其子级元素,然后通过 /… 定位到它的父级元素

HTML实例:<button type="button" class="ant-btn ant-btn-primary"><span>新 建</span></button>
xpath定位://span[text()='搜 索']/..

逻辑定位

XPath逻辑定位说明:

  1. xpath还有一个比较强的功能,可以支持与(and)、或(or)、非(not)。
  2. 一般用的比较多的是and运算,同时满足两个属性。

比如一个日期输入框无法输入

1

//获取当前页所有的数据
List datasaaa = ar.driver.findElements(By.xpath("/html/body/div[11]/table/tbody/tr/td[not(contains(@class, \"outMonthDay\"))]"));	 
System.out.println("datasaaa.size():"+datasaaa.size());
for(int i=0;i<datasaaa.size();i++){
    String text=datasaaa.get(i).getText().trim();
	System.out.println("text:" + text);
	if(Integer.parseInt(text)==day1){
		datasaaa.get(i).click();
		break;
	}
}

判断元素是否存在

场景:比如银行某些账号的对账提醒,但是不是所有的账号都有。所以要先判断元素是否存在

捕获异常方式  

捕获异常是使用findElement()方法无法获取元素则会抛出异常,如果找到元素则会返回True

//通过异常判断
public static boolean isElementExist(WebDriver driver, String xpath) {
    try {
        WebElement element = driver.findElement(By.xpath(xpath));
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

弊端:只要页面上有元素,不几个,都返回True

比如:在打开百度贴吧的时候,会有登录提醒。做一个判断,如果存在则关闭该弹窗

driver.get("https://tieba.baidu.com/");
//只需要设置一次,所有的元素都可有最多 10s 的等待加载的时间(默认0)
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//判断xpath是否存在,存在则点击关闭弹窗
boolean exist = isElementExist(driver, "//*[@id=\"tiebaCustomPassLogin\"]/div[2]/span");


父子、兄弟、相邻节点定位方式

相邻节点定位

比如,我要获取表格的总记录数。此时因为一个变化的值,

如果查询条数少,只有一页。则获取页数可以用xpath :/ul/li[5]/b

如果查询条数过多,则xpath发生变化:/ul/li[6]/b

此时,是否可以用兄弟节点定位。通过“>”来定位。“>”是可以用属性定位的//a[@class=\"next\"]


获取文本

//h5[text()='可用余额'

//span[text() = '全部']/parent::label/span[1]

子节点定位父节点

result = html.xpath('//a[@id="parentSpan"]/text()')

获取 href 属性

# 8、获取 href 属性
result = html.xpath('//a[@id="parentSpan"]/@href')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2083629.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

selenium(二)基于java、元素操控、Frame切换、元素等待

元素操控 选择到元素之后&#xff0c;我们的代码会返回元素对应的 WebElement对象&#xff0c;通过这个对象&#xff0c;我们就可以 操控 元素 输入sendKeys 项目实战&#xff1a;在网银环境下载流水[交易明细]的时候&#xff0c;需要指定查询日期&#xff0c;有些银行是可以…

一个简单的CRM客户信息管理系统,提供客户,线索,公海,联系人,跟进信息和数据统计功能(附源码)

前言 在当今快速发展的商业环境中&#xff0c;企业管理面临着种种挑战&#xff0c;尤其是如何有效管理和维护客户关系成为了一个关键问题。现有的一些处理方案往往存在功能分散、操作复杂、数据孤岛等痛点&#xff0c;这不仅影响了工作效率&#xff0c;也难以满足企业对客户关…

仿华为车机功能之--修改Launcher3,实现横向滑动桌面空白处切换壁纸

本功能基于Android13 Launcher3 需求:模仿华为问界车机,实现横向滑动桌面空白处,切换壁纸功能(本质只是切换背景,没有切换壁纸)。 实现效果: 实现思路: 第一步首先得增加手势识别 第二步切换底图,不切换壁纸是因为切换壁纸动作太大,需要调用到WallpaperManager,耗…

【赵渝强老师】构建Docker Swarm集群

在了解了Docker Swarm的体系架构以后&#xff0c;基于已经部署好三台虚拟主机便可以非常容易地构建Swarm集群。下表列出了这三台虚拟机的相关信息。其中&#xff1a;master主机将作为Swarm Manager运行&#xff1b;而node1和node2将作为Swarm Node运行。 视频讲解如下&#xf…

nacos 动态读取nacos配置中心项目配置

实现了项目稳定运行情况下不需要在项目中改配置&#xff0c;直接在nacos中修改更方便。 pom文件&#xff1a; <!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap…

大数据测试怎么做,数据应用测试、数据平台测试、数据仓库测试

本期内容由中通科技高级质量工程师龙渊在公益讲座中分享&#xff0c;他从大数据测试整体介绍、数据应用测试、数据平台测试以及数据仓库测试等方面&#xff0c;与大家共同探讨了大数据测试的方法实施与落地。 以下是讲座正文&#xff1a; 今天我们分享的内容主要从大数据简介…

阿里云Ubuntu系统安装/简单使用Kafka

一、安装kafka 1.下载安装包 1.1下载地址 https://kafka.apache.org/downloads 注意&#xff1a; 版本可以随意选择&#xff0c;我们选择版本为2.4.1 2.压缩文件上传/解压 2.1上传 2.2解压文件 #解压文件指令 tar -zxvf kafka_2.12-2.4.1.tgz -C /export/server/ #创建软…

py_gif制作

from PIL import Image import moviepy.editor as mp import os# 1. 定义函数 resize_frame&#xff0c;用于调整视频帧的大小 def resize_frame(frame, max_size240):img Image.fromarray(frame)img img.resize((max_size, max_size), Image.Resampling.LANCZOS) # 使用 LA…

【Java】—— Java面向对象基础:Java中如何创建和使用三角形类(TriAngle)来计算面积

目录 第一步&#xff1a;定义TriAngle类 第二步&#xff1a;编写TriAngleTest测试类 运行程序 总结 在Java编程中&#xff0c;面向对象的编程思想是一种非常强大的工具&#xff0c;它允许我们将现实世界中的实体&#xff08;如三角形&#xff09;抽象成程序中的类&#xff…

c++关于字符串的练习

提示并输入一个字符串&#xff0c;统计该字符串中字母个数、数字个数、空格个数、其他字符的个数 #include <iostream> #include<string> using namespace std;int main() {string s1;int letter0,digit0,space0,other0;cout<<"请输入一个字符串:"…

redis学习笔记 ——redis中的四大特殊数据结构

一.前言 在之前的学习中&#xff0c;我们已经介绍了Redis中常见的五种基本的数据结构&#xff0c;而今天我们就要开始介绍Redis的四种特殊的数据结构&#xff0c;它们分别是bitmap(位图)&#xff0c; HyperLogLog(基数统计),Geospatial(地理信息),Stream。 二.位图(Bitmap) …

springboot+vue+mybatis计算机毕业设计电子产品交易系统+PPT+论文+讲解+售后

系统根据现有的管理模块进行开发和扩展&#xff0c;采用面向对象的开发的思想和结构化的开发方法对电子产品交易管理的现状进行系统调查。采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计中采用“自下而上”…

并发高负载场景下的负载均衡优化方案

并发高负载场景下&#xff0c;负载均衡优化技术 负载均衡是一种计算机技术&#xff0c;主要用于在多个计算机(如计算机集群)、网络连接、CPU、硬盘驱动器或其他资源中分配工作负载。 其主要目标是优化资源使用、最大化吞吐率、最小化响应时间&#xff0c;同时避免任何一个资源的…

跨境电商避坑指南:如何在亚马逊和速卖通安全进行测评补单

大家好&#xff0c;近期&#xff0c;不少从事跨境电商的朋友纷纷向我求助&#xff0c;他们在执行测评补单时频繁遭遇支付难题&#xff0c;如支付失败、支付成功后订单被取消&#xff0c;更有甚者&#xff0c;账号遭遇封禁。许多朋友误以为这仅仅是支付卡的问题&#xff0c;但实…

【生信分析常用软件】plink常用功能之翻转正负链(--flip)

官网:PLINK 1.9 plink --bfile plink --flip flip.txt --make-bed --out test 当不同数据合并时&#xff0c;如果一个数据使用正链&#xff0c;另外一个数据使用反链&#xff0c;就会导致合并数据出现问题&#xff0c;报错。 这种时候方案一&#xff1a;舍弃所有不能合并位点&…

【图像去噪】论文复现:代替ReLU!Pytorch实现即插即用激活函数模块xUnit,并插入到DnCNN中实现xDnCNN!

请先看【专栏介绍文章】&#xff1a;【图像去噪&#xff08;Image Denoising&#xff09;】关于【图像去噪】专栏的相关说明&#xff0c;包含适配人群、专栏简介、专栏亮点、阅读方法、定价理由、品质承诺、关于更新、去噪概述、文章目录、资料汇总、问题汇总&#xff08;更新中…

keil添加芯片包

找到.pack将其移动到KEIL的文件路径下 双击Keil.STM32F1xx_DFP.2.4.1.pack&#xff0c;点击【Next>>】&#xff0c;开始安装芯片支持包 重新打开keil5&#xff0c;打开任意的工程&#xff0c;点击工具栏的魔术棒按钮 选择Device&#xff0c;可以看到STM32F1系列芯片已经被…

AUTOSAR_EXP_ARAComAPI的3.1章节笔记

3.1 Approach 为什么AUTOSAR发明了另一种通信中间件API/技术&#xff0c;而市场上有几十种——尤其是AutoSar AP的指导方针之一是重用现有的经过验证的技术&#xff1f;在提出新的中间件设计之前&#xff0c;我们确实评估了现有的技术&#xff0c;乍一看&#xff0c;这些技术似…

判别分析分类上接贝叶斯决策,下接最小距离分类

多元正态分布下的贝叶斯决策&#xff0c;称为判别分析分类。 先验概率相等时&#xff0c;等价于最小距离分类。 最小马氏距离分类 判别分析分类 贝叶斯后验概率

米家商城主题 html 页面源码分享,可用于网页设计作业

使用技术&#xff1a; HTML, CSS , Javascript 项目亮点&#xff1a; 1. 仿照米家商城页面布局所做的页面样式结构 2. 首页放置了可自动切换的轮播图 3. 登录页有表单结构&#xff0c;并且有切换的动画效果 4. 包含实时的动态时间&#xff0c;使用 js 实现 5. 页面布局清…