浏览器自动化方案

B端后台列表页自动新增素材方案

我设计了一套完整的浏览器自动化方案,使用 Puppeteer 实现B端后台列表页的自动新增素材功能。该方案包含数据组织、浏览器操作、错误处理等完整流程。

一、技术选型

  1. 浏览器自动化工具:Puppeteer (https://pptr.dev)
  2. 任务调度:Bull (https://github.com/OptimalBits/bull)
  3. 配置管理:dotenv (https://github.com/motdotla/dotenv)
  4. 日志记录:Winston (https://github.com/winstonjs/winston)

二、数据模型设计

首先定义素材数据结构,支持不同类型的素材:

// material.js
class Material {constructor(templateType, category, materialType, content) {this.templateType = templateType; // 模版类型:九宫格模版/幸运盲盒模版this.category = category;         // 素材类别:背景图片/抽奖动画/立即下载文案this.materialType = materialType; // 素材类型:图片/文本/代码块this.content = content;           // 素材内容:图片路径/文本内容/代码块内容this.status = 'pending';          // 处理状态this.createTime = new Date();}
}// 工厂方法创建不同类型的素材
class MaterialFactory {static createImageMaterial(templateType, category, filePath) {return new Material(templateType, category, '图片', { filePath });}static createTextMaterial(templateType, category, text) {return new Material(templateType, category, '文本', { text });}static createCodeMaterial(templateType, category, code) {return new Material(templateType, category, '代码块', { code });}
}module.exports = { Material, MaterialFactory };

三、浏览器自动化实现

使用 Puppeteer 实现浏览器自动操作流程:

// browser-automation.js
const puppeteer = require('puppeteer');
const { Material } = require('./material');
const logger = require('./logger');class BrowserAutomation {constructor(config) {this.config = config;this.browser = null;this.page = null;}// 初始化浏览器async init() {this.browser = await puppeteer.launch({headless: this.config.headless,args: ['--window-size=1920,1080'],slowMo: this.config.slowMo || 0});this.page = await this.browser.newPage();await this.page.setDefaultTimeout(this.config.timeout || 30000);}// 登录系统async login() {logger.info('开始登录系统');await this.page.goto(this.config.loginUrl);// 输入用户名和密码await this.page.type(this.config.selectors.username, this.config.username);await this.page.type(this.config.selectors.password, this.config.password);// 点击登录按钮await Promise.all([this.page.click(this.config.selectors.loginButton),this.page.waitForNavigation()]);logger.info('登录成功');}// 导航到素材列表页async navigateToListPage() {logger.info('导航到素材列表页');await this.page.goto(this.config.listPageUrl);await this.page.waitForSelector(this.config.selectors.listPage);}// 点击"新增AI素材"按钮async clickAddAIMaterialButton() {logger.info('点击"新增AI素材"按钮');await this.page.waitForSelector(this.config.selectors.addAIMaterialButton);await this.page.click(this.config.selectors.addAIMaterialButton);// 等待弹窗出现await this.page.waitForSelector(this.config.selectors.modal);}// 选择模版类型async selectTemplateType(templateType) {logger.info(`选择模版类型: ${templateType}`);await this.page.waitForSelector(this.config.selectors.templateTypeSelect);// 根据模版类型选择对应的选项值const templateValueMap = {'九宫格模版': 'nine-grid','幸运盲盒模版': 'lucky-box'};const templateValue = templateValueMap[templateType];if (!templateValue) {throw new Error(`未知的模版类型: ${templateType}`);}await this.page.select(this.config.selectors.templateTypeSelect, templateValue);}// 选择素材类别async selectCategory(category) {logger.info(`选择素材类别: ${category}`);await this.page.waitForSelector(this.config.selectors.categorySelect);// 根据素材类别选择对应的选项值const categoryValueMap = {'背景图片': 'background-image','抽奖动画': 'lottery-animation','立即下载文案': 'download-copywriting'};const categoryValue = categoryValueMap[category];if (!categoryValue) {throw new Error(`未知的素材类别: ${category}`);}await this.page.select(this.config.selectors.categorySelect, categoryValue);}// 选择素材类型async selectMaterialType(materialType) {logger.info(`选择素材类型: ${materialType}`);await this.page.waitForSelector(this.config.selectors.materialTypeSelect);// 根据素材类型选择对应的选项值const materialTypeValueMap = {'图片': 'image','文本': 'text','代码块': 'code'};const materialTypeValue = materialTypeValueMap[materialType];if (!materialTypeValue) {throw new Error(`未知的素材类型: ${materialType}`);}await this.page.select(this.config.selectors.materialTypeSelect, materialTypeValue);}// 处理素材内容async processContent(material) {logger.info(`处理素材内容: ${material.materialType}`);switch (material.materialType) {case '图片':await this.uploadImage(material.content.filePath);break;case '文本':await this.fillTextContent(material.content.text);break;case '代码块':await this.fillCodeContent(material.content.code);break;default:throw new Error(`不支持的素材类型: ${material.materialType}`);}}// 上传图片async uploadImage(filePath) {logger.info(`上传图片: ${filePath}`);await this.page.waitForSelector(this.config.selectors.imageUploadInput);const fileInput = await this.page.$(this.config.selectors.imageUploadInput);await fileInput.uploadFile(filePath);// 等待上传完成await this.page.waitForSelector(this.config.selectors.imageUploadSuccess, {timeout: 60000 // 图片上传可能需要较长时间});}// 填写文本内容async fillTextContent(text) {logger.info('填写文本内容');await this.page.waitForSelector(this.config.selectors.textContentArea);await this.page.type(this.config.selectors.textContentArea, text);}// 填写代码块内容async fillCodeContent(code) {logger.info('填写代码块内容');await this.page.waitForSelector(this.config.selectors.codeContentArea);await this.page.type(this.config.selectors.codeContentArea, code);}// 点击确定按钮完成入库async submitMaterial() {logger.info('点击确定按钮');await this.page.waitForSelector(this.config.selectors.confirmButton);// 点击确定并等待提交完成await Promise.all([this.page.click(this.config.selectors.confirmButton),this.page.waitForSelector(this.config.selectors.submitSuccessMessage, { timeout: 15000 })]);logger.info('素材入库成功');return true;}// 关闭浏览器async close() {if (this.browser) {await this.browser.close();}}// 执行完整的素材入库流程async processMaterial(material) {try {await this.init();await this.login();await this.navigateToListPage();await this.clickAddAIMaterialButton();await this.selectTemplateType(material.templateType);await this.selectCategory(material.category);await this.selectMaterialType(material.materialType);await this.processContent(material);const success = await this.submitMaterial();material.status = success ? 'success' : 'failed';return { success, material };} catch (error) {logger.error(`处理素材失败: ${error.message}`);material.status = 'failed';material.errorMessage = error.message;return { success: false, material, error };} finally {await this.close();}}
}module.exports = BrowserAutomation;

四、配置管理

创建配置文件管理选择器和环境变量:

// config.js
require('dotenv').config();module.exports = {// 环境配置headless: process.env.HEADLESS === 'true',slowMo: parseInt(process.env.SLOW_MO) || 0,timeout: parseInt(process.env.TIMEOUT) || 30000,// 登录配置loginUrl: process.env.LOGIN_URL,username: process.env.USERNAME,password: process.env.PASSWORD,// 页面URLlistPageUrl: process.env.LIST_PAGE_URL,// DOM选择器配置selectors: {// 登录页面username: '#username',password: '#password',loginButton: '#login-button',// 列表页面listPage: '.material-list',addAIMaterialButton: '#add-ai-material-btn',// 新增弹窗modal: '.add-material-modal',templateTypeSelect: '#template-type',categorySelect: '#category',materialTypeSelect: '#material-type',// 内容区域imageUploadInput: 'input[type="file"]',imageUploadSuccess: '.upload-success',textContentArea: '#text-content',codeContentArea: '#code-content',// 提交区域confirmButton: '.confirm-btn',submitSuccessMessage: '.success-message'}
};

五、任务调度与批量处理

使用 Bull 实现任务队列,支持批量处理多个素材:

// queue.js
const Queue = require('bull');
const BrowserAutomation = require('./browser-automation');
const config = require('./config');
const logger = require('./logger');// 创建任务队列
const materialQueue = new Queue('material-upload', {redis: {host: process.env.REDIS_HOST || 'localhost',port: parseInt(process.env.REDIS_PORT) || 6379}
});// 处理队列任务
materialQueue.process(async (job) => {const material = job.data;logger.info(`开始处理素材任务: ${material.id}`);const automation = new BrowserAutomation(config);return await automation.processMaterial(material);
});// 添加素材到队列
async function enqueueMaterial(material) {return await materialQueue.add(material, {attempts: 3, // 失败重试3次backoff: { type: 'exponential', delay: 1000 } // 重试间隔递增});
}// 监听队列事件
materialQueue.on('completed', (job, result) => {if (result.success) {logger.info(`素材任务 ${job.id} 处理成功`);} else {logger.error(`素材任务 ${job.id} 处理失败: ${result.error.message}`);}
});materialQueue.on('failed', (job, error) => {logger.error(`素材任务 ${job.id} 处理失败: ${error.message}`);
});module.exports = { enqueueMaterial };

六、使用示例

下面是如何使用上述代码的示例:

// app.js
const { MaterialFactory } = require('./material');
const { enqueueMaterial } = require('./queue');async function main() {// 创建不同类型的素材const imageMaterial = MaterialFactory.createImageMaterial('九宫格模版', '背景图片', './assets/background.jpg');const textMaterial = MaterialFactory.createTextMaterial('幸运盲盒模版', '立即下载文案', '点击下载,立即参与抽奖活动,赢取丰厚奖品!');const codeMaterial = MaterialFactory.createCodeMaterial('九宫格模版', '抽奖动画', 'function startLottery() { ... }');// 将素材添加到处理队列await enqueueMaterial(imageMaterial);await enqueueMaterial(textMaterial);await enqueueMaterial(codeMaterial);console.log('所有素材已添加到处理队列');
}main().catch(error => {console.error('执行过程中发生错误:', error);
});

七、部署与运行

  1. 安装依赖:

    npm install puppeteer bull dotenv winston
    
  2. 创建 .env 文件配置环境变量:

    HEADLESS=true
    SLOW_MO=0
    TIMEOUT=60000
    LOGIN_URL=https://your-b-system.com/login
    USERNAME=your_username
    PASSWORD=your_password
    LIST_PAGE_URL=https://your-b-system.com/materials
    REDIS_HOST=localhost
    REDIS_PORT=6379
    
  3. 运行程序:

    node app.js
    

八、关键技术点说明

  1. Puppeteer 核心功能

    • 元素选择与操作:page.$page.$$page.clickpage.type
    • 页面导航与等待:page.gotopage.waitForSelectorpage.waitForNavigation
    • 文件上传:uploadFile 方法
    • 无头模式:headless 选项
  2. 错误处理

    • 重试机制:通过 Bull 队列实现自动重试
    • 超时设置:全局超时和特定操作超时
    • 日志记录:使用 Winston 记录详细操作日志
  3. 配置化设计

    • 将选择器和环境变量外部化,便于适配不同系统
    • 支持通过环境变量控制执行模式(无头/有头、执行速度)

通过这个方案,您可以实现B端后台列表页的自动化新增素材功能,支持多种模版类型、素材类别和素材类型,大幅提高工作效率。

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

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

相关文章

MPPT电路设计

反激的具体计算过程要写好起码要一天,所以本次先更MPPT。这章不计算具体参数,只做分析。 目录 一、电路作用 二、电路设计 采样电路和输入电路 主体电路 驱动电路 一、电路作用 MPPT电路是一种广泛应用于光伏发电、风力发电等新能源系统中的关键电…

【基于飞浆训练车牌识别模型】

基于飞浆训练车牌识别模型 基于飞浆训练车牌识别模型 LPRNet(License Plate Recognition via Deep Neural Networks)是一种轻量级卷积神经网络,专为端到端车牌识别设计,由Intel IOTG Computer Vision Group的Sergey Zherzdev于201…

No module named ‘sklearn‘

1、运行python数据分析库时报错 No module named sklearn2、原因 虚拟环境未安装 sklearn 库(即 scikit-learn)。 3、解决方案 pip install scikit-learn使用国内镜像源: pip install scikit-learn -i https://mirrors.aliyun.com/pypi/simpl…

XPath注入攻击详解:原理、危害与防御

什么是XPath注入? XPath注入(XPath Injection)是一种针对使用XPath查询语言的应用程序的安全攻击技术,类似于SQL注入。当应用程序使用用户提供的输入来构造XPath查询而没有进行适当的过滤或转义时,攻击者可以通过构造恶…

网络编程(套接字)

目录 一、套接字 1、套接字的作用 2、关于TCP和UDP协议 1. TCP协议 2. UDP协议 3. 两者的区别 2、套接字函数 1)函数 socket(创建套接字同文件描述符) 2)准备套接字用结构体 1. 套接字的结构体 2. 客户端的套接字&…

R语言安装包

# 在安装过程中指定源地址 install.packages("RCurl", repos "https://mirrors.tuna.tsinghua.edu.cn/CRAN/") # 查看当前镜像 options()$repos # 设置为中科大镜像 options("repos" c(CRAN"https://mirrors.ustc.edu.cn/CRAN/")…

微服务引擎 MSE 及云原生 API 网关 2025 年 5 月产品动态

点击此处,了解微服务引擎 MSE 产品详情。

性能测试过程中监控linux服务器资源情况

文章目录1. cpu使用情况(1)性能瓶颈类型CPU密集型瓶颈​​I/O或等待瓶颈​(2)资源分配与竞争​资源争用分析​虚拟化环境资源分配​(3)系统稳定性与异常​​异常波动与毛刺​​过热降频影响​(4…

使用defineExpose暴露子组件的属性和方法、页面生命周期onLoad和onReady的使用

欢迎来到我的UniApp技术专栏!🎉 在这里,我将与大家分享关于UniApp开发的实用技巧、最佳实践和项目经验。 专栏特色: 📱 跨平台开发一站式解决方案 🚀 从入门到精通的完整学习路径 💡 实战项目经…

新手必看!VSCodePyCharm 配置 OpenCV 超详细教程(支持 Python 和 C++ 双语言)

新手必看!VSCode&PyCharm 配置 OpenCV 超详细教程(支持 Python 和 C 双语言) 适用对象:初学者,希望在 VSCode 与 PyCharm 两款常用 IDE 中,学会配置并使用 OpenCV,分别实现 Python 与 C 环境…

PyTorch深度学习框架入门案例实战

PyTorch深度学习框架详解与实战 1. PyTorch简介与环境配置 1.1 安装与导入 # 基础导入 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset import numpy as np import…

Spring Boot - Spring Boot 集成 MyBatis 分页实现 手写 SQL 分页

一、准备阶段 1、依赖引入 pom.xml <properties>...<postgresql.verison>42.5.6</postgresql.verison><mybatis.version>3.0.1</mybatis.version> </properties><dependencies>...<!-- postgresql 驱动 --><dependency>…

李宏毅《生成式人工智能导论》 | 第9讲 AI Agent

文章目录大模型未来趋势&#xff1a;以大型语言模型打造的AgentAI Agent运行的可能原理有记忆的ChatGPT大模型未来趋势&#xff1a;以大型语言模型打造的Agent 人类需要做多步骤的复杂任务&#xff0c;AI可以做到这件事吗&#xff1f; 如果可以我们将其称为AI Agent&#xff…

OCR 与 AI 图像识别:协同共生的智能双引擎

OCR 擅长提取图像中的文字信息&#xff0c;但面对复杂背景、扭曲角度的图片时&#xff0c;容易受干扰&#xff1b;AI 图像识别能解析图像场景、物体形态&#xff0c;却难以精准捕捉文字细节 —— 两者结合才能释放最大价值。比如在票据处理中&#xff0c;AI 图像识别先定位票据…

C# 按照主题的订阅 按照类型的订阅

安装TinyPubSub库&#xff0c;按照 主题发布订阅using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Form…

当执行shell时,出现未预期的符号 `$‘\r‘‘ 附近有语法错误

1.当执行shell时&#xff0c;出现未预期的符号 $‘\r’’ 附近有语法错误 解决&#xff1a; linux下解决&#xff1a; 方案一&#xff1a; Linux下打开shell文件&#xff0c;用vi/vim命令打开脚本文件&#xff0c;输入“:set fileformatunix”&#xff0c;回车&#xff0c;保存…

合作共赢|华望系统科技受邀出席杭州市基础软件和工业软件产业技术联盟成立大会

大会现场&#xff08;图源官方&#xff09;2025年7月11日&#xff0c;在杭州市经济和信息化局&#xff08;杭州市数字经济局&#xff09;的指导下&#xff0c;杭州市基础软件与工业软件产业技术联盟成立大会暨工业软件生态共性云平台发布仪式在西电杭州研究院圆满举行。会上&am…

7.17 滑动窗口

lc523.同余定理两个注意点同余定理&#xff1a;余数相同的两个数&#xff0c;做差可被整除。--前缀和hash存mod&#xff0c;不可以用set&#xff0c;因为要保证len大于等于2&#xff0c;所以要存idx映射&#xff01;&#xff01;还有对于全选和全不选的两个边界&#xff0c;下标…

算法与前端的可访问性

引言 可访问性&#xff08;Accessibility, a11y&#xff09;是现代 Web 开发的核心&#xff0c;确保所有用户&#xff0c;包括残障人士&#xff0c;都能无障碍地使用应用。算法在优化前端性能的同时&#xff0c;也能通过高效的数据处理和交互逻辑提升可访问性体验。例如&#x…

使用token调用Spring OAuth2 Resource Server接口错误 insufficient_scope

1、场景 最近照着《Spring Security实战》学习&#xff0c;学到第18章&#xff0c;使用Keycloak作为授权服务器&#xff0c;使用 org.springframework.boot:spring-boot-starter-oauth2-resource-server 实现资源服务器&#xff0c;调用资源服务器的接口返回403&#xff0c;具…