江苏平台网站建设价位,果洛州wap网站建设公司,网页制作教程小视频,wordpress屏蔽广告目录
背景介绍
实现思路
把脚本数据读出#xff0c;使用正则表达式#xff08;re库#xff09;匹配关键数据进行修改
把脚本数据读出#xff0c;使用BeautifulSoup的xml解析功能解析后修改
通过Beautiful Soup
Beautiful Soup
具体实现
使用string.Template字符替换…目录
背景介绍
实现思路
把脚本数据读出使用正则表达式re库匹配关键数据进行修改
把脚本数据读出使用BeautifulSoup的xml解析功能解析后修改
通过Beautiful Soup
Beautiful Soup
具体实现
使用string.Template字符替换
具体实现
使用re.sub
延展 资料获取方法 背景介绍
我们在做性能调优时时常需要根据实际压测的情况调整线程组的参数比如循环次数线程数所有线程启动的时间等。 如果是在一台Linux机器上就免不了在本机打开图形页面修改然后最后传递到压测机上面的过程所有为了解决这个业务痛点 使用Python写了一个能直接修改Jmeter基础压测参数的脚本能修改jmx脚本的线程组数、循环次数、线程组全部启动需要花的时间。 实现思路
刚开始准备写这个脚本的时候想了两个思路
把脚本数据读出使用正则表达式re库匹配关键数据进行修改
优点可以快速的改写数据 缺点无法进行区块的修改
把脚本数据读出使用BeautifulSoup的xml解析功能解析后修改
注我们的Jmx脚本其实就是一个标准格式的xml
优点 能快速的查找元素并进行修改缺点 需要熟悉BeautifulSoup的用法 通过Beautiful Soup
Beautiful Soup
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.我们使用BeautifulSoup解析xml或者html的时候能够得到一个 BeautifulSoup 的对象我们可以通过操作这个对象来完成原始数据的结构化数据。具体的使用可以参照这份文档。
具体实现
主要使用了bs4的soup.find 和self.soup.find_all功能。结化或数据的修改如loops.string num。
值得注意的是find_all支持正则匹配甚至如果没有合适过滤器那么还可以定义一个方法,方法只接受一个元素参数。
修改后的脚本将以T{}L{}R{}-{}_{}.jmx.format(thread_num, loop_num, ramp_time, self.src_script, self.get_time()) 的形式保存具体封装如下
import time
import os
from bs4 import BeautifulSoupclass OpJmx:def __init__(self, file_name):self.src_script self._split_filename(file_name)with open(file_name, r) as f:data f.read()self.soup BeautifulSoup(data, xml)staticmethoddef _split_filename(filename):新生成的文件兼容传入相对路径及文件名称:param filename::return:relative filename.split(/)return relative[len(relative)-1].split(.jmx)[0]def _theard_num(self)::return: 线程数据对象return self.soup.find(stringProp, {name: {ThreadGroup.num_threads}})def _ramp_time(self)::return: 启动所有线程时间配置对象return self.soup.find(stringProp, {name: {ThreadGroup.ramp_time}})def _bean_shell(self)::return: bean_shell对象return self.soup.find(stringProp, {name: {BeanShellSampler.query}})def _paths(self)::return: 请求路径信息对象return self.soup.find_all(stringProp, {name: {HTTPSampler.path}})def _methods(self)::return: 请求方法对象return self.soup.find_all(stringProp, {name: {HTTPSampler.method}})def _argument(self)::return: post请求参数对象# Argument.value 不唯一 通过HTTPArgument.always_encode找到return self.soup.find_all(boolProp, {name: {HTTPArgument.always_encode}})[0].find_next()def _loops(self):循环次数兼容forever 与具体次数:return: 循环次数对象_loops self.soup.find(stringProp, {name: {LoopController.loops}})if _loops:passelse:_loops self.soup.find(intProp, {name: {LoopController.loops}})return _loopsstaticmethoddef get_time():return time.strftime(%Y-%m-%d%X, time.localtime())def get_bean_shell(self):_str self._bean_shell().stringlogger.info(bean_shell: _str)return _strdef set_bean_shell(self, new_bean_shell):old_bean_shell self._bean_shell()old_bean_shell.string new_bean_shelldef get_ramp_time(self):_str self._ramp_time().stringlogger.info(ramp_time: _str)return _strcheck_numdef set_ramp_time(self, num):loops self._ramp_time()loops.string numdef get_loops(self):_str self._loops().stringlogger.info(loops: _str)return _strcheck_numdef set_loops(self, num)::param num: -1 为一直循环其他为具体循环次数:return:loops self._loops()loops.string numdef get_argument(self):_str self._argument().stringlogger.info(argument: _str)return _strdef set_argument(self, **kwargs):设置请求参数JSON传入字典:param kwargs::return:param self._argument()param.string str(kwargs)def get_thread_num(self):_str self._theard_num().stringlogger.info(thread_num: _str)return _strcheck_numdef set_thread_num(self, num):设置线程数信息:param num::return:thread_num self._theard_num()thread_num.string num# print(self.soup.find_all(stringProp, {name: {ThreadGroup.num_threads}})[0].string)def mod_header(self, key, value, index0):修改指定header的信息默认修改第一个值:param key::param value::param index::return:headers self.soup.find_all(elementProp, {elementType: {Header}})headers[index].find(stringProp, {name: {Header.name}}).string keyheaders[index].find(stringProp, {name: {Header.value}}).string value# for header in headers:# header.find(stringProp, {name: {Header.name}}).string key# header.find(stringProp, {name: {Header.value}}).string valuedef save_jmx(self):logger.info(参数设置完毕开始保存数据)cur_path os.path.dirname(os.path.realpath(__file__))thread_num self.get_thread_num()loop_num self.get_loops()ramp_time self.get_ramp_time()script_name T{}L{}R{}-{}_{}.jmx.format(thread_num, loop_num, ramp_time, self.src_script, self.get_time())script_path os.path.join(cur_path, .., script)if not os.path.exists(script_path):os.mkdir(script_path)script_location os.path.join(script_path, script_name)logger.info(测试脚本已保存于 {}.format(script_location))with open(script_location, w) as f:f.write(str(self.soup))return script_name
if __name__ __main__:jmx OpJmx(templates/template.jmx)argvs sys.argvlen_argvs len(argvs) - 1if len_argvs 0:passelif len_argvs 1:jmx.set_thread_num(argvs[1])elif len_argvs 2:jmx.set_thread_num(argvs[1])jmx.set_loops(argvs[2])elif len_argvs 3:jmx.set_thread_num(argvs[1])jmx.set_loops(argvs[2])jmx.set_ramp_time(argvs[3])jmx.save_jmx()未完待续... 使用string.Template字符替换
如果只是简单的字符串替换使用 format 或者 %s 也能完成选择使用string.Template的原因是string.Template可以自动化匹配规则且能修改操作符 而不管是fstring还是format都是用的{}来进行关键字的定位{}在jmx脚本中本身就存在特定的意义。
思路
修改jmx脚本中的关键数据使用特定操作符定义相关字典使用safe_substitute进行赋值
具体实现
#! /usr/bin/python
# coding:utf-8 author:Bingo.he
file: str_temp.py
time: 2019/08/20 import string# with open(template_str.jmx, r) as f:
# data f.read()
set_value {num_threads: 10,loops: 1011,ramp_time: 10
}
str_temp ThreadGroup guiclassThreadGroupGui testclassThreadGroup testnameThread Group enabledtruestringProp nameThreadGroup.on_sample_errorcontinue/stringPropelementProp nameThreadGroup.main_controller elementTypeLoopController guiclassLoopControlPanel testclassLoopController testnameLoop Controller enabledtrueboolProp nameLoopController.continue_foreverfalse/boolPropstringProp nameLoopController.loops%loops/stringProp/elementPropstringProp nameThreadGroup.num_threads%num_threads/stringPropstringProp nameThreadGroup.ramp_time%ramp_time/stringPropboolProp nameThreadGroup.schedulerfalse/boolPropstringProp nameThreadGroup.duration/stringPropstringProp nameThreadGroup.delay/stringProp/ThreadGroup
class MyTemplate(string.Template):# 修改操作符为%delimiter %# 修改匹配规则(正则)# idpattern [a-z]_[a-z]t MyTemplate(str_temp)print(t.safe_substitute(set_value))输出
...stringProp nameLoopController.loops1011/stringProp
/elementProp
stringProp nameThreadGroup.num_threads101/stringProp
stringProp nameThreadGroup.ramp_time10/stringProp
...使用re.sub
str_temp ThreadGroup guiclassThreadGroupGui testclassThreadGroup testnameThread Group enabledtruestringProp nameThreadGroup.on_sample_errorcontinue/stringPropelementProp nameThreadGroup.main_controller elementTypeLoopController guiclassLoopControlPanel testclassLoopController testnameLoop Controller enabledtrueboolProp nameLoopController.continue_foreverfalse/boolPropstringProp nameLoopController.loops$loops/stringProp/elementPropstringProp nameThreadGroup.num_threads$num_threads/stringPropstringProp nameThreadGroup.ramp_time$ramp_time/stringPropboolProp nameThreadGroup.schedulerfalse/boolPropstringProp nameThreadGroup.duration/stringPropstringProp nameThreadGroup.delay/stringProp/ThreadGroup
str_l re.sub(r\$loops, 101, str_temp)
str_t re.sub(r\$num_threads, 102, str_l)
str_r re.sub(r\$ramp_time, 103, str_t)print(str_r)
输出
···boolProp nameLoopController.continue_foreverfalse/boolPropstringProp nameLoopController.loops101/stringProp/elementPropstringProp nameThreadGroup.num_threads102/stringPropstringProp nameThreadGroup.ramp_time103/stringProp
···延展
相信大家也注意到了我们每替换一个参数都需要调用一次re.sub而且要将上一次调用的输出作为下一次的输入像极了递归调用。但是我们今天不介绍递归改写的方法而是使用闭包的方式具体的例子如下
import redef multiple_replace(text, adict):rx re.compile(|.join(map(re.escape, adict)))def one_xlat(match):return adict[match.group(0)]return rx.sub(one_xlat, text) # 每遇到一次匹配就会调用回调函数# 把key做成了 |分割的内容也就是正则表达式的OR
map1 {1: 2, 3: 4, 5: 6}
_str 113355
print(multiple_replace(_str, map1))文中可能存在描述不正确欢迎大神们指正补充 资料获取方法
【留言777】 各位想获取源码等教程资料的朋友请点赞 评论 收藏三连
三连之后我会在评论区挨个私信发给你们~