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

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

相关推荐
思麟呀1 小时前
Linux的基础IO流
linux·运维·服务器·开发语言·c++
winner88812 小时前
嵌入式Linux驱动开发全流程:工具协作+核心概念拆解(从入门到理解)
linux·运维·驱动开发
ShiinaKaze2 小时前
fatal error: bits/c++config.h: No such file or directory
linux·gcc·g++
Archy_Wang_12 小时前
脚本自动生成专业Linux巡检报告
linux·运维·服务器
java_logo3 小时前
SGLANG Docker容器化部署指南
linux·运维·docker·容器·eureka·1024程序员节
敲代码的瓦龙4 小时前
操作系统?进程!!!
linux·c++·操作系统
打不了嗝 ᥬ᭄4 小时前
数据链路层
linux·网络·网络协议·http
piaoxue8205 小时前
MFA MACOS 安装流程
linux·运维·服务器
小彭律师5 小时前
Node.js环境变量配置的实战技术
node.js
鱼干~6 小时前
electron基础
linux·javascript·electron