【nest】puppeteer 使用 addScriptTag 在页面中添加方法的方式

1.js方法支持(已测试)

1.1 先支持js

tsconfig.json

"compilerOptions": {"allowJs": true,...}

1.2 需要将抽离的方法放在js中封装

src/utils/utils.js

export function concatLabel(tagList)     {let labels = [];for (let i = 1; true; i++) {let li = tagList.querySelector(`li:nth-child(${i})`);if (li) {labels.push(li.textContent.trim());} else {break; // 当没有更多的 li 元素时,结束循环}}return labels.join('@');
}

1.3 service中使用该方法

import {concatLabel} from "./utils/utils.js";// 将该方法添加为script,因为如果不使用js的话,在页面执行的时候可能会报错
await page.addScriptTag({content: concatLabel.toString()});//使用 await page.$eval('执行页面代码const jobs = await page.$eval('.job-list-box', (el, methodName) => {return [...el.querySelectorAll('.job-card-wrapper')].map(item => {let tagList = item.querySelector('.company-tag-list');console.log("=========================")// 需要添加注解 @ts-ignore 否则编译无法通过// @ts-ignore// 由于该方法已注入页面,因此使用this即可调用let xxxxx = this.concatLabel(tagList);

2.引入 webpack 和 babel 的编译机制(未测试,记录下)

来源: https://www.xiday.com/2019/09/21/puppeteer-run-js/
有时我们可能需要在 Puppeteer 环境中执行一段 JS 代码。
根据官方提供的 API,我们有两种选择,

2.1 一种是添加 script 标签的方式引入 JS。

page.addScriptTag(options)

options <[Object]>
url <[string]> URL of a script to be added.
path <[string]> Path to the JavaScript file to be injected into frame. If path is a relative path, then it is resolved relative to [current working directory].
content <[string]> Raw JavaScript content to be injected into frame.
type <[string]> Script type. Use ‘module’ in order to load a Javascript ES6 module. See script for more details.
returns: <[Promise]<[ElementHandle]>> which resolves to the added tag when the script’s onload fires or when the script content was injected into frame.

2.2 另一种是使用page.evaluate

const result = await page.evaluate(x => {return Promise.resolve(8 * x);
}, 7);
console.log(result); // prints "56"

2.3 说明及遇到的问题

page.addScriptTag虽然可以引用本地文件作为 JS 执行,但是模块系统(ES6 Module 和 CommonJS 等)支持并不完善,部分 ES6 代码不支持 (最新 Chrome 可忽略)。
page.evaluate中的代码相当于在 DevTools 的控制台执行的,同样也有模块系统和 ES6 的问题,只是函数传值比page.addScriptTag方便。
所以我认为最好的解决方式是引入 webpack 和 babel 的编译机制。
具体方案是使用 Webpack Node API 配合 memory-fs 将要执行的 JS 文件作为入口,将编译结果输出为字符串,再通过page.evaluate执行。

2.4 具体方案

2.4.1 安装相关依赖

yarn add webpack memory-fs @babel/core @babel/preset-env babel-loader

2.4.2 编写一个buildModule函数来将指定文件作为入口,将相关模块依赖打包为 JS Bundle 字符串。

const webpack = require('webpack');
const MemoryFS = require('memory-fs');const buildModule = file => {const compiler = webpack({mode: 'development',devtool: 'cheap-module-eval-source-map',entry: require.resolve(file),output: {filename: 'bundle.js',path: '/build',},module: {rules: [{test: /\.m?js$/,exclude: /(node_modules|bower_components)/,use: {loader: 'babel-loader',},},],},});const fs = new MemoryFS();compiler.outputFileSystem = fs;return new Promise((resolve, reject) => {compiler.run(error => {if (error) {reject(error);return;}const content = fs.readFileSync('/build/bundle.js');resolve(content.toString());});});
};

2.4.3在根目录新建babel.config.js来指定打包时的 babel 配置,当然也可以复用项目已有的配置。

babel.config.js

module.exports = {presets: [['@babel/preset-env',{modules: false,useBuiltIns: 'entry',corejs: 3,targets: {chrome: 70,},},],],
};

最后,我们准备需要执行的 JS 入口文件,如果需要执行某些函数,可以将相关模块暴露到 window 对象,供 Puppeteer 使用。在这里我们将自己写的 sum 函数暴露到 window 上。
browser_run.js

import add from 'lodash/add';const sum = (...param) => [...param].reduce((a, b) => add(a, b), 0);window.sum = sum;

最终在 Puppeteer 中调用buildModule函数,传入入口文件路径,经由 webpack 打包和 babel 编译,最后通过page.evaluate函数执行。

const puppeteer = require('puppeteer');(async () => {const browser = await puppeteer.launch();const page = await browser.newPage();const scriptStr = await buildModule('./browser_run.js');await page.evaluate(scriptStr);await page.evaluate(() => {console.log('sum:', window.sum(1, 2, 3, 4, 5));});
})();

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

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

相关文章

node+nginx实现对react进行一键打包部署--windows版

文章目录 nodenginx实现对react进行一键打包部署--windows版1.功能展示及项目准备1.1功能展示 1.2 项目准备1.2.1技术点1.2.2安装相关配置(windows) 2.实现2.1 实现思路2.2 实现步骤2.1 项目准备2.1.1 创建env文件2.1.2 创建api/index.js文件2.1.3 添加解决跨域代码 2.2 项目实…

Android Studio中HAXM安装失败的解决方案(HAXM installation failed)

文章目录 错误示例Hyper-VWindows SandboxWindows Hypervisor Platform&#xff08;Windows 虚拟化监控程序平台&#xff09; 出现原因解决方法虚拟机平台方案一方案二方案三 错误示例 表明HAXM (Hardware Accelerated Execution Manager)安装失败了。HAXM是一个硬件辅助虚拟化…

FPGA SATA高速存储设计

今天来讲一篇如何在fpga上实现sata ip&#xff0c;然后利用sata ip实现读写sata 盘的目的&#xff0c;如果需要再速度和容量上增加&#xff0c;那么仅仅需要增加sata ip个数就能够实现增加sata盘&#xff0c;如果仅仅实现data的读写整体来说sata ip设计比较简单&#xff0c;下面…

车载系统类 UI 风格品质非凡

车载系统类 UI 风格品质非凡

List的五种常用遍历方式

在Java中&#xff0c;遍历List的方式有多种&#xff0c;每种方式适合不同的使用场景。以下是常见的几种遍历List的方式&#xff0c;并举例说明 public static void main(String[] args) {List<String> names new ArrayList<>();names.add("Alice");name…

数据资产与云计算深度融合:借助云计算技术,优化数据存储、高效处理并创新应用,驱动企业数字化转型

目录 一、引言 二、数据资产与云计算深度融合的必要性 1、数据资产的重要性 2、云计算技术的优势 三、云计算技术在数据资产管理中的应用 1、数据存储的优化 2、数据处理的高效性 3、数据应用的创新 四、云计算驱动企业数字化转型的实践案例 案例一&#xff1a;金融行…

JS的this关键字详解

引言 学习JS的this关键字往往难以理解和应用&#xff0c;本文详细解读JS中的this关键字&#xff0c;并结合案例给出相应的解释。 PS: https://github.com/WeiXiao-Hyy/blog整理了后端开发的知识网络&#xff0c;欢迎Star&#xff01; JS中的this关键字 this提供了一种更优雅…

虚拟机与主机的网络桥接

虚拟机网路桥接是一种网络配置方式&#xff0c;它允许虚拟机与物理网络中的其他设备直接通信。在桥接模式下&#xff0c;虚拟机的网络接口通过主机的物理网卡连接到局域网中&#xff0c;就像主机本身一样&#xff0c;拥有自己的MAC地址和IP地址。这种方式使得虚拟机可以像独立的…

【SpringBoot Web框架实战教程(开源)】01 使用 pom 方式创建 SpringBoot 第一个项目

导读 这是一系列关于 SpringBoot Web框架实战 的教程&#xff0c;从项目的创建&#xff0c;到一个完整的 web 框架&#xff08;包括异常处理、拦截器、context 上下文等&#xff09;&#xff1b;从0开始&#xff0c;到一个可以直接运用在生产环境中的web框架。而且所有源码均开…

MySQL进阶-索引-使用规则-最左前缀法则和范围查询

文章目录 1、最左前缀法则2、启动mysql3、查询tb_user4、查看tb_user的索引5、执行计划 profession 软件工程 and age31 and status 06、执行计划 profession 软件工程 and age317、执行计划 profession 软件工程8、执行计划 age31 and status 09、执行计划 status 010、执行…

方法的其他形式——方法使用时常见的问题

示例&#xff1a; public class MethodDemo02 {public static void main(String[] args) {//目标&#xff1a;掌握按照方法的实际业务需求不同&#xff0c;设计出合理的方法形式来解决问题//需求&#xff1a;打印三行Hello World.printfHelloWorld();System.out.println("…

python 字符串内置函数

序号函数作用1len()返回字符串的长度2find()查找字符串中指定子字符串的第一个出现的位置3rfind()查找字符串中指定子字符串的最后一个出现的位置4index()查找字符串中指定子字符串的第一个出现的位置&#xff0c;如果不存在则报错&#xff0c;提示异常。5rindex()查找字符串中…

dma是什么意思?什么是dma?

DMA有两种主要的含义&#xff0c;以下是针对这两种含义的详细解释&#xff1a; 一、DMA&#xff08;Dynamic Mechanical Analysis&#xff09; 定义&#xff1a; DMA&#xff0c;全称Dynamic Mechanical Analysis&#xff0c;即动态热机械分析。这是一种用于测量黏弹性材料的…

k8s持久化之emptyDir使用

目录 概述实践代码 概述 理解emptyDir使用&#xff0c;是后续k8s持久化进阶&#xff0c;高阶使用的基础。 实践 代码 详细说明在代码中 # 缓存数据&#xff0c;可以让多个容器共享数据 # 删除 Pod 时&#xff0c;emptyDir 数据同步消失 # 定义 initContainer -> 下载数据…

计组--输入输出系统--复习

文章目录 前言一、概述二、I/O接口三、主机和外设交换信息的方式四、中断系统总结 前言 学无止境&#xff0c;笔勤不辍。今晚加班&#xff0c;再赶一章…有关计组的输入输出系统相关的知识点… 一、概述 外设特点:1.数据传输速度相差较大 2.工作时有独立性&#xff0c;具有自…

K210视觉识别模块学习笔记6: 识别苹果_图形化操作函数_

今日开始学习K210视觉识别模块: 图形化操作函数 亚博智能 K210视觉识别模块...... 固件库: canmv_yahboom_v2.1.1.bin 训练网站: 嘉楠开发者社区 今日学习如何在识别到目标的时候添加图形化操作:(获取坐标、框出目标等) 在识别苹果的基础上 学习与添加 这些操…

C# 入门—实现 Hello, World!

目录 一、.net 平台 二、.net 都能干什么&#xff1f; 三、.net 两种交互模式 四、使用 VS Code 开发 C# 程序 五、实现 Hello, World! 一、.net 平台 下载 .NET(Linux、macOS 和 Windows) (microsoft.com) .NET 简介 - .NET | Microsoft Learn C# :一种编程语言,可以开…

未来出行新选择——加油宝APP,让您的每一次加油都充满智慧与便捷!

一、前言 随着科技的飞速发展&#xff0c;智能手机已经成为我们生活中不可或缺的一部分。为了满足广大车主对便捷、高效加油服务的需求&#xff0c;我们倾力打造了全新的加油宝APP。这款APP不仅为您提供一站式的加油服务&#xff0c;还融合了多项创新功能&#xff0c;让您的出…

从0开始C++(十一):智能指针

目录 概念 作用 auto_ptr(自动指针) unique_ptr(唯一指针) shared_ptr(共享指针) weak_ptr(虚指针) 补充&#xff1a;手写一个共享指针类 概念 C的智能指针是一种用于管理动态分配内存的指针。它是C语言的一个重要特性&#xff0c;通过自动管理内存资源&#xff0c;帮助开…

C语言入门系列:特殊的main函数和exit函数

文章目录 一&#xff0c;main函数二&#xff0c;exit函数1&#xff0c;exit函数2&#xff0c;atexit()函数2.1 atexit函数的简介2.2 atexit注册的函数一定会被调用吗2.2.1 正常退出测试2.2.2 异常退出测试 一&#xff0c;main函数 一个C程序至少包含一个函数&#xff0c;这个函…