Python(兼容Jython)跨设备JS脚本基线对比工具优化问询
脚本对比工具优化方案(适配Python 2.7/Jython)
一、对比流程优化
- 增强ndiff输出解析:基于
difflib.ndiff的输出,自定义逻辑将差异映射为新增、删除、修改三类明确类型,而非仅标记行号:- 以
+开头的行标记为新增行 - 以
-开头的行标记为删除行 - 成对出现的
-和+行标记为修改行(明确原行与修改后行的对应关系)
- 以
- 脚本预处理:对比前统一格式化JS脚本(正则去除多余空格/换行、统一缩进),避免格式差异被误判为逻辑变更;对基准脚本和设备脚本做相同标准化处理。
- 按模块拆分对比:若JS脚本有明确的函数/模块划分,先拆分后逐块对比,输出时标注具体函数名,更精准定位变更位置。
二、审计输出丰富化
- 结构化报告内容:每台设备的审计报告包含以下部分:
- 设备基础信息:设备ID、部署地点、IP地址
- 差异统计:新增行数、删除行数、修改行数
- 详细差异清单:按变更类型分组展示,示例:
设备ID: D1001 | 地点: 北京机房 差异统计: 新增2行,删除1行,修改1行 详细差异: 1. 修改行 基准脚本: function sendData() { 设备脚本: function sendUpdatedData() { 2. 删除行 基准脚本: console.log("Debug mode enabled"); 3. 新增行 设备脚本: var timestamp = new Date().getTime(); 设备脚本: payload.timestamp = timestamp;
- 双格式输出:同时生成易读的纯文本报告(用于邮件)和JSON格式数据(方便后续自动化处理)。
三、自动化流程实现
- 批量设备处理:编写循环逻辑批量拉取所有设备的运行脚本,用Jython线程池实现简单并发,提升处理效率。
- 自动告警邮件:用Python 2.7标准库
smtplib+email构建邮件,将审计报告作为正文;主题明确标记异常设备,比如[脚本告警] 设备D1001脚本与基准不符。 - 异常过滤规则:配置忽略注释行变更、设置变更行数阈值,仅当差异达到阈值时发送邮件,减少误报。
四、Jython与Ignition适配注意事项
- 严格遵循Python 2.7语法:用
print语句而非函数、xrange替代range,统一UTF-8编码避免中文乱码。 - 利用Ignition内置API:调用
system.device.listDevices()批量获取设备信息,借助Ignition日志系统记录审计过程。 - 依赖轻量化:仅使用Python标准库,避免引入第三方库(Jython对第三方库支持有限)。
核心代码片段
import difflib import smtplib from email.mime.text import MIMEText def compare_scripts(base_script, device_script): # 预处理:统一格式并过滤空行 base_lines = [line.strip() for line in base_script.splitlines() if line.strip()] device_lines = [line.strip() for line in device_script.splitlines() if line.strip()] diff = difflib.ndiff(base_lines, device_lines) diff_result = [] current_change = {} for line in diff: if line.startswith('- '): current_change['base'] = line[2:] elif line.startswith('+ '): if 'base' in current_change: # 标记修改行 diff_result.append({ 'type': 'modified', 'base_line': current_change['base'], 'device_line': line[2:] }) current_change = {} else: # 标记新增行 diff_result.append({ 'type': 'added', 'device_line': line[2:] }) elif line.startswith('? '): continue else: if current_change: # 标记删除行 diff_result.append({ 'type': 'removed', 'base_line': current_change['base'] }) current_change = {} # 处理剩余的删除行 if current_change: diff_result.append({ 'type': 'removed', 'base_line': current_change['base'] }) return diff_result def generate_report(device_info, diffs): report = f"设备ID: {device_info['id']} | 地点: {device_info['location']}\n" stats = {'added': 0, 'removed': 0, 'modified': 0} for d in diffs: stats[d['type']] += 1 report += f"差异统计: 新增{stats['added']}行,删除{stats['removed']}行,修改{stats['modified']}行\n\n" report += "详细差异:\n" for idx, d in enumerate(diffs, 1): if d['type'] == 'modified': report += f"{idx}. 修改行\n" report += f" 基准脚本: {d['base_line']}\n" report += f" 设备脚本: {d['device_line']}\n" elif d['type'] == 'removed': report += f"{idx}. 删除行\n" report += f" 基准脚本: {d['base_line']}\n" else: report += f"{idx}. 新增行\n" report += f" 设备脚本: {d['device_line']}\n" return report def send_alert_email(report, to_email): msg = MIMEText(report, 'plain', 'utf-8') msg['Subject'] = '[脚本异常告警] 设备脚本与基准存在差异' msg['From'] = 'scada-audit@yourcompany.com' msg['To'] = to_email smtp_server = 'smtp.yourcompany.com' smtp_port = 25 try: server = smtplib.SMTP(smtp_server, smtp_port) server.sendmail(msg['From'], msg['To'].split(','), msg.as_string()) server.quit() except Exception as e: print(f"邮件发送失败: {str(e)}")
内容的提问来源于stack exchange,提问作者CKemp
相关产品推荐
相关产品推荐

