web UI自动化介绍

文章目录

  • 一、web UI自动化介绍
    • 1.1 执行UI自动化测试前提
    • 1.2 Selenium介绍以及知识点梳理
  • 二、Selenium 学习
    • 2.1 基础
      • 2.1.1 环境安装与基础使用
      • 2.1.2 web浏览器控制
      • 2.1.3 常见控件的八大定位方式
        • 2.1.3.1 八大定位方式介绍
        • 2.1.3.2 NAME、ID定位
        • 2.1.3.3 css_selector定位
        • 2.1.3.4 通过XPATH定位
      • 2.1.4 强制等待与隐式等待
        • 2.4.1 **强制(直接)等待**
        • 2.4.2 **隐式等待**
        • 2.4.3 **显式等待**
        • 2.4.4 总结
      • 2.1.5 常见控件的交互方法
      • 2.1.6 练习1-测试人论坛搜索自动化
    • 2.2 进阶
      • 2.2.1 css selector定位
        • 2.2.1.1 css 选择器概念
        • 2.2.1.2 CSS基础语法
          • 调试方法
          • css基础语法
          • 关系定位
          • css 顺序关系
      • 2.2.2 XPATH定位
        • 2.2.2.1 xpath 基本概念
        • 2.2.2.2 XPTAH基础语法
          • **调试方法**
          • 基础语法
        • 2.2.2.3 xpath 高级用法
      • 2.2.3 显示等待的高级应用
        • 原理解析
        • 官方分装类 expected_conditions
        • 自定义显示等待条件
      • 2.2.4高级控件的交互方法
        • 介绍
        • ActionChains基本用法
          • 键盘操作
          • 鼠标操作
      • 2.25 网页多窗口和Frame的处理
        • 多窗口处理
        • Frame的处理
      • 文件上传以及弹窗处理
        • 文件上传
        • 弹窗处理
      • 关键数据记录
        • 介绍
        • 示范
      • 练习项目1-litemall商城管理后台
        • 前置后置操作
        • 登录功能
        • 新增商品
        • 删除商品
        • 新增商品测试用例
    • 2.3 高级
      • 2.3.1 浏览器复用-托管
      • 2.3.2 cookie复用
      • 2.3.3 Page Object思想
      • 2.3.4 异常记录关键信息
        • 常规的记录方法
        • 使用装饰器记录
      • UI自动化的常见项目结构

一、web UI自动化介绍

1.1 执行UI自动化测试前提

  1. 业务流程不频繁改动
  2. UI 元素不频繁改动,界面稳定
  3. 需要频繁回归的场景
  4. 多平台运行,组合遍历型、大量重复的任务s

业界使用较多的web UI自动化工具是 Selenium

1.2 Selenium介绍以及知识点梳理

支持多语言,行业内最火最主流

  • 用于web浏览器测试的工具

  • 支持的浏览器包括IE,Firefox,Safari,Chrome,Edge等

  • 使用简单,可使用Java,Python等多种语言编写用例脚本

  • 主要由三个工具构成:WebDriver、IDE、Grid

  • 能力建设——初级

Selenium 的架构:

brower
webdriver
selenium
client多语言
chrome
IE
FireFox
chromedriver
IEdriver
GeckoDriver
selenium
python
java
ruby

在客户端通过各种语言调用selenium库,selenium 调用对应的浏览器驱动,通过浏览器驱动去操作浏览器进行各种操作。

形式 章节 描述
知识点 Web 自动化测试价值与体系 价值体系 技术选型 学习路线
知识点 环境安装与使用 selenium、 chromedriver、 firefox geckodriver
知识点 自动化用例录制 selenium IDE、录制、回放、基本使用
知识点 自动化测试用例结构分析 录制代码解析,代码结构优化
知识点 web 浏览器控制 打开网页、刷新、回退、最大化、最小化
知识点 常见控件定位方法 id name css xpath link 定位
知识点 强制等待与隐式等待 介绍 selenium 经典的三种等待方式
知识点 常见控件交互方法 点击,输入,清空,获取元素文本、尺寸等属性信息
实战 测试人论坛搜索功能自动化测试 用例设计、用例编写、断言
  • 中级

    形式 章节 描述
    知识点 高级定位-css css 使用场景、语法
    知识点 高级定位-xpath xpath 使用场景、语法
    知识点 显式等待高级使用 显式等待原理与使用
    知识点 高级控件交互方法 右键点击、页面滑动、表单填写等自动化动作
    知识点 网页 frame 与多窗口处理 多窗口,多 frame 下的窗口识别与切换
    知识点 文件上传弹框处理 文件上传的自动化与弹框处理机制
    知识点 自动化关键数据记录 行为日志、截图,page source
    实战 电子商务产品实战 用例设计、日志封装、测试报告
    训练营 知名产品web自动化测试实战 用例设计、日志封装、测试报告
  • 高级

    形式 章节 描述
    知识点 浏览器复用 利用远程调试技术实现自动化登录
    知识点 Cookie 复用 利用 cookie 复用实现自动化登录
    知识点 page object 设计模式 page object 模式的发展历史介绍、六大设计原则
    知识点 异常自动截图 测试用例失败时自动截图
    知识点 测试用例流程设计 测试装置的应用,套件级别的初始化与清理、用例级别的初始化与清理
    实战 电子商务产品实战 page object 设计模式应用、BasePage 封装、基于 page object 模式的测试用例编写
    训练营 web自动化测试进阶实战 page object 设计模式应用、BasePage 封装、基于 page object 模式的测试用例编写
  • 拓展

    1. selenium高级用法
    形式 章节 描述
    知识点 selenium 多浏览器处理 chrome、firefox 等浏览器的自动化支持
    知识点 执行 javascript 脚本 使用 selenium 直接在当前页面中进行 js 交互
    知识点 selenium option 常用操作 selenium option 的介绍与使用
    知识点 capability 配置参数解析 capability 用法 ,firefox chrome 等浏览器的专属 capability
    1. 新一代前端测试框架
    形式 章节 描述
    知识点 cypress 测试框架介绍 web 自动化测试框架 cypress

二、Selenium 学习

2.1 基础

2.1.1 环境安装与基础使用

  1. 准备好Python环境(百度python安装教程)

  2. 准备好selenium依赖

    pip install selenium

  3. driver的下载与配置(以chrome为例)

    1. 下载chrome的webdriver

      官方链接:

      https://www.selenium.dev/documentation/en/webdriver/driver_requirements/

      淘宝镜像,下载更快

      https://npm.taobao.org/mirrors/chromedriver/

      在下载时需要 选择与浏览器对应的版本,如果找不到完全一样的,可以选取个最相近的,一般大版本相同也是可以正常使用的

    2. 配置环境变量

      为了能够直接使用webdriver,而不是使用时去写死webdriver的地址,需要将webdriver所在的文件夹路径加到 环境变量(PATH)中

    3. 验证

      打开一个cmd命令行,输入:chromedriver --version ,可以看到版本信息则说明chromedriver环境变量配置成功

  4. 在代码中import对应的依赖并打开百度

    基本使用

    from time import sleep
    
    from selenium import webdriver
    # 初始化浏览器驱动,这里选择Chrome浏览器,需要配置好webdriver的环境变量
    driver = webdriver.Chrome()
    # 浏览器打卡百度
    driver.get('http://www.baidu.com')
    sleep(10)
    # 关闭浏览器
    driver.close()
    

    运行脚本能成功打开百度则说明配置成功

2.1.2 web浏览器控制

在初始化driver后可以使用以下方法对浏览器进行控制

初始化driver即:diver = webdriver.Chrome

然后使用driver调用以下方法:

方法 使用场景 操作
get web自动化测试第一步 打开浏览器
refresh 模拟浏览器刷新 浏览器刷新
back 模拟退回步骤 浏览器退回
maximize_window 模拟浏览器最大化 最大化浏览器
minimize_window 模拟浏览器最小化 最小化浏览器
from time import sleep
from selenium import webdriver
# 初始化浏览器驱动,这里选择Chrome浏览器,需要配置好webdriver的环境变量
driver = webdriver.Chrome()
# 浏览器打卡百度
driver.get('https://ceshiren.com/')
sleep(3)
# 刷新页面
driver.refresh()
driver.get('http://www.baidu.com')
# 浏览器返回操作
driver.back()
sleep(1)
# 最小化窗口
driver.minimize_window()
sleep(1)
driver.maximize_window()
sleep(1)
# 关闭浏览器
driver.close()

2.1.3 常见控件的八大定位方式

2.1.3.1 八大定位方式介绍

控件的定位方式很多,但常用的只有以下四种:id、name、xpath、css selector ,后续会详细介绍

方式 描述 使用方法
id(重点) id 属性对应的值 driver.find_element(By.ID, “ID属性”)
name(重点) name 属性对应的值 driver.find_element(By.NAME, “Name属性对应的值”)
xpath(重点) xpath表达式 driver.find_element(By.XPATH, “xpath表达式”)
css selector(重点) css 表达式 driver.find_element(By.CSS_SELECTOR, “css表达式”)
link text 查找其可见文本与搜索值匹配的锚元素 driver.find_element(By.LINK_TEXT,“文本信息”)
partial link text 查找其可见文本包含搜索值的锚元素。
如果多个元素匹配,则只会选择第一个元素。
class name class 属性对应的值 driver.find_element(By.CLASS_NAME,‘el-submenu__title’)
tag name 标签名称 很少用

使用格式:

# 示例,两种方式作用一模一样
# 官方建议使用下面的方式
driver.find_element_by_id("su")
driver.find_element(By.ID, "su")  # 推荐你使用
  • 通过ID定位:driver.find_element(By.ID, "ID属性对应的值")

    import time
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    driver = webdriver.Chrome()
    driver.get('https://ceshiren.com/')
    # 强制等待3秒,等待元素加载完毕
    time.sleep(3)
    # 点击类别
    ele = driver.find_element(By.ID,'ember24').click()
    time.sleep(30)
    

2.1.3.2 NAME、ID定位

  • name定位格式:driver.find_element(By.NAME, "Name属性对应的值")
  • id定位格式:driver.find_element(By.ID, "ID对应的值")

2.1.3.3 css_selector定位

  • 格式: driver.find_element(By.CSS_SELECTOR, "css表达式")
  • 复制绝对定位
  • 编写 css selector 表达式(后面章节详细讲解)

web UI自动化介绍_第1张图片

2.1.3.4 通过XPATH定位

  • 格式: driver.find_element(By.XPATH, "xpath表达式")

  • chrome复制绝对定位

  • 编写 xpath 表达式(后面章节详细讲解)

    web UI自动化介绍_第2张图片

2.1.4 强制等待与隐式等待

​ 在chrome打开网页的时候,有时候由于网络加载、渲染等问题,无法定位到元素,需要等待元素加载渲染,否则会出现异常的报错,比如找不到元素等。

​ 等待元素加载分为以下三种:强制等待、隐式等待、以及显示等待

2.4.1 强制(直接)等待

  • 原理:直接在操作元素前添加sleep() 函数直接等待几秒,让元素加载成功

  • 缺点:难以确定元素加载的具体等待时间,时间短了无法定位到元素,时间长了影响执行效率,可以通过隐式等待解决

2.4.2 隐式等待

  • 原理:设置一个等待时间,轮询查找(默认0.5秒)元素是否出现,如果没出现就抛出异常

  • 隐式等待相比强制等待更智能,在脚本中我们一般看不到等待语句,但是它会在每个页面加载的时候自动等待;隐式等待只需要声明一次,一般在打开浏览器后进行声明.

    声明之后对整个drvier的生命周期都有效,后面不用重复声明

 driver.implicitly_wait(3)
  • 缺点
    • 元素可以找到,使用点击等操作,出现报错

    • 原因:

      • 页面元素加载是异步加载过程,通常html会先加载完成,js、css其后,导致进行交互操作时失败
      • 元素存在与否是由HTML决定,元素的交互是由css或者js决定
      • 隐式等待只关注元素能不能找到,不关注元素能否点击或者进行其他的交互

2.4.3 显式等待

  • 原理:在最长等待时间内,轮询,是否满足结束条件

  • 格式: WebDriverWait(driver实例, 最长等待时间, 轮询时间).until(结束条件)

    def wait_until():
        driver = webdriver.Chrome()
        driver.get("https://vip.ceshiren.com/#/ui_study")
        WebDriverWait(driver, 10).until(
            expected_conditions.element_to_be_clickable(
                (By.CSS_SELECTOR, '#success_btn')))
        driver.find_element(By.CSS_SELECTOR, "#success_btn").click()
    

2.4.4 总结

类型 使用方式 原理 适用场景
直接等待 time.sleep(等待时间)) 强制线程等待 调试代码,临时性添加
隐式等待 driver.implicitly_wait(等待时间) 在时间范围内,轮询查找元素 解决找不到元素问题,无法解决交互问题
显式等待 WebDriverWait(driver实例, 最长等待时间, 轮询时间).until(结束条件) 设定特定的等待条件,轮询操作 解决特定条件下的等待问题,比如点击等交互性行为

2.1.5 常见控件的交互方法

  • 点击 click()

    # 点击百度搜索框
    driver.find_element(By.ID,"kw").click()
    
  • 输入 send_keys('xx')

    # 输入"霍格沃兹测试开发"
    driver.find_element(By.ID,"kw").send_keys("霍格沃兹测试开发")
    
  • 清空 clear()

    # 清空搜索框中信息
    driver.find_element(By.ID,"kw").clear()
    
  • 获取元素属性信息

    • 目的:根据这些信息进行断言或者调试

    • 获取元素信息的方法

      • 获取元素文本
      • 获取元素的属性(html的属性值)
      # 获取元素文本
      driver.find_element(By.ID, "id").text
      # 获取这个元素的name属性的值
      driver.find_element(By.ID, "id").get_attribute("name")
      

2.1.6 练习1-测试人论坛搜索自动化

