油猴插件录制请求,封装接口自动化参数

news2024/12/25 10:29:53

参考:如何使用油猴插件提高测试工作效率

一、背景

在酷家乐设计工具测试中,总会有许多高频且较繁琐的工作,比如:

  • 查询插件版本:需要打开Chrome控制台,输入好几个命令然后过滤出版本信息。

  • 查询模型商品:需要先打开调试工具,查询得到模型商品id,然后跳转到测试平台进行加密,再去商家后台拼接url,最终访问到商品详情页。

  • 修改定制高级配置:至少要点击4次页面跳转,才能开始配置。

类似的重复性工作实在太多,无形中影响工作效率与体验。并且大量的命令记忆对新手特别不友好。

仔细分析这类行为,大多都属于"数据查询"、“命令输入” 、“页面访问” 等简单操作的组合,其实非常适合“插件化”,封装成各种【一键操作】。

二、思路

基于上述背景,我们期望能开发一个插件来提高测试工作效率。

对于测试插件,主要有以下诉求:

  • 开发门槛低。能让更多人参与进来,实现丰富的功能,满足各种需求。

  • API 强大。便于扩展更多能力。

  • 插件更新方便。便于新功能的推广。

最容易想到有两种方案: 酷家乐工具内部集成插件、Chrome 插件。但是很明显,这两种方式都存在开发门槛高、维护成本高、使用场景有限的缺点。

所以最后选择了另一种方案---油猴插件

什么是油猴插件?

篡改猴 (Tampermonkey) 是拥有 超过 1000 万用户 的最流行的浏览器扩展之一。它适用于 ChromeMicrosoft EdgeSafari 等主流浏览器。
它允许用户自定义并增强您最喜爱的网页的功能。用户脚本是小型 JavaScript 程序,可用于向网页添加新功能或修改现有功能。使用 篡改猴,您可以轻松在任何网站上创建、管理和运行这些用户脚本。

简单说,油猴插件是一个 Chrome 插件,但是它的功能是一个脚本管理器,能将自定义的脚本注入到当前页面,让你的代码成为网页的一部分。

油猴提供的API:

Documentation | Tampermonkey

GM_*API 按功能主要分为
WEB请求类:

GM_xmlhttpRequest(details)

GM_webRequest(rules, listener)

cookie操作:

GM_cookie.list(details[, callback])

GM_cookie.set(details[, callback])

GM_cookie.delete(details, callback)
tab选项卡操作:

GM_getTab(callback)
GM_saveTab(tab)
GM_getTabs(callback)
键值对操作:
GM_setValue(key, value)
GM_getValue(key, defaultValue)
GM_deleteValue(key)
GM_listValues()
GM_addValueChangeListener(key, (key, old_value, new_value, remote) => void)
GM_removeValueChangeListener(listenerId)
修改dom:
GM_addElement(tag_name, attributes), GM_addElement(parent_node, tag_name, attributes)
添加样式:
GM_addStyle(css)
下载:
GM_download(details), GM_download(url, name)
获取@resource 引入的资源文件的文本内容(比如js)
GM_getResourceText(name)
获取@resource 引入的资源文件的源地址
GM_getResourceURL(name)
控制台打印

GM_log(message)

屏幕通知

GM_notification(details, ondone),

GM_notification(text, title, image, onclick)

打开新选项卡

GM_openInTab(url, options),

GM_openInTab(url, loadInBackground)

菜单注册 GM_registerMenuCommand(name, callback, accessKey)
菜单注销 GM_unregisterMenuCommand(menuCmdId)
设置剪切板 GM_setClipboard(data, info)
windows窗体操作:
窗口地址改变 window.onurlchange
窗口关闭 window.close()
窗口聚焦 window.focus()

油猴脚本开发详解+油猴爬虫脚本实例_其它综合_脚本之家

demo1:页面上增加刷新按钮,且可以实现拖拽:

// ==UserScript==
// @name         测试插件
// @version      0.0.1
// @description  百度首页刷新
// @namespace    baidu.com
// @match        *://*/*
// @grant        GM_addStyle
// ==/UserScript==

