Python Selenium 5分钟简单入门

一、预备知识:Html

1. Html结构

Html本质和markdown等语法类似,目的是为了用一套格式化的语法来达到呈现图形的效果。与XML,JSON等主要是为了展示数据结构或者为了持久化的目的不同,HTML本质是为了呈现数据的,这是一个用以显示为目的的语言。HTML的实现中使用了XML的思想,但对其进行了扩充和特例化。

如同MarkDown中 # ##表示的一级二级标题一样, html中只是用<h1></h1> <h2></h2>等来表示标题而已,

这里引用一句别的博客的话:

HTML是网页的结构,就比如工人盖房子一样,首先要用砖把房子的结构搭建起来,有了房子结构才能在其基础上再进行其他作业,HTML就类似于房子的大框架结构。HTML有很多标签组成,不同的标签语义不同,所有的标签内容组合在一起就构成了网页的结构内容。HTML中写了什么内容被浏览器渲染后网页中就有什么内容,这些内容是原生态的无任何修饰。只有当网页中有了这些原生态的内容后才可以在其基础上添加样式进行修饰,让网页变得更美观,用户体验更好。所以HTML就如同整个网页的灵魂,不可或缺。

Html使用xml的方式来表示数据结构,常见的html中的元素如下图所示:

HTML结构简单介绍图

2. XPATH逻辑

XPATH是一种在XML文档中定位元素的语言。因为HTML可以看做XML的一种实现,在自动化测试里要点击,要输入的那些按钮或者输入框在什么位置,就是靠这个语言来表达出来。

A. 绝对路径定位

"/html/body/div/div[2]/div/div/div/from/span[2]/input"

由上图可知,html这一层已经是顶层了。绝对路径的意思,也就是从顶层开始,一直找到需要定位的元素。

B. 利用元素属性定位

"//input[@id='kw']"

这里也可以叫相对路径定位,注意开头是//,逻辑大概是遍历整个html文件,找到标签名为input并且属性里面id值为kw的所有input标签。

C. 层级与属性结合

"//span[@class='bg s_ipt_wr']/input"

这种结合的方式,表示要找到有属性class并且值为bg s_ipt_wr的class标签下的input标签。

D. 使用逻辑运算符

"//input[@id='kw' and @class='su']/span/input"

这里用到了and,表示需要找到的input里面必须两个属性匹配上。

E. 偷懒的办法

使用Chrome浏览器,直接在想定位的元素上右键,选择检查(Ctrl+ Shift + I),然后页面右边会展示源码,并定位到对应的html元素上高亮,此时鼠标转换到对应的代码上,继续右键,选择Copy-> Copy XPATH。这样路径就有了。

注意:需要说明的是,这种方便并不是万能的,前面4点依旧需要掌握。当需要选择多个元素或者发现页面变动的时候,自动化测试代码需要频繁修改定位元素代码的时候,就需要手动自己按照页面的规律去找到对应元素了。

3. Selenium 自动化测试框架

Selenium主要用于web应用程序的自动化测试,但并不局限于此,它还支持所有基于web的管理任务自动化。他是跨平台,跨语言,多浏览器支持,开源并且支持分布式测试用例执行的框架。

也正是因为开源,跨平台,跨浏览器,跨语言,所以这个框架的学习价值很高,复用性强。

Python Selenium 运行需要的环境

  1. Python3
  2. Chrome浏览器(其他的也行,本例用Chrome)
  3. chromedriver(相当于是Chrome浏览器的驱动,有了就能通过命令操控Chrome浏览器)

先看一眼简单的demo样例:

def main():
    password = "abc12345"
    url = "http://10.10.114.104"
    # 打开浏览器对应页面
    driver = webdriver.Chrome()
    driver.get(url)
    # 找到输入用户名的输入框
    cls = driver.find_element_by_xpath("//input[@placeholder='请输入用户名']")
    # 输入用户名
    cls.send_keys("admin")
    # 找到输入密码的用户框
    cls_pw = driver.find_element_by_xpath("//input[@placeholder='请输入密码']")
    # 输入密码
    cls_pw.send_keys(password)
    # 点击登录
    log = driver.find_element_by_xpath("//button[@class='el-button loginBtn el-button--primary el-button--small']")
    log.click()

二、待测web页面分析

我们需要测试的页面,登录进去后,基本就不会有大的跳转。也就是页面有两种,一种是登陆页,一种是配置页面。

  1. 登陆页,没太多特殊的东西,输入用户名密码,点击登录即可。
  2. 配置页,这里承载了所有的逻辑,主干是通过最上方的导航栏分为了3个子页面,分别为状态展示,基础配置和其他配置。其中基础配置里有一个子导航栏,里面又分了6个小页面;其他配置页面中左侧有导航栏,有10多个小页面。

