Linux设置定时作业执行node.js脚本

需求

定时作业使用puppeteer工具后台打开sapui5 web应用,截图发送到企业微信

1.timer和service文件路径/etc/systemd/system/

service代码

复制代码
[Unit]
Description=1000DayPushWx Service
After=network.target

[Service]
Type=oneshot
User=root
Group=root
WorkingDirectory=/opt/zauto
ExecStart=/usr/bin/node /opt/zauto/1000DayPushWx.js
StandardOutput=journal
StandardError=journal
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

js脚本路径

timer代码

复制代码
[Unit]
Description=Run 1000DayPushWx daily
Requires=1000DayPushWx.service

[Timer]
# 每天上午 9:10 执行
OnCalendar=*-*-* 09:10:00
Persistent=true

[Install]
WantedBy=timers.target 

2.node.js脚本代码

javascript 复制代码
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const os = require('os');

// 日志写入函数
function writeLog(message) {
    const logPath = path.join(__dirname, '1000_day_push.log');
    const time = new Date().toISOString();
    fs.appendFileSync(logPath, `[${time}] ${message}\n`);
    console.log(`[${time}] ${message}`);
}

// 根据操作系统确定Chrome路径
function getChromePath() {
    const platform = os.platform();
    
    if (platform === 'win32') {
        return 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
    } else if (platform === 'linux') {
        // Linux 系统下的 Chrome 路径
        const possiblePaths = [
            '/usr/bin/google-chrome',
            '/usr/bin/google-chrome-stable',
            '/usr/bin/chromium',
            '/usr/bin/chromium-browser'
        ];
        
        for (const chromePath of possiblePaths) {
            if (fs.existsSync(chromePath)) {
                return chromePath;
            }
        }
        
        // 如果找不到,让 Puppeteer 使用内置的 Chromium
        return null;
    }
    
    return null;
}

(async () => {
    const chromePath = getChromePath();
    const launchOptions = {
        headless: true,
        args: [
            '--window-size=800,1700',
            '--no-sandbox',
            '--disable-setuid-sandbox',
            '--disable-dev-shm-usage',
            '--disable-gpu',
            '--no-first-run',
            '--no-zygote',
            '--single-process'
        ]
    };
    
    // 如果找到了 Chrome 路径,则使用它
    if (chromePath) {
        launchOptions.executablePath = chromePath;
        writeLog(`使用 Chrome 路径: ${chromePath}`);
    } else {
        writeLog('使用 Puppeteer 内置的 Chromium');
    }
    
    const browser = await puppeteer.launch(launchOptions);
    
    const page = await browser.newPage();
    await page.setViewport({ width: 800, height: 1700 });
    
    // 设置更长的超时时间
    await page.setDefaultTimeout(60000);
    
    // 设置 Basic Auth 账号密码
    await page.authenticate({
        username: 账号,
        password: 密码
    });
    writeLog('已设置Basic Auth');
    
    // 访问页面,等待网络空闲
    await page.goto('http://ip/zfiori_fi06/index.html', {
        waitUntil: 'networkidle2',
        timeout: 60000
    });
    writeLog('页面打开成功');
    
    // 等待 UI5 应用完全初始化
    writeLog('等待UI5应用初始化...');
    await page.waitForFunction(() => {
        return window.sap && 
               window.sap.ui && 
               window.sap.ui.getCore() && 
               window.sap.ui.getCore().getComponent;
    }, { timeout: 30000 });
    writeLog('UI5应用初始化完成');
    
    // 等待页面元素出现,增加重试机制
    writeLog('查找page元素...');
    let pageElement = null;
    let retryCount = 0;
    const maxRetries = 3;
    
    while (!pageElement && retryCount < maxRetries) {
        try {
            pageElement = await page.waitForSelector('[id$="page"]', {
                timeout: 20000,
                visible: true
            });
            writeLog('page元素加载完成');
            break;
        } catch (error) {
            retryCount++;
            writeLog(`第 ${retryCount} 次尝试失败,等待 3 秒后重试...`);
            await page.waitForTimeout(3000);
        }
    }
    
    if (!pageElement) {
        writeLog('ERROR: 无法找到page元素,保存调试截图');
        await page.screenshot({ path: 'debug-page-not-found.png' });
        throw new Error('无法找到page元素');
    }
    
    // 等待页面完全渲染
    await new Promise(resolve => setTimeout(resolve, 5000));
    writeLog('页面渲染完成');
    
    // 等待 VizFrame 元素加载
    writeLog('等待day viz空间加载开始');
    
    const vizSelectors = [
        '[id$="idVizFrame5"]',
        '[id$="idVizFrame6"]',
        '[id$="idVizFrame7"]'
    ];
    
    for (const selector of vizSelectors) {
        try {
            await page.waitForSelector(selector, { 
                timeout: 30000,
                visible: true 
            });
            writeLog(`VizFrame元素 ${selector} 加载完成`);
        } catch (error) {
            writeLog(`ERROR: VizFrame元素 ${selector} 加载失败`);
            // 保存调试截图
            await page.screenshot({ path: `debug-vizframe-${selector}.png` });
            throw error;
        }
    }
    
    writeLog('等待day viz空间加载完成');
    
    // 等待额外时间确保图表完全渲染
    await new Promise(resolve => setTimeout(resolve, 3000));
    writeLog('图表渲染完成');
    
    // 查找并点击截图按钮
    writeLog('查找截图按钮...');
    try {
        await page.waitForSelector('[id$="idjtButton"]', { 
            timeout: 15000,
            visible: true 
        });
        await page.click('[id$="idjtButton"]');
        writeLog('已点击截图按钮');
    } catch (error) {
        writeLog('ERROR: 无法找到或点击截图按钮');
        await page.screenshot({ path: 'debug-button-not-found.png' });
        throw error;
    }
    
    writeLog('已发送日数据');
    
    // 等待操作完成
    await new Promise(resolve => setTimeout(resolve, 5000));
    writeLog('操作完成');
    
    await browser.close();
    writeLog('浏览器已关闭');
    
})().catch(error => {
    writeLog(`脚本执行失败: ${error.message}`);
    process.exit(1);
});

3.启动定时作业的linux命令

启用定时器(开机自启)

systemctl enable 1000DayPushWx.timer

启动定时器

systemctl start 1000DayPushWx.timer

检查状态

systemctl status 1000DayPushWx.timer

看到下图结果,说明启动成功

相关推荐
Yyyy4822 小时前
Ubuntu安装Jenkis
linux·运维·ubuntu
zhuzewennamoamtf3 小时前
Linux SPI设备驱动
android·linux·运维
春日见3 小时前
在虚拟机上面无法正启动机械臂的控制launch文件
linux·运维·服务器·人工智能·驱动开发·ubuntu
松涛和鸣3 小时前
Linux Makefile : From Basic Syntax to Multi-File Project Compilation
linux·运维·服务器·前端·windows·哈希算法
Predestination王瀞潞4 小时前
JDK安装及环境变量配置
java·linux·开发语言
再睡一夏就好4 小时前
深入Linux线程:从轻量级进程到双TCB架构
linux·运维·服务器·c++·学习·架构·线程
小小药4 小时前
09-vmware配置虚机连接互联网-nat模式
linux·运维·centos
Bright Xu5 小时前
Qemu 安装 LoongArch架构 Fedora Remix F42 Linux系统
linux·loongarch·国产cpu
莫白媛5 小时前
Linux创作笔记综合汇总篇
linux·运维·笔记
studytosky5 小时前
Linux系统编程:深度解析 Linux 进程,从底层架构到内存模型
linux·运维·服务器·开发语言·架构·vim