需求
定时作业使用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
看到下图结果,说明启动成功