三、本页面合适的测试模式——PO模式

针对我们待测页面的特点,选取了PO模式,即页面对象模型(PO),用来管理维护一组页面元素的对象库。在PO下,web的每一个页面都有一个对应的Page类,每一个Page类维护着该页面的元素集和操作这些元素的方法。

PO模式的原则:

  1. 抽象每一个页面

  2. 页面中元素不暴露,仅暴露操作元素的方法

  3. 页面不应该有繁琐的继承关系

  4. 页面中不是所有元素都需要涉及到,核心业务元素做建模使用

  5. 把页面划分功能模块,在Page中实现这些功能方法

四、Selenium常用到的接口

  1. find_element

这个接口是为了找到我们需要交互的元素,里面的定位方式可以按照XPATH的方式找,也可以更简单的按照tag,class,id等查找方式。

  1. send_keys

这个接口是为了给页面元素提供输入的,包括但不限于输入各种字符,数字等元素。

  1. script

这个接口是为了在页面执行一些js脚本用的,最常见的就是下拉菜单或者页面过长需要把需要点击的元素滚动到页面中的时候,可以调用此接口进行滚动。

Selenium基础页面的封装

这里基于上述三个接口,将一些常用的操作封装了起来,形成更简单的贴近独立业务接口。

class BasePage(object):
    """
    BasePage封装所有页面都公用的方法,例如driver, Find_Element等
    """
    # 实例化BasePage类时,最先执行的就是__init__方法,该方法的入参,其实就是BasePage类的入参。
    # __init__方法不能有返回值,只能返回None

    def __init__(self, selenium_driver: WebDriver, base_url):
        self.driver = selenium_driver
        self.base_url = base_url

    def _open(self, url):
        self.driver.get(url)
        self.driver.set_window_size(1280, 1080)

    def open(self):
        self._open(self.base_url)

    def find_element(self, *loc) -> WebElement:
        try:
            WebDriverWait(self.driver, 10).until(ec.visibility_of_element_located(loc))
            return self.driver.find_element(*loc)
        except AttributeError:
            print("%s 页面未能找到 %s 元素" % (self, loc))

    def scroll(self, *loc) -> WebElement:
        ele = self.driver.find_element(*loc)
        js = 'arguments[0].scrollIntoViewIfNeeded()'
        self.script(js, ele)
        return ele

    def script(self, *args):
        self.driver.execute_script(*args)

    def send_keys(self, loc, vaule, clear_first=True):
        try:
            element = self.find_element(*loc)
            if clear_first:
                element.send_keys(Keys.CONTROL, "a")
            element.send_keys(vaule)
        except AttributeError:
            print("%s 页面中未能找到 %s 元素" % (self, loc))

    def input(self, desc, loc):
        try:
            WebDriverWait(self.driver, 10).until(ec.visibility_of_element_located(loc))
            input_name = self.driver.find_element(*loc)
            input_name.send_keys(Keys.CONTROL, "a")
            input_name.send_keys(desc)
        except AttributeError:
            print("%s 页面未能找到 %s 元素" % (self, *loc))

    def source(self):
        return self.driver.page_source

五、关于Canvas的测试方式

我们web中还用到一些特殊的在Html里无法定位元素的标签,canvas。

在html结构中,canvas就只是一个标签,里面的结构无法看到。这个时候用XPATH就无法定位元素了。对于这个情况,selenium提供了更为基础的接口,按照像素移动鼠标。类似于这样:

ActionChains(self.driver).move_to_element(self.canvas_element).move_by_offset(*(-pos)).perform()

这一串操作的意思是,先移动到canvas_element这个元素的中心,然后以这个中心偏移一个指定的x和y值。由于move_by_offset这个接口每次偏移都是按照上一次移动的终点进行的增量偏移,所以需要格外注意有时候需要把鼠标移动回去。这里也简单的封装了一个canvas坐标值的类。

class CanvasPosition:
    """
    二维坐标运算
    """

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __neg__(self):
        return -self.x, -self.y

    def __add__(self, other):
        return CanvasPosition(self.x + other.x, self.y + other.y)

    def __truediv__(self, other):
        return CanvasPosition(self.x / other, self.y / other)

    def __mul__(self, other):
        return CanvasPosition(self.x * other, self.y * other)

    def __call__(self, *args, **kwargs):
        return self.x, self.y

六、参考文献

  1. 前端HTML结构详解!
  2. Html结构解析
  3. 《Selenium 2 自动化测试实战 基于Python语言》 虫师著
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值