const addContainerDiv=()=>{
    const containerDiv=document.createElement("div");
    containerDiv.id="test-tool"
    containerDiv.innerHTML= "<button>刷新1</button>"
    GM_addStyle('#test-tool {position:fixed;right:300px;top:280px;}')
    //containerDiv.addEventListener("click",()=>{window.location.reload()})
    document.body.appendChild(containerDiv);
    //设置可拖拽
    const dragButton=document.getElementById("test-tool");
    dragButton.onmousedown = function(ev){

        // 获取鼠标相对于盒子的坐标
        var x2 = ev.offsetX;
        var y2 = ev.offsetY;

        // 鼠标移动
        document.onmousemove = function (ev) {
            var x3 = ev.pageX;
            var y3 = ev.pageY;
            dragButton.style.top = y3 - y2 + "px";
            dragButton.style.left = x3 - x2 + "px"
        }

    }
     // 4.鼠标松开事件
    dragButton.onmouseup = function () {
        document.onmousemove = null;
    }
}

(function() {
    'use strict';
    addContainerDiv()
})();

 效果:(注意:如果加上刷新动作的话,会导致拖拽无效;所以先把这行代码注释掉了) 

demo2:录制接口

可以看到接口一般有两种类型,分别是fetch和xhr

Fetch和XHR都是用于发起HTTP请求的技术,但它们有以下几点区别:
1
原生API vs ES6新增函数:XHR是浏览器提供的原生API,而Fetch是ES6中新增的全局函数。
2
使用对象差异:XHR使用XMLHttpRequest对象,而Fetch使用Promise对象。
3
Cookies默认携带:Fetch默认不会携带cookies,需要手动设置credentials属性;而XHR请求会自动携带cookies。
4
请求取消能力:XHR可以取消一个正在进行的请求,而Fetch目前没有原生的请求取消机制。
5
响应类型处理:XHR的responseType属性可以设置响应类型(text、json、blob等),而Fetch需要手动解析响应。
6
进度监听功能:XHR可以监听上传和下载的进度,而Fetch不支持此功能。
7
错误处理方式:在错误处理方面,Fetch只会在网络错误时reject Promise,其他错误都会被视为成功的响应,需要手动判断;而XHR则会在出现错误时reject Promise。
8
兼容性:XHR兼容性更好,在一些旧版本的浏览器中可能无法使用Fetch2。
9
关注分离:Fetch是一种关注分离的技术,把复杂的事情拆分成几个简单的步骤实现,并得到结果3。
10
底层抽象:Fetch API更底层,包括Request、Response、Headers、Body等原生对象,而XHR需要使用一个实例来发出请求和处理响应。
11
灵活性:Fetch API比XHR更灵活,可以明确的配置请求和响应4。
12
兼容性:XHR兼容性更好,在一些旧版本的浏览器中可能无法使用Fetch2。
综上所述,Fetch和XHR各有优缺点,开发者应当根据项目需求和兼容性要求选择合适的请求技术

针对xhr:

  •  把运行时间设置为document-start,确保能拦截到较早发出的请求。
  • 使用 @grant unsafeWindow 声明,授予脚本访问或修改全局窗口对象的权限。

参考:油猴脚本高级应用:拦截与修改网页Fetch请求实战指南_油猴拦截请求-CSDN博客

这里有一点点无用代码,自己改改

// ==UserScript==
// @name         测试插件
// @run-at    document-start
// @version      0.0.1
// @description  百度首页刷新
// @namespace    baidu.com
// @match        *://*/*
// @grant        GM_addStyle
// @require      http://code.jquery.com/jquery-1.11.0.min.js
// @grant        unsafeWindow
// ==/UserScript==

