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脚本代码
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 使用内置的 Chromiumreturn 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
看到下图结果,说明启动成功