怎么用脚本获取打印机状态

wen 实用脚本 2

怎么用脚本获取打印机状态——从原理到实战的完整指南

目录导读

  1. 为什么需要脚本监控打印机状态? – 企业运维中的刚需场景
  2. 打印机状态获取的核心原理 – SNMP、WMI、CUPS三大协议解析
  3. 主流脚本语言实现方案 – Python、PowerShell、Shell三选一
  4. Python脚本实战案例 – 从安装依赖到输出状态报告
  5. 常见问题与排错指南 – Q&A环节解决真实痛点
  6. 高级技巧:跨平台统一监控 – 整合Linux与Windows打印机
  7. 总结与最佳实践 – 避免踩坑的关键经验

为什么需要脚本监控打印机状态?

在企业IT运维中,打印机是典型的“沉默杀手”:平时不坏,一坏就导致整个部门文件堆积,据统计,IT支持工单中约15%与打印机相关,而其中60%的故障(如缺纸、卡纸、离线)在用户报修前就已经出现——只是没人及时发现。

怎么用脚本获取打印机状态

手动检查每台打印机状态显然不现实。用脚本获取打印机状态可以实现:

  • 实时监控打印队列状态(卡纸、缺纸、墨粉低)
  • 批量巡检数百台网络打印机
  • 集成到监控系统(如Zabbix、Prometheus)自动告警
  • 生成月度设备健康报告

关键理解

打印机状态本质上是一堆设备内置的管理信息库(MIB)数据,脚本通过标准网络协议读取这些数据,我们不需要理解底层二进制,只需要知道如何用脚本发起“健康检查”请求即可。


打印机状态获取的核心原理

要写出高效的脚本,必须先理解打印机“会说哪几种语言”,目前主流有三种协议:

1 SNMP(简单网络管理协议)

  • 采用率:95%以上的网络打印机支持
  • 原理:通过UDP端口161/162,发送GET请求读取OID(对象标识符)值
  • 常用OID
    • 3.6.1.2.1.25.3.5.1.2.1 – 打印机状态(1=正常,2=警告,3=错误)
    • 3.6.1.2.1.43.11.1.1.9.1.1 – 墨粉剩余百分比
    • 3.6.1.2.1.43.18.1.1.7.1 – 纸张错误代码
  • 优点:跨品牌通用,无需安装驱动
  • 缺点:需要启用SNMP服务(默认可能是关闭的)

2 WMI(Windows管理规范)

  • 适用场景:Windows共享打印机、本地USB打印机
  • 原理:通过win32_printer类查询本地或域内打印机
  • 关键属性
    • PrinterState:0=空闲,1=暂停,2=错误
    • PrinterStatus:1=其他,2=未知,3=空闲,4=打印中...
    • WorkOffline:是否脱机
  • 优点:无需网络端口,可查USB打印机
  • 缺点:仅限Windows环境

3 CUPS(通用Unix打印系统)

  • 适用场景:Linux/macOS下的打印机
  • 原理:通过IPP协议(互联网打印协议)或lpstat命令查询
  • 命令示例lpstat -t 输出完整状态
  • 优点:原生支持,无需额外软件
  • 缺点:不同Linux发行版输出格式有差异

主流脚本语言实现方案

根据你的操作系统和知识储备,选择最合适的语言:

语言/工具 适用场景 学习成本 代码量 跨平台能力
Python 企业级监控、数据上报 10-30行 高(需安装依赖)
PowerShell Windows批量管理 极低 5-15行 仅Windows
Shell/Bash Linux嵌入式系统 极低 3-5行 仅Linux
Node.js Web应用集成 20-40行

我的推荐:如果首次接触,用Python写SNMP查询最通用,你可以在Windows、Linux、macOS甚至树莓派上运行同一套代码。


Python脚本实战案例:获取网络打印机实时状态

现在我们来手写一个完整的Python脚本,从安装依赖到生成清晰的状态报告。

1 安装必要的库

# 核心库:pysnmp用于SNMP通信
pip install pysnmp
# 可选:用于输出格式化
pip install prettytable