const addContainerDiv=()=>{
    const containerDiv=document.createElement("div");
    containerDiv.id="test-tool"
    containerDiv.innerHTML= "<button>刷新1</button>"
    GM_addStyle('#test-tool {position:fixed;right:300px;top:280px;}')
    var aweme_list=[];
    containerDiv.addEventListener("click",()=>{
        console.log('aba:');
        console.log("aweme_list"+aweme_list);
                // 定义包含名称和链接的数组
                const files = [];
                aweme_list.forEach((item)=>{
                    if(item.aweme_type==0||item.awemeType==0||item.aweme_type==61||item.awemeType==61){
                        try{files.push({name:item.desc,url:item.video.play_addr.url_list[0]})}catch{files.push({name:item.desc,url:item.video.playAddr[0]})}
                    }
                    if(item.aweme_type==68||item.awemeType==68){
                        var urlList=[]
                        item.images.forEach(img=>{
                            try{urlList.push(img.url_list[0])}catch{urlList.push(img.urlList[0])}

                        })
                        files.push({name:item.desc,urlList:urlList})
                    }
                });
                console.log(files);
    })
    document.body.appendChild(containerDiv);
    //设置可拖拽
    const dragButton=document.getElementById("test-tool");
    dragButton.onmousedown = function(ev){

        // 获取鼠标相对于盒子的坐标
        var x2 = ev.offsetX;
        var y2 = ev.offsetY;

        // 鼠标移动
        document.onmousemove = function (ev) {
            var x3 = ev.pageX;
            var y3 = ev.pageY;
            dragButton.style.top = y3 - y2 + "px";
            dragButton.style.left = x3 - x2 + "px"
        }

    }
     // 4.鼠标松开事件
    dragButton.onmouseup = function () {
        document.onmousemove = null;
    }
}

(function() {
    'use strict';
    addContainerDiv();
    $(() => {
        function addXMLRequestCallback(callback) {

            // 是一个劫持的函数
            var oldSend, i;
            if (XMLHttpRequest.callbacks) {
                //   判断XMLHttpRequest对象下是否存在回调列表,存在就push一个回调的函数
                // we've already overridden send() so just add the callback
                XMLHttpRequest.callbacks.push(callback);
            } else {
                // create a callback queue
                XMLHttpRequest.callbacks = [callback];
                // 如果不存在则在xmlhttprequest函数下创建一个回调列表
                // store the native send()
                oldSend = XMLHttpRequest.prototype.send;
                // 获取旧xml的send函数,并对其进行劫持
                // override the native send()
                XMLHttpRequest.prototype.send = function () {
                    // process the callback queue
                    // the xhr instance is passed into each callback but seems pretty useless
                    // you can't tell what its destination is or call abort() without an error
                    // so only really good for logging that a request has happened
                    // I could be wrong, I hope so...
                    // EDIT: I suppose you could override the onreadystatechange handler though
                    for (i = 0; i < XMLHttpRequest.callbacks.length; i++) {
                        XMLHttpRequest.callbacks[i](this);
                    }
                    // 循环回调xml内的回调函数
                    //    由于我们获取了send函数的引用,并且复写了send函数,这样我们在调用原send的函数的时候,需要对其传入引用,而arguments是传入的参数
            
                    // call the native send()
                    oldSend.apply(this, arguments);
                   
                        }
            }



        }
        // e.g.
        addXMLRequestCallback(function (xhr) {
            // 调用劫持函数,填入一个function的回调函数
            // 回调函数监听了对xhr调用了监听load状态,并且在触发的时候再次调用一个function,进行一些数据的劫持以及修改
            xhr.addEventListener("load", function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // 获取URL
                    var url = new URL(xhr.responseURL);
                    console.log("xhr接口:" + url);


                }
            });

        });

    })


})();

 另一种写法,可以拿到url+参数:

var originalSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.send = function(body) {
        var xhr = this;

        // 保存原始的onreadystatechange事件处理器
        var originalOnReadyStateChange = xhr.onreadystatechange;

        // 重写onreadystatechange事件处理器
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) { // 请求已完成
                // 打印URL和请求参数
                console.log('Request URL:', xhr.responseURL);
                console.log('Request Parameters:', body);
            }

            // 如果存在,则调用原始的onreadystatechange事件处理器
            if (originalOnReadyStateChange) {
                originalOnReadyStateChange.apply(this, arguments);
            }
        };

        // 调用原始的send方法
        originalSend.apply(this, arguments);
    };

fetch的录制下来:

 const originFetch = fetch;
unsafeWindow.fetch = (...arg) => {
    console.log('fetch arg', ...arg);

        //console.log('通过')
        return originFetch(...arg);

}

如果想要修改响应的数据: 

参考:https://zhuanlan.zhihu.com/p/436757974

