Python PageFactory-使用配置文件动态生成页面PageObject
需求
在Python Selenium 的 PageObject模式中,一般每个页面需要写一个类, 一种PageObject的写法如下:
class BaiduPageObject(object):
def __init__(self, driver): # 一般通过继成BasePage类实现该方法
self.driver = driver
# 页面元素 -----
search_ipt_loc = ('id', 'kw')
search_btn_loc = ('id', 'su')
# 页面操作 -----
def input_search_ipt(self, keyword):
search_ipt = self.driver.find_element(*search_ipt_loc)
search_ipt.clear()
search_ipt.send_keys(keyword):
def click_search_btn(self):
self.driver.find_element(*search_btn_loc).click()
def search(self, keyword):
self.input_search_ipt(keyword)
self.click_search_btn()
对于一个成型的UI项目来说, 在编写用例前, 动辄要先编写数十上百个这种PageObject类. 鉴于每个PageObject类的格式相似, 可以采用
Page Factory(页面工厂)+配置文件(yaml) -> PageObject
的方式来动态生成每一个页面对象
PageFactory本是Selenium Java SDK中的一种基于PageObject的设计模式, 使用
@FindBy(id = "kw")语法糖来标记页面元素, 并支持使用@CacheLookup来缓存页面元素(这样元素只需要查找一次)
完整介绍: https://github.com/SeleniumHQ/selenium/wiki/PageFactory
鉴于 Python的动态特性, 这里的Page Factory的实现方式与Selenium Java SDK中的完全不同
设计与实现
首先设计及约定页面配置文件的格式如下:
# filename: baidu.yaml
url: https://www.baidu.com # 可选字段, 用于打开网页
title: 百度一下,你就知道 # 可选字段, 用于判断是否在当前网页
elements: # 页面元素
search_ipt: [id, kw] # 支持id, name, class name, tag name, link text
search_btn: [id, su] # partial link text, xpath, css selector
actions: # 可选字段, 页面操作
search:
input: [search_ipt, 默认值] # input: 固定字段, 第一参数为上面的元素, 第二个为输入的文本
click: search_btn # click: 固定字段, 参数为上面配置的元素
page_factory.py
# page_factory.py
from types import MethodType # 用于为实例动态绑定方法
from collections import OrderedDict # 有序字典, 用于按顺序遍历actions中的操作步骤
import yaml
from selenium import webdriver
class Page(object):
def __init__(self, driver, from_yaml=None, **kwargs):
self.driver = driver
self.url = kwargs.get('url', None)
self.title = kwargs.get('title', None)
self.elements = kwargs.get('elements', {})
self.actions = kwargs.get('url', OrderedDict())
if from_yaml is not None:
self.init_page(from_yaml)
def init_page(self, from_yaml):
with open(from_yaml, encoding='utf-8') as f:
data = yaml.load(f)
self.url = data.get('url', None)
self.title = data.get('title', None)
self.elements = data.get('elements', {})
self.actions = OrderedDict(data.get('actions', {}))
def open(self): # 打开页面url
if self.url is not None:
self.driver.get(self.url)
def on_page(self): # 通过title判断是否在当前页面上
if self.title is not None:
return self.title in self.driver.title
def input(self, element, text): # 输入操作, 指定配置中的元素名及文本
element = self.__getattr__(element) #
element.clear()
element.send_keys(text)
def click(self, element): # 点击操作, 指定元素名
element = self.__getattr__(element)
element.click()
def _handle_element(self, item): # 处理要查找的页面元素
element_loc = self.elements.get(item, None)
if element_loc is not None:
element = self.driver.find_element(*element_loc) # todo try
setattr(Page, item, element) # 缓存元素作为页面属性
return element
def _handle_action(self, item): # 处理要查找的操作方法
action = self.actions.get(item, None)
if action is not None:
def pack_action(self, text=None): # 解析约定的action格式, 组装操作方法
for step, params in action.items():
if step == 'input':
if text is not None and isinstance(params, list) and len(params)>1:
params[1] = text # 使用调用时的text参数替换input: [search_ipt, $keyword]的第2个参数
self.input(*params)
elif step == 'click':
self.click(params)
return MethodType(pack_action, self) # 为实例绑定操作方法并返回
def __getattr__(self, item): # 查找页面属性和操作方法
if not hasattr(Page, item): # 如无该属性/方法则动态为页面添加元素属性和操作方法
return self._handle_element(item) or self._handle_action(item)
if __name__ == '__main__': # 使用方法
driver = webdriver.Chrome()
baidu = Page(driver, 'baidu.yaml')
baidu.open()
baidu.search('临渊')
TODO
- 异常捕获
- 单url框架页面的加载, 每个action的返回页面, 页面之间的流转
- 缓存页面对象, 比如不同用例中多次调用baidu = PageFactory(driver, ...), 使用同一个退休
- 增加更多的action支持, 如select, hover, switch等等
- 独立模板解析parser方法, 支持更多的变量, 如
$1, $2/$keyword, $func(a)等 - 为Page增加hooks方法让使用更灵活
PS:
使用该Page Factory(页面工厂)方法暂时还没有减轻, 数十上百的页面编写工作, 只是从原来的编写Python类改为编写yaml配置文件, 然而,静态的配置文件相对与Python类来说, 有以下好处:
- 实现了数据(页面元素定位器)与代码的分离
- PageFactory支持传入字典格式的配置参数来生成页面, 数据可以来源于yaml文件,也可以来源于页面表单/数据库,甚至爬虫爬取, 便于集成前端web页面, 或爬虫自动生成Pages
Python PageFactory-使用配置文件动态生成页面PageObject的更多相关文章
- 动态生成页面(一)——ASP.NET中Literal使用
在页面中加入内容时,假设是静态内容.无需使用容器,能够直接将标记作为HTML直接加入到页面中:可是,假设是动态内容,则必须借助容器将内容加入到页面中.典型的容器有:Label控件.Literal控件. ...
- python解析git log后生成页面显示git更新日志信息
使用git log可以查到git上项目的更新日志. 如下两个git项目,我想把git的日志信息解析成一个便于在浏览器上查看的页面. https://github.com/gityf/lua https ...
- sitemap.xml 静态和动态生成页面 shopnc二次开发 动态生成sitemap.xml
Sitemap 可方便网站管理员通知搜索引擎他们网站上有哪些可供抓取的网页.最简单的 Sitemap 形式,就是XML 文件,在其中列出网站中的网址以及关于每个网址的其他元数据(上次更新的时间.更改的 ...
- 通过js动态生成页面表格
var redlineTemplateP = $(".redlineDataList"); for (var index in detailArraryLists.rows){ v ...
- Javascript动态生成的页面信息爬取和openpyxl包FAQ小记
最近,笔者在使用Requests模拟浏览器发送Post请求时,发现程序返回的html与浏览器F12观察到的略有不同,经过观察返回的response.text,cookies确认有效,因为我们可以看到返 ...
- CGI实现页面的动态生成
传统的Web应用开发局限于有限的静态页面(HTML静态页面),不利于系统的扩展,不能提供及时信息,而且修改维护麻烦,所以建立一个动态Web应用程序尤为重要.一方面根据访问者的不同请求返回不同的访问信息 ...
- Python调用ansible API系列(四)动态生成hosts文件
方法一:通过最原始的操作文件的方式 #!/usr/bin/env python # -*- coding: utf-8 -*- """ 通过操作文件形式动态生成ansib ...
- Python+Selenium爬取动态加载页面(1)
注: 最近有一小任务,需要收集水质和水雨信息,找了两个网站:国家地表水水质自动监测实时数据发布系统和全国水雨情网.由于这两个网站的数据都是动态加载出来的,所以我用了Selenium来完成我的数据获取. ...
- SSI注入--嵌入HTML页面中的指令,类似jsp、asp对现有HTML页面增加动态生成内容,见后面例子
SSI注入漏洞总结 from:https://www.mi1k7ea.com/2019/09/28/SSI%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E6%80%BB%E ...
随机推荐
- 实现文件上下文管理(__enter__和___exit__)
实现文件上下文管理(__enter__和__exit__) 我们知道在操作文件对象的时候可以这么写 with open('a.txt') as f: '代码块' 上述叫做上下文管理协议,即with语句 ...
- hdu 2610 2611 dfs的判重技巧
对于全排列枚举的数列的判重技巧 1:如果查找的是第一个元素 那么 从0开始到当前的位置看有没有出现过这个元素 出现过就pass 2: 如果查找的不是第一个元素 那么 从查找的子序列当前位置的前一个元素 ...
- Redis 的订阅发布(PUB/SUB)示例
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("127.0.0.1"); ISubscriber sub ...
- dev gridview 视图层级
表格对象继承的关系
- CSS精灵技术(sprite)
CSS技术的使用场景:有效的减少了服务器接收和发送请求的次数,css精灵是一种出来网页背景图像的方式,将一个页面设计到的所有零星背景图集中到一张大图中去,然后将大图应用于网页 .通过backgroun ...
- python生成式:列表、字典、集合
python的3类生成式: 列表生成式 字典生成式 集合生成式 1.python列表生成式 my_data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(&quo ...
- 学习手写vue,理解原理
class Compiler{ constructor(el,vm){ // 判断el属性 是不是 一个元素, 如果不是就获取 this.el = this.isElementNode(el)?el: ...
- MySQL备份--xtrabackup与mysqldump工具使用
MySQL备份----xtrabackup与mysqldump工具的使用 一.Xtrabackup8.0: 一个用于MySQL数据库物理热备的备份工具,支持MySQL.Percona server和M ...
- 03.Zabbix应用服务监控
一.Zabbix监控Nginx 1.1 实验环境 服务器系统 角色 IP CentOS 7.4 x86_64 Zabbix-Server 192.168.90.10 CentOS 7.4 x86_64 ...
- Linux环境下交叉编译器安装及运行
描述: 由于 使用第三方编译器是提示No such file or directory 原因:编译器为32位版本,而系统是64位的 解决方法:安装32位版本编译支持库 sudo apt-get ins ...