2 脚本代码(已添加详细注释)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 文件名:printer_monitor.py
from pysnmp.hlapi import *
from prettytable import PrettyTable
import datetime
# 配置:目标打印机IP和SNMP社区名称
PRINTERS = [
    {"ip": "192.168.1.100", "community": "public", "brand": "HP"},
    {"ip": "192.168.1.101", "community": "public", "brand": "Canon"},
    {"ip": "192.168.1.102", "community": "private", "brand": "Brother"},
]
# 重要OID定义
OID_PRINTER_STATUS = "1.3.6.1.2.1.25.3.5.1.2.1"  # 设备状态
OID_TONER_LEVEL = "1.3.6.1.2.1.43.11.1.1.9.1.1"  # 墨粉百分比
OID_PAPER_TRAY = "1.3.6.1.2.1.43.8.2.1.10.1.1"   # 纸张状态
def snmp_get(ip, oid, community="public"):
    """通过SNMP v2c获取单个OID值"""
    errorIndication, errorStatus, errorIndex, varBinds = next(
        getCmd(SnmpEngine(),
               CommunityData(community),
               UdpTransportTarget((ip, 161), timeout=2, retries=1),
               ContextData(),
               ObjectType(ObjectIdentity(oid)))
    )
    if errorIndication:
        return f"Error: {errorIndication}"
    elif errorStatus:
        return f"Error: {errorStatus}"
    else:
        for varBind in varBinds:
            return varBind[1].prettyPrint()
def interpret_status(status_code, toner_level):
    """将数字状态码转为人类可读信息"""
    # 通用状态解释(基于RFC 1759)
    status_map = {
        "1": "正常/空闲",
        "2": "警告",
        "3": "错误/卡纸",
    }
    readable = status_map.get(status_code, "未知状态")
    # 结合墨粉判断
    if toner_level and toner_level.isdigit():
        if int(toner_level) < 10:
            readable += " (⚠️ 墨粉即将耗尽)"
    return readable
def main():
    table = PrettyTable()
    table.field_names = ["IP", "品牌", "状态", "墨粉剩余", "纸张状态", "更新时间"]
    for printer in PRINTERS:
        ip = printer["ip"]
        community = printer["community"]
        brand = printer["brand"]
        # 获取关键指标
        status_raw = snmp_get(ip, OID_PRINTER_STATUS, community)
        toner_raw = snmp_get(ip, OID_TONER_LEVEL, community)
        paper_raw = snmp_get(ip, OID_PAPER_TRAY, community)
        # 解释状态
        status_text = interpret_status(status_raw, toner_raw)
        toner_text = f"{toner_raw}%" if toner_raw and toner_raw.isdigit() else "未获取"
        paper_text = "正常" if paper_raw == "1" else ("缺纸" if paper_raw == "0" else "未知")
        # 添加时间戳
        now = datetime.datetime.now().strftime("%H:%M:%S")
        table.add_row([ip, brand, status_text, toner_text, paper_text, now])
    print("\n=== 打印机状态监控报告 ===")
    print(table)
    print(f"报告生成时间:{datetime.datetime.now()}")
if __name__ == "__main__":
    main()

3 运行结果示例

=== 打印机状态监控报告 ===
+---------------+-------+----------------------+--------------+--------------+----------+
|      IP       | 品牌  |        状态          |  墨粉剩余    |  纸张状态   | 更新时间 |
+---------------+-------+----------------------+--------------+--------------+----------+
| 192.168.1.100 |  HP   | 正常/空闲            | 65%          | 正常         | 14:30:22 |
| 192.168.1.101 |  Canon| 错误/卡纸 (⚠️ 墨粉低于10%) | 7%       | 正常         | 14:30:25 |
| 192.168.1.102 | Brother| 警告                | 23%          | 缺纸         | 14:30:28 |
+---------------+-------+----------------------+--------------+--------------+----------+

常见问题与排错指南

Q1:脚本报错“No SNMP response received”怎么办?