let oldfetch = fetch;
function fuckfetch() {
    return new Promise((resolve, reject) => {
        oldfetch.apply(this, arguments).then(response => {
            const oldJson = response.json;
            response.json = function() {
                return new Promise((resolve, reject) => {
                    oldJson.apply(this, arguments).then(result => {
                        result.hook = 'success';
                        resolve(result);
                    });
                });
            };
            resolve(response);
        });
    });
}
window.fetch = fuckfetch;

完整demo要求:抓捕当前页面上的所有请求,得到fetch格式:

得到这一串代码: 

fetch("http://xx/compare", {
  "headers": {
    "accept": "application/json, text/plain, */*",
    "accept-language": "zh-CN,zh;q=0.9",
    "content-type": "application/json",
    "proxy-connection": "keep-alive",
    "token": “”,
  "referrerPolicy": "strict-origin-when-cross-origin",
  "body": "{\"id\":\"3862\",“\Version\":\"001420240626\"}",
  "method": "POST",
});

然后可以拷贝url和body,之后可以直接粘贴到接口自动化脚本中,方便编写脚本

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

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

相关文章

java设计模式day03--(结构型模式:代理模式、适配器模式、装饰者模式、桥接模式、外观模式、组合模式、享元模式)

5&#xff0c;结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低&#xff0c;满足“…

SpingBoot中使用Swagger快速生成接口文档

目录 一.Swagger快速上手 二.Swagger中的基本注解 三.使用Swagger进行测试 一.Swagger快速上手 Swagger是⼀个接⼝⽂档⽣成⼯具&#xff0c;它可以帮助开发者⾃动⽣成接⼝⽂档。当项⽬的接⼝发⽣变更时&#xff0c;Swagger可以实时更新⽂档&#xff0c;确保⽂档的准确性和时…

【神经网络系列(高级)】神经网络Grokking现象的电路效率公式——揭秘学习飞跃的秘密【通俗理解】

【通俗理解】神经网络Grokking现象的电路效率公式 论文地址&#xff1a; https://arxiv.org/abs/2309.02390 参考链接&#xff1a; [1]https://x.com/VikrantVarma_/status/1699823229307699305 [2]https://pair.withgoogle.com/explorables/grokking/ 关键词提炼 #Grokkin…

组合优化与凸优化 学习笔记3 凸函数

目前学到了73页 凸函数的定义&#xff1a; 人话&#xff1a;函数f的定义域是凸集&#xff08;在一般的情况下就是不能是断开的定义域&#xff08;一般的情况是1维的嘛&#xff09;&#xff0c;假如x是什么多维向量的话就是说x的取值范围是一个凸集内&#xff09;&#xff0c;并…

基于云原生向量数据库 PieCloudVector 的 RAG 实践

近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;已然成为最热门的话题之一。工业界出现了各种内容生成工具&#xff0c;能够跨多种模态产生多样化的内容。这些主流的模型能够取得卓越表现&#xff0c;归功于创新的算法、模型规模的大幅扩展&#xff0c;以及海…

XXL-JOB调度中心与执行器

XXL-JOB是一个轻量级的分布式任务调度平台&#xff0c;主要由调度中心和执行器两部分组成。下面详细讲解调度中心与执行器的功能和作用。 调度中心 调度中心是XXL-JOB的核心组件&#xff0c;负责任务的调度管理。其主要功能包括&#xff1a; 任务管理&#xff1a;调度中心提供…

计算组合数:scipy.special.comb()

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 计算组合数&#xff1a; scipy.special.comb() 选择题 以下代码两次输出的结果是&#xff1f; from scipy.special import comb print("【执行】print(comb(3,2))") print(comb(3…

011. Oracle-约束

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

小白学装修 之 硬装阶段

在准备阶段 了解了 装修的基本概念 顺利收房 进行了需求和预算的大致规划 并且完成了简单的自主设计接下来就是带着自己的设计图 预算和想法 去找公司或者施工方了 找施工方 可以是 设计师和施工方分开找 也可以找有设计的装修公司 或者 有施工能力的设计室都行 但不 管哪…

【#第三期实战营闯关作业 ## 茴香豆:企业级知识库问答工具】

今天学习了《 茴香豆&#xff1a;企业级知识库问答工具》这一课&#xff0c;对大模型的应用有了更深得认识。以下是记录本课实操过程及截图&#xff1a; 搭建茴香豆虚拟环境&#xff1a; 输入以下命令 studio-conda -o internlm-base -t huixiangdou 成功安装虚拟环境截图 …

OpenAI gym CarRacing-v2 episode termination

题意&#xff1a;OpenAI Gym CarRacing-v2 赛道终止处理 问题背景&#xff1a; I am using gym0.26.0 library and am trying to understand what means that an episode is finished/done in the CarRacing-v2 environment. In the documentation is written this. 我正在使…

用Python实现时间序列模型实战——Day 12: 状态空间模型

一、学习内容 1. 状态空间模型的基本概念 状态空间模型是一种用于时间序列分析的强大工具&#xff0c;能够描述具有潜在状态动态变化的系统。该模型通过显式地建模时间序列中的潜在状态&#xff08;即隐藏变量&#xff09;&#xff0c;能够捕捉复杂的动态结构&#xff0c;适用…

如何选择合适的变压吸附制氧设备

在选择合适的变压吸附(Pressure Swing Adsorption, PSA)制氧设备时&#xff0c;需要综合考虑多个因素以确保设备能够高效、稳定地运行&#xff0c;满足特定应用场景的需求。以下是一些关键步骤和考虑因素&#xff0c;帮助您做出明智的决策。 1. 明确应用需求 明确您的制氧需求至…

GNU_HASH确定函数地址

前言&#xff1a; 最近看了以下pwntoos的DynELF方法&#xff0c;对其中是如何获取到函数地址的过程很感兴趣&#xff0c;就研究了一下&#xff0c;对通过DT_GNU_HASH获取函数地址的过程有了比较清晰的了解 漏洞&#xff1a; 我这里使用2013-PlaidCTF进行测试&#xff0c;首先…

DeepDFA: 受控制流分析驱动的有效深度漏洞检测

目前基于深度学习的漏洞检测中性能最高的方法使用的是基于 token 的 transformer 模型&#xff0c;这对于捕捉漏洞检测所需的代码语义来说并不是最有效的。文中设计了一个受数据流分析启发的图学习框架 DeepDFA&#xff0c;以及一种能让图学习模拟数据流计算的嵌入技术。其训练…

打造温馨家居,全屋智能家居解决方案

智能家居全屋解决方案覆盖全屋照明、温度、娱乐影音等各种常见的日常生活需求、可通过一键设置联动场景来控制自己的家、也可通过语音对话来操控家中的照明、电器及各种场景模式任意切换&#xff0c;一键升级自己的智能家。 1.入户解决方案 通过智能指纹锁穿过玄关、进入大厅、…

贴心服务,一路随行:用友BIP商旅云6.0推出客服中心

在全球经济日益一体化的今天&#xff0c;企业商旅活动频繁且复杂&#xff0c;对高效、专业的客户服务需求与日俱增。为了精准对接企业商旅管理的需求与挑战&#xff0c;用友BIP商旅云6.0创新性地推出了客服中心&#xff0c;以全方位、全天候的贴心服务&#xff0c;为企业商旅活…

OpenObserve云原生可观测平台本地Docker部署与远程访问实战教程

文章目录 前言1. 安装Docker2. Docker镜像源添加方法3. 创建并启动OpenObserve容器4. 本地访问测试5. 公网访问本地部署的OpenObserve5.1 内网穿透工具安装5.2 创建公网地址 6. 配置固定公网地址 前言 本文主要介绍如何在Linux系统使用Docker快速本地化部署OpenObserve云原生可…

html 页面引入 vue 组件之 http-vue-loader.js

一、http-vue-loader.js http-vue-loader.js 是一个 Vue 单文件组件加载器&#xff0c;可以让我们在传统的 HTML 页面中使用 Vue 单文件组件&#xff0c;而不必依赖 Node.js 等其他构建工具。它内置了 Vue.js 和样式加载器&#xff0c;并能自动解析 Vue 单文件组件中的所有内容…

运维学习————Jenkins(1)

目录 一、项目开发周期 二、jenkins的简介和作用 三、jenkins下载 1、使用war包安装 2、初始化配置 3、工作流程图 4、Jenkins安装配置maven和git maven git 5、jenkins安装插件 6、配置maven,git,jdk jdk配置 Git配置 Maven配置 四、修改tomcat的一些配置 五…