测试人搜索功能测试—进入测试人论坛首页(https://ceshiren.com)

  1. 点击搜索按钮
  2. 输入搜索关键词
  3. 输入回车进行搜索

预期结果判断:

  1. 搜索成功
  2. 搜索结果列表包含关键字
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


class TestCeshirenSearch:
    def setup_class(self):
        # 初始化driver并打开首页
        self.driver = webdriver.Chrome()
        self.driver.get('https://ceshiren.com')
        # 设置 隐式等待,整个测试期间只需要设置一次
        self.driver.implicitly_wait(5)

    def teardown_class(self):
        sleep(3)
        # 关闭 浏览器
        self.driver.close()

    def test_search(self):
        # 点击搜索 按钮
        self.driver.find_element(By.ID, 'search-button').click()
        # 在搜索输入框输入pytest
        self.driver.find_element(By.ID, 'search-term').send_keys('pytest')
        
        # 显示等待5秒,直到 搜索结果 按钮可点击
        WebDriverWait(self.driver, 5).until(
            expected_conditions.element_to_be_clickable(
                self.driver.find_element(By.CSS_SELECTOR, '.results')
            )
        )
        # 查看搜索结果 并根据 结果中是否包含搜索的元素进行 断言
        el_topic_list = self.driver.find_element(By.CSS_SELECTOR, ".topic-list-body")
        topic_title_text = el_topic_list.text
        assert 'pytest' in topic_title_text

2.2 进阶

HTML中常用标签,定位方式一般选取 css定位 或者xpath 定位,需要对html中常用标签有一定的了解,以下是一些基本的标签

标题:

段落:<p> 链接:<a> 图像:<img> 样式:<style> 列表:`无序列表<ul>、有序列表<ol>、列表项<li>` 块:`<div>、<span>` 脚本:<script> 注释:<!--注释--> </code></pre> <h3>2.2.1 css selector定位</h3> <h4>2.2.1.1 css 选择器概念</h4> <ul> <li> <p>css selector 定位 实际就是HTML的 Css选择器 的标签定位</p> </li> <li> <p>css 定位可以支持web端的产品也可支持app端的webview场景</p> </li> <li> <p>css 选择器有自己的语法规则和表达式</p> </li> <li> <p>css 定位通常分为绝对定位和相对定位</p> <pre><code class="prism language-python"><span class="token comment"># 绝对定位</span> $<span class="token punctuation">(</span><span class="token string">"#ember63 > td.main-link.clearfix.topic-list-data > span > span > a"</span><span class="token punctuation">)</span> <span class="token comment"># 相对定位</span> $<span class="token punctuation">(</span><span class="token string">"#ember63 [title='新话题']"</span><span class="token punctuation">)</span> </code></pre> <p>从上可以看到相对定位更加简洁优雅,此外相对定位还有以下有点不</p> <ul> <li>可维护性更强</li> <li>语法更加简洁</li> <li>解决各种复杂的定位场景</li> </ul> </li> </ul> <h4>2.2.1.2 CSS基础语法</h4> <p>使用css相对定位,需要使用的对应的基础语法,使用基础语法可以使用chrome自带的console 进行调试判断</p> <h5>调试方法</h5> <p>在浏览器(如:Chrome) 上,按<strong>F12</strong>或者鼠标右键<strong>检查</strong> ,进入console,</p> <p>输入 <code>$("css表达式")</code></p> <p>或者 <code>$$("css表达式")</code></p> <p>回车后查看是否定位到准确的结果</p> <p><a href="http://img.e-com-net.com/image/info8/fda4740709cc49778569b608148fbd07.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/fda4740709cc49778569b608148fbd07.jpg" alt="web UI自动化介绍_第3张图片" width="650" height="269" style="border:1px solid black;"></a></p> <h5>css基础语法</h5> <p>css 可以定位html 元素中的标签、id、类、以及其他属性进行定位,详细介绍如下</p> <p>**PS注意:**对于class 属性,如果属性值有空格 ,类似这样的<code>class="nav-item_top top ember-view"</code></p> <p>其中的空格 并不是字符串,而是作为分隔符,表示class 有多个属性值,定位时选取一个不对导致的重复的属性值即可(其他属性对应的属性值是唯一的)</p> <table> <thead> <tr> <th align="left">类型</th> <th align="left">表达式</th> <th align="left">浏览器console中的写法</th> <th>示例</th> </tr> </thead> <tbody> <tr> <td align="left">标签</td> <td align="left">标签名</td> <td align="left">$(‘标签名’)</td> <td>$(‘li’)</td> </tr> <tr> <td align="left">类</td> <td align="left">.class属性值</td> <td align="left">$(‘.类的值’)</td> <td>$(‘.nav-item_top’)</td> </tr> <tr> <td align="left">ID</td> <td align="left">#id属性值</td> <td align="left">$(‘#id属性值’)</td> <td>$(‘#ember85’)</td> </tr> <tr> <td align="left">属性</td> <td align="left">[属性名=‘属性值’]</td> <td align="left"><span class="katex--inline"><span class="katex"><span class="katex-mathml"> ( " [ 属性名 = ′ 属性 值 ′ ] " ) 或者 < b r > ("[属性名='属性值']")或者<br> </span><span class="katex-html"><span class="base"><span class="strut" style="height: 1.0019em; vertical-align: -0.25em;"></span><span class="mopen">(</span><span class="mord">"</span><span class="mopen">[</span><span class="mord cjk_fallback">属性名</span><span class="mspace" style="margin-right: 0.2778em;"></span><span class="mrel"><span class="mrel">=</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height: 0.7519em;"><span class="" style="top: -3.063em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.2778em;"></span></span><span class="base"><span class="strut" style="height: 1.0019em; vertical-align: -0.25em;"></span><span class="mord cjk_fallback">属性</span><span class="mord"><span class="mord cjk_fallback">值</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height: 0.7519em;"><span class="" style="top: -3.063em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mclose">]</span><span class="mord">"</span><span class="mclose">)</span><span class="mord cjk_fallback">或者</span><span class="mspace" style="margin-right: 0.2778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right: 0.2778em;"></span></span><span class="base"><span class="strut" style="height: 0.7335em; vertical-align: -0.0391em;"></span><span class="mord mathnormal">b</span><span class="mord mathnormal" style="margin-right: 0.0278em;">r</span><span class="mspace" style="margin-right: 0.2778em;"></span><span class="mrel">></span></span></span></span></span>(‘[属性名=“属性值”]’)</td> <td>$(“[title=‘过去一年、一个月、一周或一天中最活跃的话题’]”)</td> </tr> </tbody> </table> <p>示例对应的html结构:</p> <p><a href="http://img.e-com-net.com/image/info8/eb6aa61aa1b0411892727e11de737db0.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/eb6aa61aa1b0411892727e11de737db0.jpg" alt="web UI自动化介绍_第4张图片" width="650" height="214" style="border:1px solid black;"></a></p> <h5>关系定位</h5> <table> <thead> <tr> <th align="left">类型</th> <th align="left">格式</th> <th align="left">说明</th> <th>浏览器console中的写法</th> </tr> </thead> <tbody> <tr> <td align="left">父子</td> <td align="left">元素>元素</td> <td align="left"></td> <td>$(‘#s_kw_wrap>input’)</td> </tr> <tr> <td align="left">后代</td> <td align="left">元素 元素</td> <td align="left">节点子节点及子节点的所有子节点</td> <td>$(‘#form input’)</td> </tr> <tr> <td align="left">并集(了解)</td> <td align="left">元素,元素</td> <td align="left">只要有一个元素存在<br>就返回定位结果</td> <td>$(‘.bg,.s_ipt_wr,.new-pmd,.quickdelete-wrap’)</td> </tr> <tr> <td align="left">邻近兄弟(了解即可)</td> <td align="left">元素**+**元素</td> <td align="left">元素在同一个父节点下,且相邻</td> <td>$(‘.soutu-btn+input’)</td> </tr> <tr> <td align="left">兄弟(了解即可)</td> <td align="left">元素1~元素2</td> <td align="left">元素在同一个父节点下</td> <td>$(‘.soutu<sub>btn</sub>i’)</td> </tr> </tbody> </table> <p>示例:</p> <p><a href="http://img.e-com-net.com/image/info8/b6a52ba07d6d4b45abd9ff8d9eb0ed4f.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/b6a52ba07d6d4b45abd9ff8d9eb0ed4f.jpg" alt="web UI自动化介绍_第5张图片" width="650" height="232" style="border:1px solid black;"></a></p> <p>以下为输入chrome console的语法:</p> <ul> <li>父子关系——定位节点1下的子节点2: <code>$('#ember206>#ember208')</code></li> <li>后代关系——定位节点1的后代节点4: <code>$('[id="ember206"] [title="有新帖子的话题"]')</code> (PS: id属性也是属性的一种,因此也可使用属性的语法)</li> <li>临近兄弟——定位节点2的临近兄弟节点3: <code>$('#ember208+[id="navigation-bar"]')</code></li> <li>兄弟——定位节点4的兄弟节点6:<code>$('#ember213~#ember216')</code></li> <li>并集关系——定位节点4和节点6 :<code>$('#ember213,#ember216')</code> ,只要能知道到其中一个就返回结果</li> </ul> <h5>css 顺序关系</h5> <table> <thead> <tr> <th align="left">类型</th> <th align="left">格式</th> <th>jiei</th> <th>浏览器console中的写法</th> </tr> </thead> <tbody> <tr> <td align="left">父子关系+顺序</td> <td align="left">父->子:nth-child**(<strong>n</strong>)**</td> <td></td> <td>$(‘#form>input:nth-child(2)’)</td> </tr> <tr> <td align="left">父子关系+标签类型+顺序</td> <td align="left">父->子:nth-of-type**(<strong>n</strong>)**</td> <td></td> <td>$(‘#form>input:nth-of-type(1)’)</td> </tr> </tbody> </table> <p>示例:</p> <p><a href="http://img.e-com-net.com/image/info8/4ab6f63fa7564113b18b2e640c3e3775.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/4ab6f63fa7564113b18b2e640c3e3775.jpg" alt="web UI自动化介绍_第6张图片" width="650" height="213" style="border:1px solid black;"></a></p> <ul> <li>定位 navigation-bar的第9个孩子: <code>$('[id="navigation-bar"]>li:nth-child(9)')</code></li> </ul> <p>当父节点下的子节点 类型不一样,又想找某个类型下的第几个元素时,则可使用 第二种 即:<code>$('[id="navigation-bar"]>li:nth-child(9)')</code> 表示 定位 navigation-bar节点下的 li标签中的第9个</p> <h3>2.2.2 XPATH定位</h3> <h4>2.2.2.1 xpath 基本概念</h4> <p>​ XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历;可以使用路径表达式来选取 XML 文档中的节点或者节点集;也可以在web或者app自动化的测试中使用xpath 进行元素定位。</p> <h4>2.2.2.2 XPTAH基础语法</h4> <p>​ 和css定位一样,xpath 定位也分为绝对定位和相对定位,绝对定位需要根节点开始一层一层的向下定位,因此非常的臃肿且存在一旦前端修改了中间的某一个节点的依赖,原来的表达式就会失效,因此自动化中最后 使用简洁 优雅的相对定位。</p> <p>XPATH相对定位的优点:</p> <ul> <li>可维护性更强</li> <li>语法更加简洁</li> <li>相比于css可以支持更多的方式</li> </ul> <h5><strong>调试方法</strong></h5> <ul> <li>浏览器-console <ul> <li><code>$x("xpath表达式")</code></li> </ul> </li> <li>浏览器-elements <ul> <li>ctrl+f 输入xpath或者css</li> </ul> </li> </ul> <h5>基础语法</h5> <table> <thead> <tr> <th align="left">表达式</th> <th align="left">结果</th> <th></th> </tr> </thead> <tbody> <tr> <td align="left">/</td> <td align="left">从根节点的子元素选取,绝对定位的开头</td> <td>整个页面: <code>$x("/")</code></td> </tr> <tr> <td align="left">//</td> <td align="left">从符合条件的元素开始,不考虑他们的位置,相对定位常用开头</td> <td></td> </tr> <tr> <td align="left">*</td> <td align="left">通配符</td> <td></td> </tr> <tr> <td align="left">nodename</td> <td align="left">选取此节点的所有子节点</td> <td></td> </tr> <tr> <td align="left">…</td> <td align="left">选取当前节点的父节点</td> <td></td> </tr> <tr> <td align="left">@</td> <td align="left">选取属性</td> <td>$x(‘//*[@属性名=“属性值”]’)</td> </tr> </tbody> </table> <p>示例 输入Chrome console的命令:</p> <pre><code># 页面中的所有的子元素 $x("/*") # 整个页面中的所有元素 $x("//*") # 查找页面上面所有的div标签节点 $x("//div") # 查找id属性为site-logo的节点 $x('//*[@id="site-logo"]') # 查找节点的父节点 $x('//*[@id="site-logo"]/..') </code></pre> <ul> <li> <p>xpath通过索引直接获取对应元素</p> <pre><code class="prism language-bash"><span class="token comment"># 获取此节点下的所有的li元素</span> <span class="token variable">$x</span><span class="token punctuation">(</span><span class="token string">"//*[@id='ember21']//li"</span><span class="token punctuation">)</span> <span class="token comment"># 获取此节点下【所有的节点的】第一个li元素</span> <span class="token variable">$x</span><span class="token punctuation">(</span><span class="token string">"//*[@id='ember21']//li[1]"</span><span class="token punctuation">)</span> </code></pre> </li> </ul> <h4>2.2.2.3 xpath 高级用法</h4> <ul> <li> <p><code>[last()]</code>: 选取最后一个</p> <pre><code class="prism language-bash"><span class="token comment"># 选取最后一个input标签</span> //input<span class="token punctuation">[</span>last<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span> </code></pre> </li> <li> <p><code>[@属性名='属性值' and @属性名='属性值']</code>: 与关系</p> <pre><code class="prism language-bash"><span class="token comment"># 选取属性name的值为passward并且属性pwd的值为123456的input标签</span> //input<span class="token punctuation">[</span>@name<span class="token operator">=</span><span class="token string">'passward'</span> and @pwd<span class="token operator">=</span><span class="token string">'123456'</span><span class="token punctuation">]</span> </code></pre> </li> <li> <p><code>[@属性名='属性值' or @属性名='属性值']</code>: 或关系</p> <pre><code class="prism language-bash"><span class="token comment"># 选取属性name的值为passward或属性pwd的值为123456的input标签</span> //input<span class="token punctuation">[</span>@name<span class="token operator">=</span><span class="token string">'passward'</span> or @pwd<span class="token operator">=</span><span class="token string">'123456'</span><span class="token punctuation">]</span> </code></pre> </li> <li> <p><code>[text()='文本信息']</code>: 根据文本信息定位</p> <pre><code class="prism language-bash"><span class="token comment"># 选取所有文本信息为'霍格沃兹测试开发'的元素</span> //*<span class="token punctuation">[</span>text<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=</span><span class="token string">'霍格沃兹测试开发'</span><span class="token punctuation">]</span> </code></pre> </li> <li> <p><code>[contains(text(),'文本信息')]</code>: 根据文本信息包含定位</p> <pre><code class="prism language-bash"><span class="token comment"># 选取所有文本信息包'霍格沃兹'的元素</span> //*<span class="token punctuation">[</span>contains<span class="token punctuation">(</span>text<span class="token punctuation">(</span><span class="token punctuation">)</span>,<span class="token string">'霍格沃兹'</span><span class="token punctuation">)</span><span class="token punctuation">]</span> </code></pre> </li> </ul> <h3>2.2.3 显示等待的高级应用</h3> <h4>原理解析</h4> <p>​ 由于页面元素加载是异步加载过程,通常html会先加载完成,js、css其后,所以可能导致进行交互操作时失败,因此可以利用selenium中的**<code>WebDriverWait</code>** 类来实现等待,直到指定条件生效 或者 超出设定的时间。</p> <p>显示等待的原理:</p> <ul> <li>在代码中定义等待一定条件发生后再进一步执行代码(解决元素已加载但js等交互未完全加载的问题)</li> <li>在<strong>最长等待时间</strong>内<strong>循环</strong>执行<strong>结束条件的函数</strong></li> <li>WebDriverWait(driver 实例, 最长等待时间, 轮询时间).until(结束条件函数)</li> </ul> <p>WebDriverWait类的结构:</p> <div class="mermaid"> <div style="display: inline-block; white-space: nowrap;"> <span class="nodeLabel"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span class="nodeLabel">WebDriverWait</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span class="nodeLabel">POLL_FREQUENCY: float = 0.5 轮询间隔</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span class="nodeLabel">__init__(driver,timeout,poll_frequency,ignored_exceptions)</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span class="nodeLabel">until(self, method, message: str = "")</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span class="nodeLabel">until_not(self, method, message: str = "")</span> </div> </div> <p>在WebDriverWait 类中一个属性POLL_FREQUENCY,表示轮询的间隔;还有3个函数,分别是 构造函数init、直到条件成立函数until 和 直到条件不成立函数unitil_not。</p> <p>在构造函数中 需要传入 webdriver的实例化对象driver、超时时间timeout、以及轮询间隔poll_frequency,默认轮询间隔为0.5秒。</p> <p>其中until 方法中需要传入一个 函数对象,以及提示信息message(非必填)</p> <p>其中until的源码如下(额外自己添加一点的注释):</p> <div class="mermaid"> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-start-end_time" class="edgeLabel L-LS-start' L-LE-end_time"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-end_time-while" class="edgeLabel L-LS-end_time' L-LE-while"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-while-callMethod" class="edgeLabel L-LS-while' L-LE-callMethod"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-callMethod-judge" class="edgeLabel L-LS-callMethod' L-LE-judge"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-judge-rt1" class="edgeLabel L-LS-judge' L-LE-rt1">yes</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-rt1-over" class="edgeLabel L-LS-rt1' L-LE-over"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-judge-except" class="edgeLabel L-LS-judge' L-LE-except">no</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-except-sleep" class="edgeLabel L-LS-except' L-LE-sleep"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-sleep-judge2" class="edgeLabel L-LS-sleep' L-LE-judge2"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-judge2-callMethod" class="edgeLabel L-LS-judge2' L-LE-callMethod">No</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-judge2-break" class="edgeLabel L-LS-judge2' L-LE-break">Yes</span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-break-rt2" class="edgeLabel L-LS-break' L-LE-rt2"></span> </div> <div style="display: inline-block; white-space: nowrap;"> <span id="L-L-rt2-over" class="edgeLabel L-LS-rt2' L-LE-over"></span> </div> <div style="display: inline-block; white-space: nowrap;"> 开始 </div> <div style="display: inline-block; white-space: nowrap;"> 结束 </div> <div style="display: inline-block; white-space: nowrap;"> 设置结束时间 </div> <div style="display: inline-block; white-space: nowrap;"> 设置死循环 </div> <div style="display: inline-block; white-space: nowrap;"> 调用method函数并赋值给value </div> <div style="display: inline-block; white-space: nowrap;"> value真? </div> <div style="display: inline-block; white-space: nowrap;"> 返回value值 </div> <div style="display: inline-block; white-space: nowrap;"> 捕获忽略的异常 </div> <div style="display: inline-block; white-space: nowrap;"> 等待一个轮询间隔 </div> <div style="display: inline-block; white-space: nowrap;"> 判断是否超时 </div> <div style="display: inline-block; white-space: nowrap;"> 跳出循环 </div> <div style="display: inline-block; white-space: nowrap;"> 抛出超时异常 </div> </div> <pre><code class="prism language-python"> <span class="token keyword">def</span> <span class="token function">until</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> method<span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">:</span> screen <span class="token operator">=</span> <span class="token boolean">None</span> stacktrace <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token comment"># 结束时间 = 当前的时间(单调时间的秒数) + 构造函数初始化时传入的超时时间</span> end_time <span class="token operator">=</span> time<span class="token punctuation">.</span>monotonic<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> self<span class="token punctuation">.</span>_timeout <span class="token comment"># 设置死循环</span> <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span> <span class="token keyword">try</span><span class="token punctuation">:</span> <span class="token comment"># 调用 传入的函数名,该函数的参数是 driver的实例化对象,并将返回值赋值给value</span> value <span class="token operator">=</span> method<span class="token punctuation">(</span>self<span class="token punctuation">.</span>_driver<span class="token punctuation">)</span> <span class="token comment"># 当为True时 return 函数结束</span> <span class="token keyword">if</span> value<span class="token punctuation">:</span> <span class="token keyword">return</span> value <span class="token comment"># 捕获忽略传入的异常</span> <span class="token keyword">except</span> self<span class="token punctuation">.</span>_ignored_exceptions <span class="token keyword">as</span> exc<span class="token punctuation">:</span> screen <span class="token operator">=</span> <span class="token builtin">getattr</span><span class="token punctuation">(</span>exc<span class="token punctuation">,</span> <span class="token string">"screen"</span><span class="token punctuation">,</span> <span class="token boolean">None</span><span class="token punctuation">)</span> stacktrace <span class="token operator">=</span> <span class="token builtin">getattr</span><span class="token punctuation">(</span>exc<span class="token punctuation">,</span> <span class="token string">"stacktrace"</span><span class="token punctuation">,</span> <span class="token boolean">None</span><span class="token punctuation">)</span> <span class="token comment"># 等待一个轮询间隔</span> time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span>self<span class="token punctuation">.</span>_poll<span class="token punctuation">)</span> <span class="token comment"># 当超出 结束时间时 跳出循环</span> <span class="token keyword">if</span> time<span class="token punctuation">.</span>monotonic<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> end_time<span class="token punctuation">:</span> <span class="token keyword">break</span> <span class="token comment"># 抛出超时异常</span> <span class="token keyword">raise</span> TimeoutException<span class="token punctuation">(</span>message<span class="token punctuation">,</span> screen<span class="token punctuation">,</span> stacktrace<span class="token punctuation">)</span> </code></pre> <p><a href="http://img.e-com-net.com/image/info8/a1904803dafd489cb6ecd858092e0174.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/a1904803dafd489cb6ecd858092e0174.jpg" alt="web UI自动化介绍_第7张图片" width="650" height="451" style="border:1px solid black;"></a></p> <h4>官方分装类 expected_conditions</h4> <p>官网说明: https://www.selenium.dev/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html</p> <p>官方为显示等待封装了许多的条件函数,在expected_conditions类中有以下常用的条件方法:</p> <p>常见 expected_conditions</p> <table> <thead> <tr> <th align="left">类型</th> <th align="left">示例方法</th> <th align="left">说明</th> </tr> </thead> <tbody> <tr> <td align="left">element</td> <td align="left">element_to_be_clickable() (常用)visibility_of_element_located()</td> <td align="left">针对于元素,比如判断元素是否可以点击,或者元素是否可见</td> </tr> <tr> <td align="left">url</td> <td align="left">url_contains()</td> <td align="left">针对于url</td> </tr> <tr> <td align="left">title</td> <td align="left">title_is()</td> <td align="left">针对于标题</td> </tr> <tr> <td align="left">frame</td> <td align="left">frame_to_be_available_and_switch_to_it(locator)</td> <td align="left">针对于frame</td> </tr> <tr> <td align="left">alert</td> <td align="left">alert_is_present()</td> <td align="left">针对于弹窗</td> </tr> </tbody> </table> <h4>自定义显示等待条件</h4> <p>部分按钮处于可点击状态,但是有时候点击一次元素未生效需要多次点击元素,因此需要设计一个条件函数,在点击后返回需要的一个新的元素,当点击一次时,无法找到元素会返回为None,此时,until方法会在等待时间内,重复执行该函数。</p> <p><a href="http://img.e-com-net.com/image/info8/f6ab9a58cf3f4f0891ad85dae7b24b9b.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/f6ab9a58cf3f4f0891ad85dae7b24b9b.jpg" alt="web UI自动化介绍_第8张图片" width="650" height="195" style="border:1px solid black;"></a></p> <pre><code class="prism language-python"><span class="token keyword">from</span> time <span class="token keyword">import</span> sleep <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>support<span class="token punctuation">.</span>wait <span class="token keyword">import</span> WebDriverWait driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://vip.ceshiren.com/#/ui_study/frame'</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>maximize_window<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">multi_clickable</span><span class="token punctuation">(</span>target_ele<span class="token punctuation">,</span> next_ele<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">""" 点击元素直到出现预期的新元素 点击目标元素,返回点击后出现的新元素,没有则返回None :param target_ele: 需要点击的目标元素,如:(By.ID, "primary_btn"),传入的是一个元组 :param next_ele: 点击目标元素的后需要返回的新元素: :return: """</span> <span class="token keyword">def</span> <span class="token function">_predicate</span><span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># 点击目标元素</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span><span class="token operator">*</span>target_ele<span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 返回期待的下一个元素,不存在时返回None</span> <span class="token keyword">return</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span><span class="token operator">*</span>next_ele<span class="token punctuation">)</span> <span class="token keyword">return</span> _predicate WebDriverWait<span class="token punctuation">(</span>driver<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">.</span>until<span class="token punctuation">(</span> multi_clickable<span class="token punctuation">(</span><span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span> <span class="token string">"primary_btn"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span><span class="token string">'//*[text()="该弹框点击两次后才会弹出"]'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <h3>2.2.4高级控件的交互方法</h3> <h4>介绍</h4> <p>在进行selenium 操作时,有些场景需要模拟键鼠操作才可以实现,比如 复制粘贴、元素的拖拽等;selenium中提供<strong>ActionChains</strong>来实现相关的操作</p> <table> <thead> <tr> <th align="left">使用场景</th> <th align="left">对应事件</th> </tr> </thead> <tbody> <tr> <td align="left">复制粘贴</td> <td align="left">键盘事件</td> </tr> <tr> <td align="left">拖动元素到某个位置</td> <td align="left">鼠标事件</td> </tr> <tr> <td align="left">鼠标悬停</td> <td align="left">鼠标事件</td> </tr> <tr> <td align="left">滚动到某个元素</td> <td align="left">滚动事件</td> </tr> <tr> <td align="left">使用触控笔点击</td> <td align="left">触控笔事件(了解即可)</td> </tr> </tbody> </table> <h4>ActionChains基本用法</h4> <p>​ 在进行网页交互通常还有右击、双击、鼠标悬停、拖拽、ctrl+c复制以及粘贴,大写输入等控制,在selenium中提供了<strong>ActionChains</strong>类来实现各种键鼠操作。</p> <p>​ 当我们调用ActionChains的方法时,不会立即执行,而是会将所有的操作按顺序存放在一个队列里,当调用perform()方法时,队列中的事件才会依次执行。</p> <p>​ 使用的基本语法如下:</p> <p>​ 实例化化 ActionChains类: <code>ActionChains(driver)</code> ,其中driver为webdriver</p> <pre><code class="prism language-python"><span class="token comment"># 实例化时传入webdriver,调用perform()后操作才会执行</span> ActionChains<span class="token punctuation">(</span>self<span class="token punctuation">.</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>操作<span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre> <h5>键盘操作</h5> <ul> <li> <p>按下/释放某个键位</p> <p>按下shift 键 <code>key_down(Keys.SHIFT, ele)</code> ,<strong>其中ele 为定位的元素,必传</strong></p> <p>释放shift建 <code>key_up(Keys.SHIFT,el)</code>,<strong>其中ele 为定位的元素,必传</strong></p> </li> <li> <p>按键输入字符:</p> <p>输入 selenium <code>send_keys("selenium")</code></p> </li> <li> <p>输入回车</p> <ul> <li> <p>直接输入回车: 元素.send_keys(Keys.ENTER)</p> </li> <li> <p>使用ActionChains: key_down(Keys.ENTER)</p> </li> </ul> </li> <li> <p>复制、粘贴、剪切—组合键位</p> <p>上诉三个设计多个案件,其中需要用到的ctr 可以通过 key_down()方法进行控制,c、v、x 可以通过send_keys()输入需要的按键,需要注意的时,需要考虑系统的兼容</p> <ul> <li>多系统兼容 <ul> <li>mac 的复制按钮为 command +c</li> <li>windows 的复制按钮为 ctrl +c</li> </ul> </li> </ul> <p>示例:在输入输入字符后,全选剪切,再进行粘贴</p> <pre><code class="prism language-python"><span class="token comment"># 复制粘贴 win 和 mac 有所不同,因此区分下</span> cmd_ctrl <span class="token operator">=</span> Keys<span class="token punctuation">.</span>COMMAND <span class="token keyword">if</span> sys<span class="token punctuation">.</span>platform <span class="token operator">==</span> <span class="token string">'darwin'</span> <span class="token keyword">else</span> Keys<span class="token punctuation">.</span>CONTROL <span class="token comment"># 1.在输入框 先输入 chrome 2.ctr+a 全选 3.ctr+x 剪切 4. ctr+v 粘贴(3次)5.释放ctrl键</span> ActionChains<span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">'chrome'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>\ key_down<span class="token punctuation">(</span>cmd_ctrl<span class="token punctuation">,</span>el_search_input<span class="token punctuation">)</span><span class="token punctuation">.</span>\ send_keys<span class="token punctuation">(</span><span class="token string">'axvvv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>\ key_up<span class="token punctuation">(</span>cmd_ctrl<span class="token punctuation">,</span>el_search_input<span class="token punctuation">)</span><span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre> <p>源码:https://gitee.com/sailor233/seleniumDemo/blob/dev/try/keyboard2-copy-.py</p> </li> </ul> <h5>鼠标操作</h5> <p>官网:https://www.selenium.dev/documentation/webdriver/actions_api/mouse/</p> <ul> <li>双击:<code>double_click(元素对象)</code></li> <li>拖动元素:<code>drag_and_drop(起始元素对象, 结束元素对象)</code></li> <li>指定位置悬浮:<code>move_to_element(元素对象)</code></li> <li>鼠标右键:<code>context_click(元素对象)</code></li> <li>鼠标滚轮滚动操作:(selenium 版本需要在 4.2 之后) <ul> <li>官网:https://www.selenium.dev/documentation/webdriver/actions_api/wheel/</li> <li>滚动到元素:<code>scroll_to_element(WebElement对象)</code></li> <li>根据坐标滚动:<code>scroll_by_amount(横坐标, 纵坐标)</code></li> </ul> </li> </ul> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/4 23:00</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : ActionChains_MouseAction.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des : ActionChains的鼠标操作</span> <span class="token keyword">import</span> time <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver <span class="token keyword">import</span> ActionChains <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://vip.ceshiren.com/#/ui_study/mouseover'</span><span class="token punctuation">)</span> <span class="token comment"># 双击元素</span> ele_double <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'primary_btn'</span><span class="token punctuation">)</span> ActionChains<span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>double_click<span class="token punctuation">(</span>ele_double<span class="token punctuation">)</span><span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment"># 点击确定</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span><span class="token string">'.el-message-box__btns>button'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment"># 鼠标移入悬浮</span> moveToEle <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span><span class="token string">'[id="mouseover"]>button'</span><span class="token punctuation">)</span> ActionChains<span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>move_to_element<span class="token punctuation">(</span>moveToEle<span class="token punctuation">)</span><span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment"># 鼠标右键</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://vip.ceshiren.com/#/ui_study/clicks'</span><span class="token punctuation">)</span> right_ele <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span><span class="token string">'[id="rightClick"]>button'</span><span class="token punctuation">)</span> ActionChains<span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>context_click<span class="token punctuation">(</span>right_ele<span class="token punctuation">)</span><span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment"># 元素拖拽</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://vip.ceshiren.com/#/ui_study/action_chains'</span><span class="token punctuation">)</span> start_ele <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'item1'</span><span class="token punctuation">)</span> end_ele <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'item3'</span><span class="token punctuation">)</span> ActionChains<span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>drag_and_drop<span class="token punctuation">(</span>start_ele<span class="token punctuation">,</span>end_ele<span class="token punctuation">)</span><span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> </code></pre> <h3>2.25 网页多窗口和Frame的处理</h3> <h4>多窗口处理</h4> <p>在网页点击链接时,会打开新的窗口,如果我们想要在新的窗口进行操作,就需要先切换窗口。每个窗口都有一个句柄作为唯一标识,因此我们可以通过切换句柄来实现多个页面之前的灵活操作。</p> <ul> <li> <p>多窗口的处理流程</p> <ol> <li> <p>先获取当前窗口的窗口句柄(<code>dirver.current_window_handle</code>),返回句柄标识,一个字符串</p> <p>如:<code>B351ACAA077B689431FA53199D88D0C0</code></p> </li> <li> <p>获取所有的窗口句柄(<code>driver.window_handles</code>),返回一个列表,包含所有的句柄标识</p> <p>如: <code>['B351ACAA077B689431FA53199D88D0C0', 'CB85E316C47BC4C8B3A2FE51F0C0D736']</code></p> </li> <li> <p>判断当前窗口是否为想操作的窗口,如果是则对窗口进行操作;否则切换窗口 <code>driver.switch_to.window(all_windows[0])</code></p> </li> </ol> </li> <li> <p>案例</p> <ol> <li>打开百度页面</li> <li>点击登录</li> <li>弹框点击 <code>立即注册</code> 输入用户名和手机号</li> <li>返回刚才的登录页面,输入用户名、密码、点击登录</li> </ol> </li> </ul> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/6 22:08</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : switch_window.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des : selenium 多窗口切换操作</span> <span class="token keyword">from</span> time <span class="token keyword">import</span> sleep <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://wwww.baidu.com'</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>LINK_TEXT<span class="token punctuation">,</span><span class="token string">'登录'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 查看当前句柄标识</span> <span class="token keyword">print</span><span class="token punctuation">(</span>driver<span class="token punctuation">.</span>current_window_handle<span class="token punctuation">)</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>LINK_TEXT<span class="token punctuation">,</span><span class="token string">'立即注册'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 获取所有窗口的句柄标识</span> all_windows <span class="token operator">=</span> driver<span class="token punctuation">.</span>window_handles <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'all_windows:%s'</span> <span class="token operator">%</span>all_windows<span class="token punctuation">)</span> <span class="token comment"># 切换到新的窗口</span> driver<span class="token punctuation">.</span>switch_to<span class="token punctuation">.</span>window<span class="token punctuation">(</span>all_windows<span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment"># 输入用户名、手机号</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'TANGRAM__PSP_4__userName'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">'zhangsan'</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'TANGRAM__PSP_4__phone'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">'13594531258'</span><span class="token punctuation">)</span> <span class="token comment"># 切换会之前的窗口</span> driver<span class="token punctuation">.</span>switch_to<span class="token punctuation">.</span>window<span class="token punctuation">(</span>all_windows<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment"># 输入 用户名</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'TANGRAM__PSP_11__userName'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">'lisi'</span><span class="token punctuation">)</span> <span class="token comment"># 输入密码</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'TANGRAM__PSP_11__password'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">'adasda'</span><span class="token punctuation">)</span> <span class="token comment"># 点击登录</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span><span class="token string">'TANGRAM__PSP_11__submit'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> </code></pre> <h4>Frame的处理</h4> <ul> <li>介绍</li> </ul> <p>​ 在web页面中,html可以使用frame框架,在一个主页面中,利用frame创建不同的框架,从而实现在一个web页面呈现多个页面,每个frame框架的内容可以有自己的布局方式。因此有时定位不到元素可能就是因为元素,那么可能元素在ifrme中,可以查看元素是否被包含与frame标签中。</p> <p>​ w3c frame框架demo:https://www.w3school.com.cn/tiy/t.asp?f=eg_html_frame_cols</p> <p><a href="http://img.e-com-net.com/image/info8/32b0cb3c1c7b446fa236305f2b0614ee.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/32b0cb3c1c7b446fa236305f2b0614ee.jpg" alt="web UI自动化介绍_第9张图片" width="650" height="211" style="border:1px solid black;"></a></p> <p>其中Frame分为3类:</p> <ol> <li>frame标签包含 frameset、frame、iframe三种</li> <li>其中frameset与其他标签一样,可以使用id、name等selenium中任意支持的方式定位</li> <li>frame和iframe在selenium中有专门的定位方法</li> </ol> <ul> <li> <p><strong>多Frame切换</strong></p> <ol> <li>根据frame的id或者index 切换: <code>driver.switch_to.frame()</code></li> <li>切换到默认frame: <code>driver.swutch_to.default_conten()</code></li> <li>切换到父级frame(嵌套frame的情况): <code>driver.swicth_to.parent_frame()</code></li> </ol> <p>举例:拖动元素,其中两个元素在iframe中</p> </li> </ul> <p>​ 演示环境:https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable</p> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/10 23:28</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : frame.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des : 演示地址https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable</span> <span class="token keyword">from</span> time <span class="token keyword">import</span> sleep <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver <span class="token keyword">import</span> ActionChains <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'</span><span class="token punctuation">)</span> <span class="token comment"># 切换到 iframe框架内</span> driver<span class="token punctuation">.</span>switch_to<span class="token punctuation">.</span>frame<span class="token punctuation">(</span><span class="token string">'iframeResult'</span><span class="token punctuation">)</span> ele_drag <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span><span class="token string">'//*[text()="请拖拽我!"]'</span><span class="token punctuation">)</span> ele_drop <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span><span class="token string">'//*[text()="请放置到这里!"]'</span><span class="token punctuation">)</span> ActionChains<span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>drag_and_drop<span class="token punctuation">(</span>ele_drag<span class="token punctuation">,</span>ele_drop<span class="token punctuation">)</span><span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 切换会主框架</span> driver<span class="token punctuation">.</span>switch_to<span class="token punctuation">.</span>default_content<span class="token punctuation">(</span><span class="token punctuation">)</span> sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> </code></pre> <h3>文件上传以及弹窗处理</h3> <h4>文件上传</h4> <p>如果页面使用web页面使用 input标签实现文件上传,可以直接使用send_keys(文件绝对地址)进行上传文件</p> <p>步骤如下:</p> <ol> <li>找到上传按钮: <code>el = driver.find_element(By.CSS_SELECTOR,'.upload-pic')</code></li> <li>使用上传按钮上传图片:<code>el.send_keys(jpg_path)</code></li> </ol> <p>ps: 也可以直接合并为一步</p> <p>举例:使用百度首页,点击图片上传功能,上传图片</p> <p><a href="http://img.e-com-net.com/image/info8/ec5d37dc58d04f109bb14b70bd9c1b47.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/ec5d37dc58d04f109bb14b70bd9c1b47.jpg" alt="web UI自动化介绍_第10张图片" width="650" height="308" style="border:1px solid black;"></a></p> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/11 22:08</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : file_upload.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des : 文件上传处理</span> <span class="token keyword">import</span> os <span class="token keyword">import</span> time <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://www.baidu.com'</span><span class="token punctuation">)</span> <span class="token comment"># 点击 相机按钮</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span><span class="token string">'.soutu-btn'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 点击 选择文件 按钮</span> el <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span><span class="token string">'.upload-pic'</span><span class="token punctuation">)</span> <span class="token comment"># 获取文件的绝对路径</span> jpg_path <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>abspath<span class="token punctuation">(</span><span class="token string">'test.jpg'</span><span class="token punctuation">)</span> <span class="token comment"># 上传文件</span> el<span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span>jpg_path<span class="token punctuation">)</span> time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span> </code></pre> <h4>弹窗处理</h4> <p>在页面操作时,有时候会出现由js生成的弹窗,如alert、confirm以及prompt;在selenium中可以使用 `switch_to.alert 进行定位。</p> <p>常用方法如下:</p> <ol> <li>切换到弹框:<code>switch_to.alert</code></li> <li>获取弹窗中的文本信息:<code>text</code></li> <li>接受现有警告框:<code>accept()</code></li> <li>解散警告框:<code>dismiss()</code></li> <li>发送文本到警告框: <code>send_keys()</code></li> </ol> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/11 22:55</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : alert.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des :</span> <span class="token keyword">from</span> time <span class="token keyword">import</span> sleep <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver <span class="token keyword">import</span> ActionChains <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'</span><span class="token punctuation">)</span> <span class="token comment"># 切换到 iframe框架内</span> driver<span class="token punctuation">.</span>switch_to<span class="token punctuation">.</span>frame<span class="token punctuation">(</span><span class="token string">'iframeResult'</span><span class="token punctuation">)</span> ele_drag <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span><span class="token string">'//*[text()="请拖拽我!"]'</span><span class="token punctuation">)</span> ele_drop <span class="token operator">=</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span><span class="token string">'//*[text()="请放置到这里!"]'</span><span class="token punctuation">)</span> ActionChains<span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">.</span>drag_and_drop<span class="token punctuation">(</span>ele_drag<span class="token punctuation">,</span>ele_drop<span class="token punctuation">)</span><span class="token punctuation">.</span>perform<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 切换到弹窗并点击确认</span> driver<span class="token punctuation">.</span>switch_to<span class="token punctuation">.</span>alert<span class="token punctuation">.</span>accept<span class="token punctuation">(</span><span class="token punctuation">)</span> sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> </code></pre> <h3>关键数据记录</h3> <h4>介绍</h4> <p>​ 为了后续排查错误,需要将自动化执行过程中的关键数据记录下来,关键数据执行日志、执行行为的截图、页面源码,以下分别对三种数据的功能进行介绍</p> <ol> <li> <p>代码的执行日志</p> <ul> <li>记录代码的执行记录,方便复现场景</li> <li>可以作为bug依据</li> <li>用法:在关键位置使用 logging库打印日志</li> </ul> </li> <li> <p>代码执行的截图</p> <ul> <li>断言失败或成功截图</li> <li>异常截图达到丰富报告的作用</li> <li>可以作为bug依据</li> <li>用法:<code> driver.save_screenshot('./images/search1.png')</code></li> </ul> </li> <li> <p>page source(页面源代码)<code>self.driver.page_source</code></p> <ul> <li> <p>协助排查报错时元素当时是否存在页面上</p> </li> <li> <p>用法:</p> <pre><code class="prism language-python"><span class="token comment"># 在报错行前面添加保存page_source的操作</span> <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">"record.html"</span><span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"u8"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span> f<span class="token punctuation">.</span>write<span class="token punctuation">(</span>self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>page_source<span class="token punctuation">)</span> </code></pre> </li> </ul> </li> </ol> <h4>示范</h4> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/12 22:21</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : reord.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des :</span> <span class="token comment"># 日志与脚本结合</span> <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By <span class="token keyword">from</span> logUtil <span class="token keyword">import</span> logger <span class="token keyword">class</span> <span class="token class-name">TestDataRecord</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">setup_class</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">teardown_class</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>quit<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">test_log_data_record</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># 实例化self.driver</span> search_content <span class="token operator">=</span> <span class="token string">"霍格沃兹测试开发学社"</span> <span class="token comment"># 打开百度首页</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"https://www.sogou.com/"</span><span class="token punctuation">)</span> logger<span class="token punctuation">.</span>debug<span class="token punctuation">(</span><span class="token string">"打开搜狗首页"</span><span class="token punctuation">)</span> <span class="token comment"># 输入霍格沃兹测试学院</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">"#query"</span><span class="token punctuation">)</span><span class="token punctuation">.</span> \ send_keys<span class="token punctuation">(</span>search_content<span class="token punctuation">)</span> logger<span class="token punctuation">.</span>debug<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"搜索的内容为</span><span class="token interpolation"><span class="token punctuation">{</span>search_content<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span> <span class="token comment"># 点击搜索</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">"#stb"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 搜索结果</span> search_res <span class="token operator">=</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">"em"</span><span class="token punctuation">)</span> <span class="token comment"># 保存搜索结构截图</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>save_screenshot<span class="token punctuation">(</span><span class="token string">'searchResult.jpg'</span><span class="token punctuation">)</span> <span class="token comment"># 保存页面源码</span> <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">"record.html"</span><span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"u8"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span> f<span class="token punctuation">.</span>write<span class="token punctuation">(</span>self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>page_source<span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"搜索结果为</span><span class="token interpolation"><span class="token punctuation">{</span>search_res<span class="token punctuation">.</span>text<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span> <span class="token keyword">assert</span> search_res<span class="token punctuation">.</span>text <span class="token operator">==</span> search_content </code></pre> <p>日志模块:</p> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/12 22:20</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : logUtil.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des :</span> <span class="token comment"># 日志配置</span> <span class="token keyword">import</span> logging <span class="token comment"># 创建logger实例</span> logger <span class="token operator">=</span> logging<span class="token punctuation">.</span>getLogger<span class="token punctuation">(</span><span class="token string">'simple_example'</span><span class="token punctuation">)</span> <span class="token comment"># 设置日志级别</span> logger<span class="token punctuation">.</span>setLevel<span class="token punctuation">(</span>logging<span class="token punctuation">.</span>DEBUG<span class="token punctuation">)</span> <span class="token comment"># 流处理器</span> ch <span class="token operator">=</span> logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span> ch<span class="token punctuation">.</span>setLevel<span class="token punctuation">(</span>logging<span class="token punctuation">.</span>DEBUG<span class="token punctuation">)</span> <span class="token comment"># 日志打印格式</span> formatter <span class="token operator">=</span> logging<span class="token punctuation">.</span>Formatter\ <span class="token punctuation">(</span><span class="token string">'%(asctime)s - %(name)s - %(levelname)s - %(message)s'</span><span class="token punctuation">)</span> <span class="token comment"># 添加格式配置</span> ch<span class="token punctuation">.</span>setFormatter<span class="token punctuation">(</span>formatter<span class="token punctuation">)</span> <span class="token comment"># 添加日志配置</span> logger<span class="token punctuation">.</span>addHandler<span class="token punctuation">(</span>ch<span class="token punctuation">)</span> </code></pre> <h3>练习项目1-litemall商城管理后台</h3> <p>在litemall管理商城后台 对商品类目进行添加 和删除</p> <p>产品信息:</p> <ul> <li>地址:<em>http://litemall.hogwarts.ceshiren.com/#/dashboard</em></li> <li>使用账户,用户名: manage 密码: manage123</li> </ul> <p>实现的用例场景:</p> <table> <thead> <tr> <th align="left">用例标题</th> <th align="left">前提条件</th> <th align="left">执行步骤</th> <th align="left">预期结果</th> </tr> </thead> <tbody> <tr> <td align="left">添加商品</td> <td align="left">1. 登录并进入用户管理后台 <br>2. 登录账号有商品管理的权限</td> <td align="left">1. 点击增加<br> 2. 输入商品名称和商品编号<br> 3. 点击 上架</td> <td align="left">1. 跳转商品列表<br> 2. 新增在第一行行,新增成功</td> </tr> <tr> <td align="left">删除商品</td> <td align="left">1. 进入用户管理后台<br> 2. 商品列表里面有已存在的商品(新增)</td> <td align="left">1. 点击删除按钮</td> <td align="left">1. 是否有删除成功提示 <br>2. 被删除商品不在商品类目列表展示</td> </tr> </tbody> </table> <p>脚本编写思路:</p> <ol> <li>编写前置后置操作,如drvier的初始化、登录平台等</li> <li>实现基本功能</li> <li>代码优化,将强制等待换为隐式等待</li> <li>完善细节:日志、报告、截图</li> </ol> <h4>前置后置操作</h4> <p>前置操作setup_class中,实现浏览器的打开、隐式等待</p> <p>后置操作teardown_class 中,实现浏览器的关闭</p> <pre><code>class TestLiteMall: def setup_class(self): self.driver = webdriver.Chrome() # 初始化driver,使用chrome浏览器 self.driver.maximize_window() # 最大化浏览器窗口 self.driver.implicitly_wait(5) # 全局设置隐式等待5s def teardown_class(self): self.driver.quit() # 退出浏览器 </code></pre> <p>实现基本功能:</p> <p>基本功能分为:登录、新增商品、删除商品</p> <h4>登录功能</h4> <pre><code class="prism language-python"><span class="token keyword">def</span> <span class="token function">login</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">""" 实现登录功能 :return: """</span> <span class="token comment"># 由于用户名 和 密码有原本文本,需要先清除</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>NAME<span class="token punctuation">,</span> <span class="token string">'username'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>clear<span class="token punctuation">(</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>NAME<span class="token punctuation">,</span> <span class="token string">'username'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">'manage'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>NAME<span class="token punctuation">,</span> <span class="token string">'password'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>clear<span class="token punctuation">(</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>NAME<span class="token punctuation">,</span> <span class="token string">'password'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">'manage123'</span><span class="token punctuation">)</span> <span class="token comment"># 点击登录按钮</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">'button'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre> <h4>新增商品</h4> <pre><code class="prism language-python"><span class="token keyword">def</span> <span class="token function">add_merchandise</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> merchandise_id<span class="token punctuation">,</span> merchandise_name<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">""" 添加商品 :param merchandise_id:商品ID :param merchandise_name:商品名称 :return: 无 """</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'点击商品管理'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//*[text()="商品管理"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'点金商品列表'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//*[text()="商品列表"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'点击点击按钮'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">'.filter-container>button:nth-of-type(2)'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'输入商品编号'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//*[text()="商品编号"]/../div/div/input'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span>merchandise_id<span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'输入商品名称'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//*[text()="商品名称"]/../div/div/input'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span>merchandise_name<span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'点击上架'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">'.op-container>button:nth-child(2)'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre> <h4>删除商品</h4> <pre><code class="prism language-python"><span class="token keyword">def</span> <span class="token function">delet_merchandise</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> merchandise_id<span class="token operator">=</span><span class="token string">'1439956'</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token triple-quoted-string string">""" 通过商品id删除商品 :param merchandise_id:商品对应的id :return: """</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'点击商品管理'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//*[text()="商品管理"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'点金商品列表'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//*[text()="商品列表"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f'通过商品id:</span><span class="token interpolation"><span class="token punctuation">{</span>merchandise_id<span class="token punctuation">}</span></span><span class="token string">,定位到对应删除按钮后 点击删除'</span></span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string-interpolation"><span class="token string">f'//*[text()="</span><span class="token interpolation"><span class="token punctuation">{</span>merchandise_id<span class="token punctuation">}</span></span><span class="token string">"]/../../td[last()]/div/button[2]'</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre> <h4>新增商品测试用例</h4> <pre><code class="prism language-python"><span class="token decorator annotation punctuation">@pytest<span class="token punctuation">.</span>mark<span class="token punctuation">.</span>parametrize</span><span class="token punctuation">(</span><span class="token string">'merchandise_id,merchandise_name'</span><span class="token punctuation">,</span> test_add_data<span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">test_add_merchandise</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> merchandise_id<span class="token punctuation">,</span> merchandise_name<span class="token punctuation">)</span><span class="token punctuation">:</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f'测试添加商品:</span><span class="token interpolation"><span class="token punctuation">{</span>merchandise_id<span class="token punctuation">}</span></span><span class="token string">,</span><span class="token interpolation"><span class="token punctuation">{</span>merchandise_name<span class="token punctuation">}</span></span><span class="token string">'</span></span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>add_merchandise<span class="token punctuation">(</span>merchandise_id<span class="token punctuation">,</span> merchandise_name<span class="token punctuation">)</span> logger<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">'断言出现提示信息:创建成功'</span><span class="token punctuation">)</span> WebDriverWait<span class="token punctuation">(</span>self<span class="token punctuation">.</span>driver<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">.</span>until<span class="token punctuation">(</span> expected_conditions<span class="token punctuation">.</span>visibility_of_element_located<span class="token punctuation">(</span><span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//p[text()="创建成功"]'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">assert</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">'//p[text()="创建成功"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>text <span class="token operator">==</span> <span class="token string">'创建成功'</span> </code></pre> <h2>2.3 高级</h2> <h3>2.3.1 浏览器复用-托管</h3> <ul> <li> <p>介绍</p> <p>浏览器复用指的是 selenium代码执行调用的浏览器与我们当前使用的浏览器是一个,而不是从新打开一个由selenium控制打开的浏览器;这样实现便于自动测试过程中的人为介入,从而提高测试效率。</p> <p>如果seleniu控制打开时一个新的chrome,不会携带任何cookie信息等,不利用人工介入如扫码登陆、调式等,具体场景举例:</p> <ol> <li>当运行 selenium 自动化时,要求已经登录才能才做。这个时候我们可以提前登录,运行脚本的时候复用已经打开的浏览器。</li> <li>当调试了某个步骤很多的测试用例,前面N-1步已经成功,只需调试第N步。如果从头开始运行脚本,耗时过多,这时我们可以直接复用浏览器手动操作第N不进行调试。</li> </ol> </li> <li> <p>配置步骤</p> <ol> <li> <p>首先退出当前所有的谷歌浏览器,其中windows还需打开任务管理器 查看chrome进程是否关闭</p> </li> <li> <p>配置环境变量,将chrome浏览器exe文件所在位置放到环境变量path中</p> <p><a href="http://img.e-com-net.com/image/info8/44dcee1374a249af8b831b202f1ac4b8.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/44dcee1374a249af8b831b202f1ac4b8.jpg" alt="web UI自动化介绍_第11张图片" width="650" height="519" style="border:1px solid black;"></a></p> </li> <li> <p>验证是否配置成功</p> <ol> <li> <p>重新打开cmd命令输入以下命令,打开浏览器</p> <pre><code class="prism language-shell">chrome --remote-debugging-port<span class="token operator">=</span><span class="token number">9222</span> </code></pre> </li> <li> <p>再打开的浏览器输入 <code>localhost:9222</code> 会打开一个空白页面或者一个简单页面</p> </li> </ol> </li> </ol> </li> <li> <p>代码中使用</p> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/25 22:25</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : chrome_remote.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des :</span> <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>chrome<span class="token punctuation">.</span>options <span class="token keyword">import</span> Options opt <span class="token operator">=</span> Options<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 地址要和cmd启动的一致chrome一致</span> opt<span class="token punctuation">.</span>debugger_address <span class="token operator">=</span> <span class="token string">'localhost:9222'</span> <span class="token comment"># 实例化driver传入 启动的chrome地址</span> driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span>options<span class="token operator">=</span>opt<span class="token punctuation">)</span> <span class="token comment"># 使用已打开的chrome 打开百度,而不是重新启动一个chrome浏览器</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'http://www.baidu.com'</span><span class="token punctuation">)</span> </code></pre> </li> </ul> <h3>2.3.2 cookie复用</h3> <ul> <li> <p>cookie是什么</p> <p>Cookie是保存在计算机上的一种文件。当我们使用计算机浏览网页时,服务器会生成一个证书并将其返回给我们的计算机。这个证书是cookie。一般来说,cookie是服务器写给客户端的文件,也可以称为浏览器缓存,复用已有的cookie,可以直接登录,不需要重新进行登录认证;对于部分只能扫码登录的应用,可以先登录后,保存cookie,后续直接使用cookie进行访问。</p> </li> <li> <p>为什么需要复用cookie</p> <ul> <li>复用浏览器仍然在每次用例开始都需要人为介入</li> <li>若用例需要经常执行,复用浏览器则不是一个好的选择</li> <li>大部分cookie的时效性都很长,扫一次可以使用多次</li> </ul> </li> <li> <p>复用cookie的思路</p> <ol> <li>打开浏览器,扫码登录</li> <li>确保登录之后(重点!!!),获取cookies</li> <li>检查本地文件是否已经获取成功</li> <li>再次打开浏览器,通过cookie直接进入主页</li> </ol> </li> <li> <p>代码实现</p> <ul> <li>获取cookie:<code>driver.get_cookies()</code></li> <li>添加cookie: <code>driver.add_cookie(cookie)</code></li> </ul> </li> <li> <p>demo 企业微信登录cookie复用</p> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @Time : 2023/7/26 21:58</span> <span class="token comment"># @Author : sailor233</span> <span class="token comment"># @File : test_cookie.py</span> <span class="token comment"># @Software: PyCharm</span> <span class="token comment"># @Des :</span> <span class="token keyword">from</span> time <span class="token keyword">import</span> sleep <span class="token keyword">import</span> yaml <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">def</span> <span class="token function">test_getcookie</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://work.weixin.qq.com/wework_admin/loginpage_wx?from=myhome'</span><span class="token punctuation">)</span> <span class="token comment"># 获取cookie</span> <span class="token comment"># get_cookie()</span> add_cookies<span class="token punctuation">(</span>driver<span class="token punctuation">)</span> driver<span class="token punctuation">.</span>refresh<span class="token punctuation">(</span><span class="token punctuation">)</span> sleep<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">get_cookie</span><span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># 获取cookies</span> cookies <span class="token operator">=</span> driver<span class="token punctuation">.</span>get_cookies<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 将获取到的cookie保存到文件中</span> <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'cookie.yaml'</span><span class="token punctuation">,</span> <span class="token string">'w'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span> yaml<span class="token punctuation">.</span>safe_dump<span class="token punctuation">(</span>cookies<span class="token punctuation">,</span> f<span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">add_cookies</span><span class="token punctuation">(</span>driver<span class="token punctuation">)</span><span class="token punctuation">:</span> cookies <span class="token operator">=</span> yaml<span class="token punctuation">.</span>safe_load<span class="token punctuation">(</span><span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'cookie.yaml'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">for</span> cookie <span class="token keyword">in</span> cookies<span class="token punctuation">:</span> driver<span class="token punctuation">.</span>add_cookie<span class="token punctuation">(</span>cookie<span class="token punctuation">)</span> </code></pre> </li> <li> <p>常见问题</p> <ol> <li>获取cookie的时候,即执行代码获取cookie时,一定要确保已经登录</li> <li>植入cookie之后需要进入登录页面,刷新验证是否自动登录成功。</li> </ol> </li> </ul> <h3>2.3.3 Page Object思想</h3> <p>传统的UI自动化是线性脚本,元素操作、断言等步骤混合在一起,当UI存在变换时改动非常麻烦,工作量很大,也无法清晰的表达出业务用例的场景。</p> <ul> <li> <p>PO思想简介</p> <p>把一个具体的页面转换成编程语言当中的一个类,页面特性转化成对象属性,页面操作转换成对象方法。</p> </li> <li> <p>PO建模原则</p> <ul> <li>字段意义 <ul> <li>不要暴露页面内的所有元素给外部</li> <li>不需要建模UI内的所有元素,元素很多无法重复建模,选择重点元素</li> </ul> </li> <li>方法意义 <ul> <li>用公共方法代表UI所提供的的功能</li> <li>方法应该返回其他PageObject的或者返回用于断言的数据</li> <li>同样的行为不同结果可以建模不同的方法</li> <li>不要在方法内加断言</li> </ul> </li> </ul> </li> </ul> <p>以测试登录雪球测试为例:</p> <ul> <li>之前的线性脚本:</li> </ul> <pre><code class="prism language-python"><span class="token keyword">class</span> <span class="token class-name">TestSearch</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">test_search</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># 初始化浏览器</span> self<span class="token punctuation">.</span>driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"https://xueqiu.com/"</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token comment"># 输入搜索关键词</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>NAME<span class="token punctuation">,</span> <span class="token string">"q"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span><span class="token string">"阿里巴巴-SW"</span><span class="token punctuation">)</span> <span class="token comment"># 点击搜索按钮</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">"i.search"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># 获取搜索结果</span> name <span class="token operator">=</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">"//table//strong"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>text <span class="token comment"># 断言</span> <span class="token keyword">assert</span> name <span class="token operator">==</span> <span class="token string">"阿里巴巴-SW"</span> </code></pre> <ul> <li> <p>使用PO思想设计测试脚本</p> <ul> <li> <p>先封装搜索页面</p> <pre><code class="prism language-python"><span class="token comment">#!/usr/bin/env python</span> <span class="token comment"># -*- coding: utf-8 -*-</span> <span class="token comment"># @File : search_page.py</span> <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By <span class="token keyword">class</span> <span class="token class-name">SearchPage</span><span class="token punctuation">:</span> __INPUT_SEARCH <span class="token operator">=</span> <span class="token punctuation">(</span>By<span class="token punctuation">.</span>NAME<span class="token punctuation">,</span> <span class="token string">"q"</span><span class="token punctuation">)</span> __BUTTON_SEARCH <span class="token operator">=</span> <span class="token punctuation">(</span>By<span class="token punctuation">.</span>CSS_SELECTOR<span class="token punctuation">,</span> <span class="token string">"i.search"</span><span class="token punctuation">)</span> __SPAN_STOCK <span class="token operator">=</span> <span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">"//table//strong"</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>implicitly_wait<span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"https://xueqiu.com/"</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">search_stock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> stock_name<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span><span class="token operator">*</span>self<span class="token punctuation">.</span>__INPUT_SEARCH<span class="token punctuation">)</span><span class="token punctuation">.</span>send_keys<span class="token punctuation">(</span>stock_name<span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span><span class="token operator">*</span>self<span class="token punctuation">.</span>__BUTTON_SEARCH<span class="token punctuation">)</span><span class="token punctuation">.</span>click<span class="token punctuation">(</span><span class="token punctuation">)</span> name <span class="token operator">=</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>XPATH<span class="token punctuation">,</span> <span class="token string">"//table//strong"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>text <span class="token keyword">return</span> name </code></pre> </li> <li> <p>测试用例</p> <pre><code class="prism language-python"><span class="token keyword">from</span> search_page <span class="token keyword">import</span> SearchPage <span class="token keyword">class</span> <span class="token class-name">TestSearch</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">test_search</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> text <span class="token operator">=</span> SearchPage<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>search_stock<span class="token punctuation">(</span><span class="token string">"阿里巴巴-SW"</span><span class="token punctuation">)</span> <span class="token comment"># 断言</span> <span class="token keyword">assert</span> <span class="token string">"阿里巴巴-SW"</span> <span class="token operator">==</span> text </code></pre> </li> </ul> </li> </ul> <h3>2.3.4 异常记录关键信息</h3> <h4>常规的记录方法</h4> <p>一般记录方式使用try,except 进行记录</p> <pre><code class="prism language-python"><span class="token keyword">import</span> time <span class="token keyword">import</span> allure <span class="token keyword">from</span> selenium <span class="token keyword">import</span> webdriver <span class="token keyword">from</span> selenium<span class="token punctuation">.</span>webdriver<span class="token punctuation">.</span>common<span class="token punctuation">.</span>by <span class="token keyword">import</span> By <span class="token comment"># 问题1: 异常处理会影响用例本身的结果</span> <span class="token comment"># 解决方案: 需要在异常处理后使用raise 再把异常抛出去</span> <span class="token comment"># 问题2:异常处理的逻辑与业务无关,添加后显得非常冗余,需要进行解耦</span> <span class="token comment"># 解决方案: 使用装饰器进行异常逻辑的处理</span> <span class="token keyword">class</span> <span class="token class-name">TestBaidu</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">test</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'http://www.baidu.com'</span><span class="token punctuation">)</span> <span class="token keyword">try</span><span class="token punctuation">:</span> <span class="token comment"># 查找一个不存在的id</span> driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span> <span class="token string">'su1'</span><span class="token punctuation">)</span> <span class="token keyword">except</span> Exception<span class="token punctuation">:</span> timestamp <span class="token operator">=</span> <span class="token builtin">int</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> image_path <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f'./images/image_</span><span class="token interpolation"><span class="token punctuation">{</span>timestamp<span class="token punctuation">}</span></span><span class="token string">.PNG'</span></span> <span class="token comment"># 需要先创建imagse目录</span> <span class="token comment"># 保存截图</span> driver<span class="token punctuation">.</span>save_screenshot<span class="token punctuation">(</span>image_path<span class="token punctuation">)</span> <span class="token comment"># 保存源码</span> page_path <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f'./page_source/page_</span><span class="token interpolation"><span class="token punctuation">{</span>timestamp<span class="token punctuation">}</span></span><span class="token string">.html'</span></span> <span class="token comment"># 需要先创建page_source目录</span> <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>page_path<span class="token punctuation">,</span> <span class="token string">'w'</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span> f<span class="token punctuation">.</span>write<span class="token punctuation">(</span>driver<span class="token punctuation">.</span>page_source<span class="token punctuation">)</span> <span class="token comment"># 将截图放入allure测试报告</span> allure<span class="token punctuation">.</span>attach<span class="token punctuation">.</span><span class="token builtin">file</span><span class="token punctuation">(</span>image_path<span class="token punctuation">,</span> name<span class="token operator">=</span><span class="token string">'picture'</span><span class="token punctuation">,</span> attachment_type<span class="token operator">=</span>allure<span class="token punctuation">.</span>attachment_type<span class="token punctuation">.</span>PNG<span class="token punctuation">)</span> <span class="token comment"># 将源码放入allure测试报告</span> allure<span class="token punctuation">.</span>attach<span class="token punctuation">.</span><span class="token builtin">file</span><span class="token punctuation">(</span>page_path<span class="token punctuation">,</span> name<span class="token operator">=</span><span class="token string">'pagesoce'</span><span class="token punctuation">,</span> attachment_type<span class="token operator">=</span>allure<span class="token punctuation">.</span>attachment_type<span class="token punctuation">.</span>HTML<span class="token punctuation">)</span> <span class="token keyword">raise</span> Exception </code></pre> <p>使用allure命令 可以生成测试报告 并看到执行后保存的数据:</p> <pre><code class="prism language-bash">pytest <span class="token parameter variable">--alluredir</span><span class="token operator">=</span>./report allure serve ./report </code></pre> <p><a href="http://img.e-com-net.com/image/info8/8cd022f5cfef4432b2a5f87dd934f35f.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/8cd022f5cfef4432b2a5f87dd934f35f.jpg" alt="web UI自动化介绍_第12张图片" width="650" height="225" style="border:1px solid black;"></a></p> <ul> <li> <p>存在的问题</p> <ol> <li> <p>由于添加了异常处理,影响了用例本身的执行结果,本该是执行失败的结果测试报告中显示 <strong>Passed</strong></p> <p>解决方式: 在exception后捕获了异常并处理的最后增加语句抛出异常:<code>raise Exeception</code></p> <p>执行结果:<code>pytest --alluredir=./report</code> 、 <code>allure serve ./report</code></p> <p><a href="http://img.e-com-net.com/image/info8/7e34e9209e454a4db0445f7142a8817f.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/7e34e9209e454a4db0445f7142a8817f.jpg" alt="web UI自动化介绍_第13张图片" width="650" height="178" style="border:1px solid black;"></a></p> </li> <li> <p>异常处理代码和业务无关,不能耦合否则用例</p> <p>解决方法:使用装饰器,就可以不体现在源码中</p> </li> </ol> </li> </ul> <h4>使用装饰器记录</h4> <ul> <li> <p>装饰器函数</p> <pre><code class="prism language-python"><span class="token comment"># 问题3: 通driver进行截图时、获取源码时报错没有driver</span> <span class="token comment"># 解决方案: 通过debug可以看到args[0]中存在TestBaidu的实例对象,它包含了实例属性self.driver,</span> <span class="token comment"># 因此可以通过# args[0].driver获取drievr</span> <span class="token comment"># 问题4:当某测试函数执行后没有返回值,</span> <span class="token comment"># 解决方法: 执行 装饰函数时需要return</span> <span class="token keyword">def</span> <span class="token function">ui_exception_record</span><span class="token punctuation">(</span>func<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">wrapper</span><span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">,</span> <span class="token operator">**</span>kwargs<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">try</span><span class="token punctuation">:</span> <span class="token comment"># 成功后需要返回,否则无法看到返回值</span> <span class="token keyword">return</span> func<span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">,</span> <span class="token operator">**</span>kwargs<span class="token punctuation">)</span> <span class="token keyword">except</span> Exception<span class="token punctuation">:</span> <span class="token comment"># 获取被装饰方式的实例对象self</span> <span class="token comment"># 前提条件:1.被装饰方法是一个实例方法 2.获取的变量也是实例变量即是self.driver</span> <span class="token comment"># 根据调试 可以看到args[0]是类TestBaidu的实例对象,存在实例属性 driver</span> driver <span class="token operator">=</span> args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>driver <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'出现异常'</span><span class="token punctuation">)</span> timestamp <span class="token operator">=</span> <span class="token builtin">int</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> image_path <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f'./images/image_</span><span class="token interpolation"><span class="token punctuation">{</span>timestamp<span class="token punctuation">}</span></span><span class="token string">.PNG'</span></span> <span class="token comment"># 需要先创建imagse目录</span> <span class="token comment"># 保存截图</span> driver<span class="token punctuation">.</span>save_screenshot<span class="token punctuation">(</span>image_path<span class="token punctuation">)</span> <span class="token comment"># 保存源码</span> page_path <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f'./page_source/page_</span><span class="token interpolation"><span class="token punctuation">{</span>timestamp<span class="token punctuation">}</span></span><span class="token string">.html'</span></span> <span class="token comment"># 需要先创建page_source目录</span> <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>page_path<span class="token punctuation">,</span> <span class="token string">'w'</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span> f<span class="token punctuation">.</span>write<span class="token punctuation">(</span>driver<span class="token punctuation">.</span>page_source<span class="token punctuation">)</span> <span class="token comment"># 将截图放入allure测试报告</span> allure<span class="token punctuation">.</span>attach<span class="token punctuation">.</span><span class="token builtin">file</span><span class="token punctuation">(</span>image_path<span class="token punctuation">,</span> name<span class="token operator">=</span><span class="token string">'picture'</span><span class="token punctuation">,</span> attachment_type<span class="token operator">=</span>allure<span class="token punctuation">.</span>attachment_type<span class="token punctuation">.</span>PNG<span class="token punctuation">)</span> <span class="token comment"># 将源码放入allure测试报告</span> allure<span class="token punctuation">.</span>attach<span class="token punctuation">.</span><span class="token builtin">file</span><span class="token punctuation">(</span>page_path<span class="token punctuation">,</span> name<span class="token operator">=</span><span class="token string">'pagesoce'</span><span class="token punctuation">,</span> attachment_type<span class="token operator">=</span>allure<span class="token punctuation">.</span>attachment_type<span class="token punctuation">.</span>HTML<span class="token punctuation">)</span> <span class="token keyword">raise</span> Exception <span class="token keyword">return</span> wrapper </code></pre> <ul> <li>装饰执行测试函数:</li> </ul> <pre><code class="prism language-python"><span class="token keyword">class</span> <span class="token class-name">TestBaidu</span><span class="token punctuation">:</span> <span class="token decorator annotation punctuation">@ui_exception_record</span> <span class="token keyword">def</span> <span class="token function">test</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>driver <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Chrome<span class="token punctuation">(</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'http://www.baidu.com'</span><span class="token punctuation">)</span> self<span class="token punctuation">.</span>driver<span class="token punctuation">.</span>find_element<span class="token punctuation">(</span>By<span class="token punctuation">.</span>ID<span class="token punctuation">,</span> <span class="token string">'su1'</span><span class="token punctuation">)</span> </code></pre> <p>通过装饰器的使用,在测试函数中出现异常的处理不体现在业务逻辑中,程序变得非常优雅</p> </li> </ul> <h3>UI自动化的常见项目结构</h3> <pre><code class="prism language-python"><span class="token operator">-</span> page<span class="token punctuation">:</span> 页面对象 <span class="token operator">-</span> testcases<span class="token punctuation">:</span> 测试用例 <span class="token operator">-</span> utils<span class="token punctuation">:</span> 公共工具 <span class="token operator">-</span> log<span class="token punctuation">:</span> 日志信息 </code></pre> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1702733678897082368"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(Web,UI,自动化,ui,自动化,自动化测试,selenium)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835513551142350848.htm" title="OC语言多界面传值五大方式" target="_blank">OC语言多界面传值五大方式</a> <span class="text-muted">Magnetic_h</span> <a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/objective-c/1.htm">objective-c</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>前言在完成暑假仿写项目时,遇到了许多需要用到多界面传值的地方,这篇博客来总结一下比较常用的五种多界面传值的方式。属性传值属性传值一般用前一个界面向后一个界面传值,简单地说就是通过访问后一个视图控制器的属性来为它赋值,通过这个属性来做到从前一个界面向后一个界面传值。首先在后一个界面中定义属性@interfaceBViewController:UIViewController@propertyNSSt</div> </li> <li><a href="/article/1835513424734416896.htm" title="UI学习——cell的复用和自定义cell" target="_blank">UI学习——cell的复用和自定义cell</a> <span class="text-muted">Magnetic_h</span> <a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a> <div>目录cell的复用手动(非注册)自动(注册)自定义cellcell的复用在iOS开发中,单元格复用是一种提高表格(UITableView)和集合视图(UICollectionView)滚动性能的技术。当一个UITableViewCell或UICollectionViewCell首次需要显示时,如果没有可复用的单元格,则视图会创建一个新的单元格。一旦这个单元格滚动出屏幕,它就不会被销毁。相反,它被添</div> </li> <li><a href="/article/1835512920797179904.htm" title="element实现动态路由+面包屑" target="_blank">element实现动态路由+面包屑</a> <span class="text-muted">软件技术NINI</span> <a class="tag" taget="_blank" href="/search/vue%E6%A1%88%E4%BE%8B/1.htm">vue案例</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>el-breadcrumb是ElementUI组件库中的一个面包屑导航组件,它用于显示当前页面的路径,帮助用户快速理解和导航到应用的各个部分。在Vue.js项目中,如果你已经安装了ElementUI,就可以很方便地使用el-breadcrumb组件。以下是一个基本的使用示例:安装ElementUI(如果你还没有安装的话):你可以通过npm或yarn来安装ElementUI。bash复制代码npmi</div> </li> <li><a href="/article/1835511912843014144.htm" title="理解Gunicorn:Python WSGI服务器的基石" target="_blank">理解Gunicorn:Python WSGI服务器的基石</a> <span class="text-muted">范范0825</span> <a class="tag" taget="_blank" href="/search/ipython/1.htm">ipython</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>理解Gunicorn:PythonWSGI服务器的基石介绍Gunicorn,全称GreenUnicorn,是一个为PythonWSGI(WebServerGatewayInterface)应用设计的高效、轻量级HTTP服务器。作为PythonWeb应用部署的常用工具,Gunicorn以其高性能和易用性著称。本文将介绍Gunicorn的基本概念、安装和配置,帮助初学者快速上手。1.什么是Gunico</div> </li> <li><a href="/article/1835509770287673344.htm" title="swagger访问路径" target="_blank">swagger访问路径</a> <span class="text-muted">igotyback</span> <a class="tag" taget="_blank" href="/search/swagger/1.htm">swagger</a> <div>Swagger2.x版本访问地址:http://{ip}:{port}/{context-path}/swagger-ui.html{ip}是你的服务器IP地址。{port}是你的应用服务端口,通常为8080。{context-path}是你的应用上下文路径,如果应用部署在根路径下,则为空。Swagger3.x版本对于Swagger3.x版本(也称为OpenAPI3)访问地址:http://{ip</div> </li> <li><a href="/article/1835504218178416640.htm" title="Google earth studio 简介" target="_blank">Google earth studio 简介</a> <span class="text-muted">陟彼高冈yu</span> <a class="tag" taget="_blank" href="/search/%E6%97%85%E6%B8%B8/1.htm">旅游</a> <div>GoogleEarthStudio是一个基于Web的动画工具,专为创作使用GoogleEarth数据的动画和视频而设计。它利用了GoogleEarth强大的三维地图和卫星影像数据库,使用户能够轻松地创建逼真的地球动画、航拍视频和动态地图可视化。网址为https://www.google.com/earth/studio/。GoogleEarthStudio是一个基于Web的动画工具,专为创作使用G</div> </li> <li><a href="/article/1835502578050363392.htm" title="PHP环境搭建详细教程" target="_blank">PHP环境搭建详细教程</a> <span class="text-muted">好看资源平台</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/php/1.htm">php</a> <div>PHP是一个流行的服务器端脚本语言,广泛用于Web开发。为了使PHP能够在本地或服务器上运行,我们需要搭建一个合适的PHP环境。本教程将结合最新资料,介绍在不同操作系统上搭建PHP开发环境的多种方法,包括Windows、macOS和Linux系统的安装步骤,以及本地和Docker环境的配置。1.PHP环境搭建概述PHP环境的搭建主要分为以下几类:集成开发环境:例如XAMPP、WAMP、MAMP,这</div> </li> <li><a href="/article/1835498925755297792.htm" title="DIV+CSS+JavaScript技术制作网页(旅游主题网页设计与制作)云南大理" target="_blank">DIV+CSS+JavaScript技术制作网页(旅游主题网页设计与制作)云南大理</a> <span class="text-muted">STU学生网页设计</span> <a class="tag" taget="_blank" href="/search/%E7%BD%91%E9%A1%B5%E8%AE%BE%E8%AE%A1/1.htm">网页设计</a><a class="tag" taget="_blank" href="/search/%E6%9C%9F%E6%9C%AB%E7%BD%91%E9%A1%B5%E4%BD%9C%E4%B8%9A/1.htm">期末网页作业</a><a class="tag" taget="_blank" href="/search/html%E9%9D%99%E6%80%81%E7%BD%91%E9%A1%B5/1.htm">html静态网页</a><a class="tag" taget="_blank" href="/search/html5%E6%9C%9F%E6%9C%AB%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">html5期末大作业</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E9%A1%B5%E8%AE%BE%E8%AE%A1/1.htm">网页设计</a><a class="tag" taget="_blank" href="/search/web%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">web大作业</a> <div>️精彩专栏推荐作者主页:【进入主页—获取更多源码】web前端期末大作业:【HTML5网页期末作业(1000套)】程序员有趣的告白方式:【HTML七夕情人节表白网页制作(110套)】文章目录二、网站介绍三、网站效果▶️1.视频演示2.图片演示四、网站代码HTML结构代码CSS样式代码五、更多源码二、网站介绍网站布局方面:计划采用目前主流的、能兼容各大主流浏览器、显示效果稳定的浮动网页布局结构。网站程</div> </li> <li><a href="/article/1835497537369370624.htm" title="利用Requests Toolkit轻松完成HTTP请求" target="_blank">利用Requests Toolkit轻松完成HTTP请求</a> <span class="text-muted">nseejrukjhad</span> <a class="tag" taget="_blank" href="/search/http/1.htm">http</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/1.htm">网络协议</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>RequestsToolkit的力量:轻松构建HTTP请求Agent在现代软件开发中,API请求是与外部服务交互的核心。RequestsToolkit提供了一种便捷的方式,帮助开发者构建自动化的HTTP请求Agent。本文旨在详细介绍RequestsToolkit的设置、使用和潜在挑战。引言RequestsToolkit是一个强大的工具包,可用于构建执行HTTP请求的智能代理。这对于想要自动化与外</div> </li> <li><a href="/article/1835496149843275776.htm" title="关于城市旅游的HTML网页设计——(旅游风景云南 5页)HTML+CSS+JavaScript" target="_blank">关于城市旅游的HTML网页设计——(旅游风景云南 5页)HTML+CSS+JavaScript</a> <span class="text-muted">二挡起步</span> <a class="tag" taget="_blank" href="/search/web%E5%89%8D%E7%AB%AF%E6%9C%9F%E6%9C%AB%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">web前端期末大作业</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/%E6%97%85%E6%B8%B8/1.htm">旅游</a><a class="tag" taget="_blank" href="/search/%E9%A3%8E%E6%99%AF/1.htm">风景</a> <div>⛵源码获取文末联系✈Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业|游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作|HTML期末大学生网页设计作业,Web大学生网页HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScrip</div> </li> <li><a href="/article/1835496148601761792.htm" title="HTML网页设计制作大作业(div+css) 云南我的家乡旅游景点 带文字滚动" target="_blank">HTML网页设计制作大作业(div+css) 云南我的家乡旅游景点 带文字滚动</a> <span class="text-muted">二挡起步</span> <a class="tag" taget="_blank" href="/search/web%E5%89%8D%E7%AB%AF%E6%9C%9F%E6%9C%AB%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">web前端期末大作业</a><a class="tag" taget="_blank" href="/search/web%E8%AE%BE%E8%AE%A1%E7%BD%91%E9%A1%B5%E8%A7%84%E5%88%92%E4%B8%8E%E8%AE%BE%E8%AE%A1/1.htm">web设计网页规划与设计</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/dreamweaver/1.htm">dreamweaver</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作HTML期末大学生网页设计作业HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScript:做与用户的交互行为文章目录前端学习路线</div> </li> <li><a href="/article/1835495170972413952.htm" title="git - Webhook让部署自动化" target="_blank">git - Webhook让部署自动化</a> <span class="text-muted">大猪大猪</span> <div>我们现在有一个需求,将项目打包上传到gitlab或者github后,程序能自动部署,不用手动地去服务器中进行项目更新并运行,如何做到?这里我们可以使用gitlab与github的挂钩,挂钩的原理就是,每当我们有请求到gitlab与github服务器时,这时他俩会根据我们配置的挂钩地扯进行访问,webhook挂钩程序会一直监听着某个端口请求,一但收到他们发过来的请求,这时就知道用户有请求提交了,这时</div> </li> <li><a href="/article/1835493267907637248.htm" title="webpack图片等资源的处理" target="_blank">webpack图片等资源的处理</a> <span class="text-muted">dmengmeng</span> <div>需要的loaderfile-loader(让我们可以引入这些资源文件)url-loader(其实是file-loader的二次封装)img-loader(处理图片所需要的)在没有使用任何处理图片的loader之前,比如说css中用到了背景图片,那么最后打包会报错的,因为他没办法处理图片。其实你只想能够使用图片的话。只加一个file-loader就可以,打开网页能准确看到图片。{test:/\.(p</div> </li> <li><a href="/article/1835471059135066112.htm" title="你可能遗漏的一些C#/.NET/.NET Core知识点" target="_blank">你可能遗漏的一些C#/.NET/.NET Core知识点</a> <span class="text-muted">追逐时光者</span> <a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/.NET/1.htm">.NET</a><a class="tag" taget="_blank" href="/search/DotNetGuide%E7%BC%96%E7%A8%8B%E6%8C%87%E5%8D%97/1.htm">DotNetGuide编程指南</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/.netcore/1.htm">.netcore</a><a class="tag" taget="_blank" href="/search/microsoft/1.htm">microsoft</a> <div>前言在这个快速发展的技术世界中,时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NETCore拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节,以帮助大家更全面地了解这些技术栈的特性和发展方向。拾遗补漏GitHub开源地址https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/D</div> </li> <li><a href="/article/1835470931783413760.htm" title="「豆包Marscode体验官」 | 云端 IDE 启动 & Rust 体验" target="_blank">「豆包Marscode体验官」 | 云端 IDE 启动 & Rust 体验</a> <span class="text-muted">张风捷特烈</span> <a class="tag" taget="_blank" href="/search/ide/1.htm">ide</a><a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>theme:cyanosis我正在参加「豆包MarsCode初体验」征文活动MarsCode可以看作一个运行在服务端的远程VSCode开发环境。对于我这种想要学习体验某些语言,但不想在电脑里装环境的人来说非常友好。本文就来介绍一下在MarsCode里,我的体验rust开发体验。一、MarsCode是什么它的本质是:提供代码助手和云端IDE服务的web网站,可通过下面的链接访问https://www</div> </li> <li><a href="/article/1835467782687387648.htm" title="linux 发展史" target="_blank">linux 发展史</a> <span class="text-muted">种树的猴子</span> <a class="tag" taget="_blank" href="/search/%E5%86%85%E6%A0%B8/1.htm">内核</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/1.htm">操作系统</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a> <div>linux发展史说明此前对linux认识模糊一知半解,近期通过学习将自己对于linux的发展总结一下方便大家日后的学习。那Linux是目前一款非常火热的开源操作系统,可是linux是什么时候出现的,又是因为什么样的原因被开发出来的呢。以下将对linux的发展历程进行详细的讲解。目录一、Linux发展背景二、UINIX的诞生三、UNIX的重要分支-BSD的诞生四、Minix的诞生五、GNU与Free</div> </li> <li><a href="/article/1835458199755517952.htm" title="spring如何整合druid连接池?" target="_blank">spring如何整合druid连接池?</a> <span class="text-muted">惜.己</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/junit/1.htm">junit</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/idea/1.htm">idea</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a> <div>目录spring整合druid连接池1.新建maven项目2.新建mavenModule3.导入相关依赖4.配置log4j2.xml5.配置druid.xml1)xml中如何引入properties2)下面是配置文件6.准备jdbc.propertiesJDBC配置项解释7.配置druid8.测试spring整合druid连接池1.新建maven项目打开IDE(比如IntelliJIDEA,Ecl</div> </li> <li><a href="/article/1835455048277127168.htm" title="Python神器!WEB自动化测试集成工具 DrissionPage" target="_blank">Python神器!WEB自动化测试集成工具 DrissionPage</a> <span class="text-muted">亚丁号</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>一、前言用requests做数据采集面对要登录的网站时,要分析数据包、JS源码,构造复杂的请求,往往还要应付验证码、JS混淆、签名参数等反爬手段,门槛较高。若数据是由JS计算生成的,还须重现计算过程,体验不好,开发效率不高。使用浏览器,可以很大程度上绕过这些坑,但浏览器运行效率不高。因此,这个库设计初衷,是将它们合而为一,能够在不同须要时切换相应模式,并提供一种人性化的使用方法,提高开发和运行效率</div> </li> <li><a href="/article/1835454921990828032.htm" title="Java爬虫框架(一)--架构设计" target="_blank">Java爬虫框架(一)--架构设计</a> <span class="text-muted">狼图腾-狼之传说</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6/1.htm">框架</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E4%BB%BB%E5%8A%A1/1.htm">任务</a><a class="tag" taget="_blank" href="/search/html%E8%A7%A3%E6%9E%90%E5%99%A8/1.htm">html解析器</a><a class="tag" taget="_blank" href="/search/%E5%AD%98%E5%82%A8/1.htm">存储</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E5%AD%90%E5%95%86%E5%8A%A1/1.htm">电子商务</a> <div>一、架构图那里搜网络爬虫框架主要针对电子商务网站进行数据爬取,分析,存储,索引。爬虫:爬虫负责爬取,解析,处理电子商务网站的网页的内容数据库:存储商品信息索引:商品的全文搜索索引Task队列:需要爬取的网页列表Visited表:已经爬取过的网页列表爬虫监控平台:web平台可以启动,停止爬虫,管理爬虫,task队列,visited表。二、爬虫1.流程1)Scheduler启动爬虫器,TaskMast</div> </li> <li><a href="/article/1835454795712917504.htm" title="esp32开发快速入门 8 : MQTT 的快速入门,基于esp32实现MQTT通信" target="_blank">esp32开发快速入门 8 : MQTT 的快速入门,基于esp32实现MQTT通信</a> <span class="text-muted">z755924843</span> <a class="tag" taget="_blank" href="/search/ESP32%E5%BC%80%E5%8F%91%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/1.htm">ESP32开发快速入门</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>MQTT介绍简介MQTT(MessageQueuingTelemetryTransport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联</div> </li> <li><a href="/article/1835454543471669248.htm" title="Java:爬虫框架" target="_blank">Java:爬虫框架</a> <span class="text-muted">dingcho</span> <a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>一、ApacheNutch2【参考地址】Nutch是一个开源Java实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。Nutch致力于让每个人能很容易,同时花费很少就可以配置世界一流的Web搜索引擎.为了完成这一宏伟的目标,Nutch必须能够做到:每个月取几十亿网页为这些网页维护一个索引对索引文件进行每秒上千次的搜索提供高质量的搜索结果简单来说Nutch支持分</div> </li> <li><a href="/article/1835452528599330816.htm" title="vue项目element-ui的table表格单元格合并" target="_blank">vue项目element-ui的table表格单元格合并</a> <span class="text-muted">酋长哈哈</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/elementui/1.htm">elementui</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>一、合并效果二全部代码exportdefault{name:'CellMerge',data(){return{tableData:[{id:'1',name:'王小虎',amount1:'165',amount2:'3.2',amount3:10},{id:'1',name:'王小虎',amount1:'162',amount2:'4.43',amount3:12},{id:'1',name:'</div> </li> <li><a href="/article/1835451016456269824.htm" title="MongoDB知识概括" target="_blank">MongoDB知识概括</a> <span class="text-muted">GeorgeLin98</span> <a class="tag" taget="_blank" href="/search/%E6%8C%81%E4%B9%85%E5%B1%82/1.htm">持久层</a><a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a> <div>MongoDB知识概括MongoDB相关概念单机部署基本常用命令索引-IndexSpirngDataMongoDB集成副本集分片集群安全认证MongoDB相关概念业务应用场景:传统的关系型数据库(如MySQL),在数据操作的“三高”需求以及应对Web2.0的网站需求面前,显得力不从心。解释:“三高”需求:①Highperformance-对数据库高并发读写的需求。②HugeStorage-对海量数</div> </li> <li><a href="/article/1835450511071997952.htm" title="android 更改窗口的层次,浮窗开发之窗口层级" target="_blank">android 更改窗口的层次,浮窗开发之窗口层级</a> <span class="text-muted">Ms.Bu</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E6%9B%B4%E6%94%B9%E7%AA%97%E5%8F%A3%E7%9A%84%E5%B1%82%E6%AC%A1/1.htm">更改窗口的层次</a> <div>最近在项目中遇到了这样的需求:需要在特定的其他应用之上悬浮自己的UI交互(拖动、输入等复杂的UI交互),和九游的浮窗类似,不过我们的比九游的体验更好,我们越过了很多授权的限制。浮窗效果很多人都知道如何去实现一个简单的浮窗,但是却很少有人去深入的研究背后的流程机制,由于项目中浮窗交互比较复杂,遇到了些坑查看了很多资料,故总结浮窗涉及到的知识点:窗口层级关系(浮窗是如何“浮”的)?浮窗有哪些限制,如何</div> </li> <li><a href="/article/1835450384198496256.htm" title="matlab mle 优化,MLE+: Matlab Toolbox for Integrated Modeling, Control and Optimization for Buildings..." target="_blank">matlab mle 优化,MLE+: Matlab Toolbox for Integrated Modeling, Control and Optimization for Buildings...</a> <span class="text-muted">Simon Zhong</span> <a class="tag" taget="_blank" href="/search/matlab/1.htm">matlab</a><a class="tag" taget="_blank" href="/search/mle/1.htm">mle</a><a class="tag" taget="_blank" href="/search/%E4%BC%98%E5%8C%96/1.htm">优化</a> <div>摘要:FollowingunilateralopticnervesectioninadultPVGhoodedrat,theaxonguidancecueephrin-A2isup-regulatedincaudalbutnotrostralsuperiorcolliculus(SC)andtheEphA5receptorisdown-regulatedinaxotomisedretinalgan</div> </li> <li><a href="/article/1835446943296352256.htm" title="TextFiled 中输入金额" target="_blank">TextFiled 中输入金额</a> <span class="text-muted">宁梓茞</span> <div>要求:输入的金额不能超过六位,小数点后面只能输入两位小数如果textFIled中第一位输入的是0,后面必须输入小数点,否则禁止输入用到textfiled代理方法#pragmamark----textFiledDelegate-----(BOOL)textField:(UITextField*)textFieldshouldChangeCharactersInRange:(NSRange)range</div> </li> <li><a href="/article/1835444076007223296.htm" title="JAVA·一个简单的登录窗口" target="_blank">JAVA·一个简单的登录窗口</a> <span class="text-muted">MortalTom</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a> <div>文章目录概要整体架构流程技术名词解释技术细节资源概要JavaSwing是Java基础类库的一部分,主要用于开发图形用户界面(GUI)程序整体架构流程新建项目,导入sql.jar包(链接放在了文末),编译项目并运行技术名词解释一、特点丰富的组件提供了多种可视化组件,如按钮(JButton)、文本框(JTextField)、标签(JLabel)、下拉列表(JComboBox)等,可以满足不同的界面设计</div> </li> <li><a href="/article/1835443823287824384.htm" title="Python实现下载当前年份的谷歌影像" target="_blank">Python实现下载当前年份的谷歌影像</a> <span class="text-muted">sand&wich</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>在GIS项目和地图应用中,获取最新的地理影像数据是非常重要的。本文将介绍如何使用Python代码从Google地图自动下载当前年份的影像数据,并将其保存为高分辨率的TIFF格式文件。这个过程涉及地理坐标转换、多线程下载和图像处理。关键功能该脚本的核心功能包括:坐标转换:支持WGS-84与WebMercator投影之间转换,以及处理中国GCJ-02偏移。自动化下载:多线程下载地图瓦片,提高效率。图像</div> </li> <li><a href="/article/1835443569528238080.htm" title="Vue( ElementUI入门、vue-cli安装)" target="_blank">Vue( ElementUI入门、vue-cli安装)</a> <span class="text-muted">m0_l5z</span> <a class="tag" taget="_blank" href="/search/elementui/1.htm">elementui</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>一.ElementUI入门目录:1.ElementUI入门1.1ElementUI简介1.2Vue+ElementUI安装1.3开发示例2.搭建nodejs环境2.1nodejs介绍2.2npm是什么2.3nodejs环境搭建2.3.1下载2.3.2解压2.3.3配置环境变量2.3.4配置npm全局模块路径和cache默认安装位置2.3.5修改npm镜像提高下载速度2.3.6验证安装结果3.运行n</div> </li> <li><a href="/article/1835443569968640000.htm" title="Spring MVC 全面指南:从入门到精通的详细解析" target="_blank">Spring MVC 全面指南:从入门到精通的详细解析</a> <span class="text-muted">一杯梅子酱</span> <a class="tag" taget="_blank" href="/search/%E6%8A%80%E6%9C%AF%E6%A0%88%E5%AD%A6%E4%B9%A0/1.htm">技术栈学习</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/mvc/1.htm">mvc</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>引言:SpringMVC,作为Spring框架的一个重要模块,为构建Web应用提供了强大的功能和灵活性。无论是初学者还是有一定经验的开发者,掌握SpringMVC都将显著提升你的Web开发技能。本文旨在为初学者提供一个全面且易于理解的学习路径,通过详细的知识点分析和实际案例,帮助你快速上手SpringMVC,让学习过程既深刻又高效。一、SpringMVC简介1.1什么是SpringMVC?Spri</div> </li> <li><a href="/article/31.htm" title="312个免费高速HTTP代理IP(能隐藏自己真实IP地址)" target="_blank">312个免费高速HTTP代理IP(能隐藏自己真实IP地址)</a> <span class="text-muted">yangshangchuan</span> <a class="tag" taget="_blank" href="/search/%E9%AB%98%E9%80%9F/1.htm">高速</a><a class="tag" taget="_blank" href="/search/%E5%85%8D%E8%B4%B9/1.htm">免费</a><a class="tag" taget="_blank" href="/search/superword/1.htm">superword</a><a class="tag" taget="_blank" href="/search/HTTP%E4%BB%A3%E7%90%86/1.htm">HTTP代理</a> <div>    124.88.67.20:843 190.36.223.93:8080 117.147.221.38:8123 122.228.92.103:3128 183.247.211.159:8123 124.88.67.35:81 112.18.51.167:8123 218.28.96.39:3128 49.94.160.198:3128 183.20</div> </li> <li><a href="/article/158.htm" title="pull解析和json编码" target="_blank">pull解析和json编码</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/pull%E8%A7%A3%E6%9E%90/1.htm">pull解析</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a> <div>n.json文件: [{name:java,lan:c++,age:17},{name:android,lan:java,age:8}]   pull.xml文件 <?xml version="1.0" encoding="utf-8"?> <stu>     <name>java</div> </li> <li><a href="/article/285.htm" title="[能源与矿产]石油与地球生态系统" target="_blank">[能源与矿产]石油与地球生态系统</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E8%83%BD%E6%BA%90/1.htm">能源</a> <div>       按照苏联的科学界的说法,石油并非是远古的生物残骸的演变产物,而是一种可以由某些特殊地质结构和物理条件生产出来的东西,也就是说,石油是可以自增长的....       那么我们做一个猜想: 石油好像是地球的体液,我们地球具有自动产生石油的某种机制,只要我们不过量开采石油,并保护好</div> </li> <li><a href="/article/412.htm" title="类与对象浅谈" target="_blank">类与对象浅谈</a> <span class="text-muted">沐刃青蛟</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%9F%BA%E7%A1%80/1.htm">基础</a> <div>        类,字面理解,便是同一种事物的总称,比如人类,是对世界上所有人的一个总称。而对象,便是类的具体化,实例化,是一个具体事物,比如张飞这个人,就是人类的一个对象。但要注意的是:张飞这个人是对象,而不是张飞,张飞只是他这个人的名字,是他的属性而已。而一个类中包含了属性和方法这两兄弟,他们分别用来描述对象的行为和性质(感觉应该是</div> </li> <li><a href="/article/539.htm" title="新站开始被收录后,我们应该做什么?" target="_blank">新站开始被收录后,我们应该做什么?</a> <span class="text-muted">IT独行者</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/seo/1.htm">seo</a> <div>新站开始被收录后,我们应该做什么?         百度终于开始收录自己的网站了,作为站长,你是不是觉得那一刻很有成就感呢,同时,你是不是又很茫然,不知道下一步该做什么了?至少我当初就是这样,在这里和大家一份分享一下新站收录后,我们要做哪些工作。       至于如何让百度快速收录自己的网站,可以参考我之前的帖子《新站让百</div> </li> <li><a href="/article/666.htm" title="oracle 连接碰到的问题" target="_blank">oracle 连接碰到的问题</a> <span class="text-muted">文强chu</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a> <div>Unable to find a java Virtual Machine--安装64位版Oracle11gR2后无法启动SQLDeveloper的解决方案 作者:草根IT网 来源:未知 人气:813标签: 导读:安装64位版Oracle11gR2后发现启动SQLDeveloper时弹出配置java.exe的路径,找到Oracle自带java.exe后产生的路径“C:\app\用户名\prod</div> </li> <li><a href="/article/793.htm" title="Swing中按ctrl键同时移动鼠标拖动组件(类中多借口共享同一数据)" target="_blank">Swing中按ctrl键同时移动鼠标拖动组件(类中多借口共享同一数据)</a> <span class="text-muted">小桔子</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%BB%A7%E6%89%BF/1.htm">继承</a><a class="tag" taget="_blank" href="/search/swing/1.htm">swing</a><a class="tag" taget="_blank" href="/search/%E6%8E%A5%E5%8F%A3/1.htm">接口</a><a class="tag" taget="_blank" href="/search/%E7%9B%91%E5%90%AC/1.htm">监听</a> <div>        都知道java中类只能单继承,但可以实现多个接口,但我发现实现多个接口之后,多个接口却不能共享同一个数据,应用开发中想实现:当用户按着ctrl键时,可以用鼠标点击拖动组件,比如说文本框。 编写一个监听实现KeyListener,NouseListener,MouseMotionListener三个接口,重写方法。定义一个全局变量boolea</div> </li> <li><a href="/article/920.htm" title="linux常用的命令" target="_blank">linux常用的命令</a> <span class="text-muted">aichenglong</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/1.htm">常用命令</a> <div>1 startx切换到图形化界面 2 man命令:查看帮助信息 man 需要查看的命令,man命令提供了大量的帮助信息,一般可以分成4个部分 name:对命令的简单说明 synopsis:命令的使用格式说明 description:命令的详细说明信息 options:命令的各项说明 3 date:显示时间 语法:date [OPTION]... [+FORMAT] </div> </li> <li><a href="/article/1047.htm" title="eclipse内存优化" target="_blank">eclipse内存优化</a> <span class="text-muted">AILIKES</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a><a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a><a class="tag" taget="_blank" href="/search/jdk/1.htm">jdk</a> <div>一 基本说明      在JVM中,总体上分2块内存区,默认空余堆内存小于 40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。     1)堆内存(Heap memory):堆是运行时数据区域,所有类实例和数组的内存均从此处分配,是Java代码可及的内存,是留给开发人</div> </li> <li><a href="/article/1174.htm" title="关键字的使用探讨" target="_blank">关键字的使用探讨</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/%E5%85%B3%E9%94%AE%E5%AD%97/1.htm">关键字</a> <div>//关键字的使用探讨/*访问关键词private 只能在本类中访问public 只能在本工程中访问protected 只能在包中和子类中访问默认的 只能在包中访问*//*final   类 方法 变量 final 类 不能被继承 final 方法 不能被子类覆盖,但可以继承 final 变量 只能有一次赋值,赋值后不能改变 final 不能用来修饰构造方法*///this()</div> </li> <li><a href="/article/1301.htm" title="JS中定义对象的几种方式" target="_blank">JS中定义对象的几种方式</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/js/1.htm">js</a> <div>    1. 基于已有对象扩充其对象和方法(只适合于临时的生成一个对象): <html> <head> <title>基于已有对象扩充其对象和方法(只适合于临时的生成一个对象)</title> </head> <script> var obj = new Object(); </div> </li> <li><a href="/article/1428.htm" title="表驱动法实例" target="_blank">表驱动法实例</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%A1%A8%E9%A9%B1%E5%8A%A8%E6%B3%95/1.htm">表驱动法</a><a class="tag" taget="_blank" href="/search/TDD/1.htm">TDD</a> <div>获得月的天数是典型的直接访问驱动表方式的实例,下面我们来展示一下: MonthDaysTest.java package com.study.test; import org.junit.Assert; import org.junit.Test; import com.study.MonthDays; public class MonthDaysTest { @T</div> </li> <li><a href="/article/1555.htm" title="LInux启停重启常用服务器的脚本" target="_blank">LInux启停重启常用服务器的脚本</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>启动,停止和重启常用服务器的Bash脚本,对于每个服务器,需要根据实际的安装路径做相应的修改   #! /bin/bash Servers=(Apache2, Nginx, Resin, Tomcat, Couchbase, SVN, ActiveMQ, Mongo); Ops=(Start, Stop, Restart); currentDir=$(pwd); echo</div> </li> <li><a href="/article/1682.htm" title="【HBase六】REST操作HBase" target="_blank">【HBase六】REST操作HBase</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/hbase/1.htm">hbase</a> <div>HBase提供了REST风格的服务方便查看HBase集群的信息,以及执行增删改查操作   1. 启动和停止HBase REST 服务 1.1 启动REST服务 前台启动(默认端口号8080) [hadoop@hadoop bin]$ ./hbase rest start   后台启动 hbase-daemon.sh start rest   启动时指定</div> </li> <li><a href="/article/1809.htm" title="大话zabbix 3.0设计假设" target="_blank">大话zabbix 3.0设计假设</a> <span class="text-muted">ronin47</span> <div>What’s new in Zabbix 2.0? 去年开始使用Zabbix的时候,是1.8.X的版本,今年Zabbix已经跨入了2.0的时代。看了2.0的release notes,和performance相关的有下面几个:          :: Performance improvements::Trigger related da</div> </li> <li><a href="/article/1936.htm" title="http错误码大全" target="_blank">http错误码大全</a> <span class="text-muted">byalias</span> <a class="tag" taget="_blank" href="/search/http%E5%8D%8F%E8%AE%AE/1.htm">http协议</a><a class="tag" taget="_blank" href="/search/javaweb/1.htm">javaweb</a> <div>响应码由三位十进制数字组成,它们出现在由HTTP服务器发送的响应的第一行。 响应码分五种类型,由它们的第一位数字表示: 1)1xx:信息,请求收到,继续处理 2)2xx:成功,行为被成功地接受、理解和采纳 3)3xx:重定向,为了完成请求,必须进一步执行的动作 4)4xx:客户端错误,请求包含语法错误或者请求无法实现 5)5xx:服务器错误,服务器不能实现一种明显无效的请求 </div> </li> <li><a href="/article/2063.htm" title="J2EE设计模式-Intercepting Filter" target="_blank">J2EE设计模式-Intercepting Filter</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a> <div>Intercepting Filter类似于职责链模式 有两种实现 其中一种是Filter之间没有联系,全部Filter都存放在FilterChain中,由FilterChain来有序或无序地把把所有Filter调用一遍。没有用到链表这种数据结构。示例如下: package com.ljn.filter.custom; import java.util.ArrayList;</div> </li> <li><a href="/article/2190.htm" title="修改jboss端口" target="_blank">修改jboss端口</a> <span class="text-muted">chicony</span> <a class="tag" taget="_blank" href="/search/jboss/1.htm">jboss</a> <div>修改jboss端口   %JBOSS_HOME%\server\{服务实例名}\conf\bindingservice.beans\META-INF\bindings-jboss-beans.xml   中找到 <!-- The ports-default bindings are obtained by taking the base bindin</div> </li> <li><a href="/article/2317.htm" title="c++ 用类模版实现数组类" target="_blank">c++ 用类模版实现数组类</a> <span class="text-muted">CrazyMizzz</span> <a class="tag" taget="_blank" href="/search/C%2B%2B/1.htm">C++</a> <div>最近c++学到数组类,写了代码将他实现,基本具有vector类的功能 #include<iostream> #include<string> #include<cassert> using namespace std; template<class T> class Array { public: //构造函数 </div> </li> <li><a href="/article/2444.htm" title="hadoop dfs.datanode.du.reserved 预留空间配置方法" target="_blank">hadoop dfs.datanode.du.reserved 预留空间配置方法</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/%E9%A2%84%E7%95%99%E7%A9%BA%E9%97%B4/1.htm">预留空间</a> <div>对于datanode配置预留空间的方法 为:在hdfs-site.xml添加如下配置  <property>     <name>dfs.datanode.du.reserved</name>     <value>10737418240</value>    </div> </li> <li><a href="/article/2571.htm" title="mysql远程访问的设置" target="_blank">mysql远程访问的设置</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E9%98%B2%E7%81%AB%E5%A2%99/1.htm">防火墙</a> <div>第一步: 激活网络设置 你需要编辑mysql配置文件my.cnf. 通常状况,my.cnf放置于在以下目录: /etc/mysql/my.cnf (Debian linux) /etc/my.cnf (Red Hat Linux/Fedora Linux) /var/db/mysql/my.cnf (FreeBSD) 然后用vi编辑my.cnf,修改内容从以下行: [mysqld] 你所需要: 1</div> </li> <li><a href="/article/2698.htm" title="ios 使用特定的popToViewController返回到相应的Controller" target="_blank">ios 使用特定的popToViewController返回到相应的Controller</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/controller/1.htm">controller</a> <div>1、取navigationCtroller中的Controllers NSArray * ctrlArray = self.navigationController.viewControllers; 2、取出后,执行, [self.navigationController popToViewController:[ctrlArray objectAtIndex:0] animated:YES</div> </li> <li><a href="/article/2825.htm" title="Linux正则表达式和通配符的区别" target="_blank">Linux正则表达式和通配符的区别</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a><a class="tag" taget="_blank" href="/search/%E9%80%9A%E9%85%8D%E7%AC%A6%E5%92%8C%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%8C%BA%E5%88%AB/1.htm">通配符和正则表达式的区别</a><a class="tag" taget="_blank" href="/search/%E9%80%9A%E9%85%8D%E7%AC%A6/1.htm">通配符</a> <div>转载请出自出处:http://eksliang.iteye.com/blog/1976579 首先得明白二者是截然不同的 通配符只能用在shell命令中,用来处理字符串的的匹配。 判断一个命令是否为bash shell(linux 默认的shell)的内置命令 type -t commad 返回结果含义 file  表示为外部命令 alias  表示该</div> </li> <li><a href="/article/2952.htm" title="Ubuntu Mysql Install and CONF" target="_blank">Ubuntu Mysql Install and CONF</a> <span class="text-muted">gengzg</span> <a class="tag" taget="_blank" href="/search/Install/1.htm">Install</a> <div>http://www.navicat.com.cn/download/navicat-for-mysql Step1: 下载Navicat ,网址:http://www.navicat.com/en/download/download.html Step2:进入下载目录,解压压缩包:tar -zxvf navicat11_mysql_en.tar.gz </div> </li> <li><a href="/article/3079.htm" title="批处理,删除文件bat" target="_blank">批处理,删除文件bat</a> <span class="text-muted">huqiji</span> <a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/dos/1.htm">dos</a> <div>@echo off ::演示:删除指定路径下指定天数之前(以文件名中包含的日期字符串为准)的文件。 ::如果演示结果无误,把del前面的echo去掉,即可实现真正删除。 ::本例假设文件名中包含的日期字符串(比如:bak-2009-12-25.log) rem 指定待删除文件的存放路径 set SrcDir=C:/Test/BatHome rem 指定天数 set DaysAgo=1</div> </li> <li><a href="/article/3206.htm" title="跨浏览器兼容的HTML5视频音频播放器" target="_blank">跨浏览器兼容的HTML5视频音频播放器</a> <span class="text-muted">天梯梦</span> <a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a> <div>HTML5的video和audio标签是用来在网页中加入视频和音频的标签,在支持html5的浏览器中不需要预先加载Adobe Flash浏览器插件就能轻松快速的播放视频和音频文件。而html5media.js可以在不支持html5的浏览器上使video和audio标签生效。   How to enable <video> and <audio> tags in </div> </li> <li><a href="/article/3333.htm" title="Bundle自定义数据传递" target="_blank">Bundle自定义数据传递</a> <span class="text-muted">hm4123660</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/Serializable/1.htm">Serializable</a><a class="tag" taget="_blank" href="/search/%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E4%BC%A0%E9%80%92/1.htm">自定义数据传递</a><a class="tag" taget="_blank" href="/search/Bundle/1.htm">Bundle</a><a class="tag" taget="_blank" href="/search/Parcelable/1.htm">Parcelable</a> <div>      我们都知道Bundle可能过put****()方法添加各种基本类型的数据,Intent也可以通过putExtras(Bundle)将数据添加进去,然后通过startActivity()跳到下一下Activity的时候就把数据也传到下一个Activity了。如传递一个字符串到下一个Activity   把数据放到Intent</div> </li> <li><a href="/article/3460.htm" title="C#:异步编程和线程的使用(.NET 4.5 )" target="_blank">C#:异步编程和线程的使用(.NET 4.5 )</a> <span class="text-muted">powertoolsteam</span> <a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/%E7%BA%BF%E7%A8%8B/1.htm">线程</a><a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/1.htm">异步编程</a> <div>异步编程和线程处理是并发或并行编程非常重要的功能特征。为了实现异步编程,可使用线程也可以不用。将异步与线程同时讲,将有助于我们更好的理解它们的特征。 本文中涉及关键知识点 1. 异步编程 2. 线程的使用 3. 基于任务的异步模式 4. 并行编程 5. 总结 异步编程 什么是异步操作?异步操作是指某些操作能够独立运行,不依赖主流程或主其他处理流程。通常情况下,C#程序</div> </li> <li><a href="/article/3587.htm" title="spark 查看 job history 日志" target="_blank">spark 查看 job history 日志</a> <span class="text-muted">Stark_Summer</span> <a class="tag" taget="_blank" href="/search/%E6%97%A5%E5%BF%97/1.htm">日志</a><a class="tag" taget="_blank" href="/search/spark/1.htm">spark</a><a class="tag" taget="_blank" href="/search/history/1.htm">history</a><a class="tag" taget="_blank" href="/search/job/1.htm">job</a> <div>SPARK_HOME/conf 下: spark-defaults.conf 增加如下内容 spark.eventLog.enabled true spark.eventLog.dir hdfs://master:8020/var/log/spark spark.eventLog.compress true spark-env.sh 增加如下内容 export SP</div> </li> <li><a href="/article/3714.htm" title="SSH框架搭建" target="_blank">SSH框架搭建</a> <span class="text-muted">wangxiukai2015eye</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a><a class="tag" taget="_blank" href="/search/struts/1.htm">struts</a> <div>MyEclipse搭建SSH框架 Struts Spring Hibernate 1、new一个web project。 2、右键项目,为项目添加Struts支持。    选择Struts2 Core Libraries -<MyEclipes-Library>      点击Finish。src目录下多了struts</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>