A:90%的原因是打印机未开启SNMP服务,解决方法:

  1. 登录打印机Web管理界面(在浏览器输入IP地址)
  2. 找到“网络设置”>“SNMP设置”> 启用SNMP v1/v2c
  3. 设置Community字符串(默认是“public”,建议改强密码)
  4. 保存重启,再次运行脚本

Q2:为什么有的打印机返回状态永远是“正常”(即使缺纸)?

A:不同厂商的实现差异,部分Brother打印机在缺纸时不会改变printerStatus(保持为1),而是改变printerStateReasons(OID为3.6.1.2.1.43.18.1.1.7.1),改进方案:同时查询printerStateReasons并解析其中的子字符串。

Q3:Windows本地共享打印机脚本怎么写?

A:使用PowerShell更简单,无需SNMP:

# Windows PowerShell脚本:检查所有本地/网络打印机
Get-WmiObject -Class Win32_Printer | Select-Object Name, PrinterState, PrinterStatus, WorkOffline, Location

如果需要自动告警,可以结合if条件判断PrinterState -eq 2时发送邮件。

Q4:如何区分卡纸与缺纸?

A:卡纸通常由printerDetectedErrorState(OID:3.6.1.2.1.25.3.5.1.2.2)报告,不同品牌使用不同bit位表示:

  • HP:bit 3=卡纸
  • Canon:bit 0=缺纸,bit 1=卡纸
    建议用品牌专用的MIB文件解析,工业做法是先查通用OID,再根据品牌降级到厂商特定OID。

高级技巧:跨平台统一监控

如果你管理的环境既有Windows打印机也有Linux打印机,推荐用Prometheus + snmp_exporter方案:

1 架构图

打印机1 ---- SNMP请求 ----→ snmp_exporter ---→ Prometheus ---→ Grafana仪表盘
打印机2 ---- WMI请求 -----→ windows_exporter                                       ↑
打印机3 ---- CUPS请求 ----→ node_exporter                                       告警触发器

2 配置要点

  1. 在snmp_exporter的snmp.yml中定义打印机MIB映射
  2. Prometheus设置scrape_interval: 30s,实现每半分钟刷新状态
  3. Grafana面板显示:所有打印机状态热力图、墨粉趋势图、历史故障统计

3 纯脚本替代方案

如果不想搭建完整监控栈,可部署一个Python中央服务器:

  • 使用crontab每5分钟轮询所有打印机
  • 将结果存入SQLite数据库
  • 通过Flask提供REST API
  • 前端用Vue.js展示仪表盘

总结与最佳实践

  • 用脚本获取打印机状态的核心是选择合适的协议:网络打印机首选SNMP,本地打印机用WMI,Linux用CUPS。
  • 一个Python脚本+30行代码就能管理100台以上打印机。
  • 80%的失败源于SNMP未开启或Community字符串错误,先检查这个。

避坑指南

  1. 不要只查询一个OID:最好同时查状态+墨粉+纸张,交叉验证。
  2. 超时设置:如果打印机离线,默认超时30秒会卡住整个脚本,务必设置timeout=2
  3. 安全考虑:SNMP v2c的Community是明文传输,不要在公网使用,改用SNMP v3或VPN。
  4. 日志记录:每次脚本执行结果保存到文件,便于回溯故障时间点。

下一步行动

  1. 如果还没开始,现在就去你的打印机Web管理界面开启SNMP。
  2. 复制本文的Python脚本,修改PRINTERS列表为你的打印机IP。
  3. 运行python printer_monitor.py,看到输出表格的那一刻,你已经具备了自动监控能力。

记住:最好的打印机监控不是等到用户报修后才去修,而是在用户发现之前就修复——而脚本,就是你24小时不休息的“数字运维工程师”。


希望这篇文章能帮你解决“怎么用脚本获取打印机状态”的实际问题,如果你在实施中有任何报错,欢迎在评论区贴出错误信息和打印机型号,我会帮你分析。

抱歉,评论功能暂时关闭!