psutil 实现主机信息查询系统的源码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import psutil

# 获取当前系统的登录用户数
login_users = len(psutil.users())


def bytes2human(n):
    """
    字节转换工具
    http://code.activestate.com/recipes/578019
    #bytes2human(10000)
    '9.8K'
    #>>> bytes2human(100001221)
    '95.4M'
    :param n:
    :return:
    """

    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
    prefix = {}
    for i, s in enumerate(symbols):
       # 0  K
       # 1  M
        prefix[s] = 1 << (i + 1) * 10
       # {"K": 1024,
       #  "M": 1048576,
       #  "Y": ... }
    for s in reversed(symbols):
        if n >= prefix[s]:
            value = float(n) / prefix[s]
            return '{:.1f}{}'.format(value, s)
    return "%sB" % n


# 获取 CPU 信息
def get_cpu():
    # cpu 实例数
    cpu_count = len(psutil.Process().cpu_affinity())

    # 每颗 cpu 的物理核心数
    cpu_py_count = psutil.cpu_count(logical=False)

    # cpu 信息
    cpu_info = psutil.cpu_times_percent(interval=0.1)

    return cpu_count, cpu_py_count, cpu_info


# 打印 CPU 信息
def display_cpu():
    cpu_temple = """
************************** CPU 信息 **************************
CPU 颗数: {cpu_count}       CPU 总使用率: {cpu_time}%
物理核心数: {cpu_py_count}    IO 等待 CPU 空闲率: {io_wait_time}%  
"""

    cpu_count, cpu_py_count, cpu_info = get_cpu()
    import sys
    plf = sys.platform
    print(cpu_temple.format(
        cpu_count=cpu_count,
        cpu_py_count=cpu_py_count,
        cpu_time=cpu_info.user + cpu_info.system,

        # iowait Mac 系统不支持,在 mac 系统下需要把 io_wait_time 赋值为空
        # io_wait_time=""

        io_wait_time=cpu_info.iowait if plf == 'linux' else ''
    ))


def get_mem():
    # 内存信息
    return psutil.virtual_memory()

# mem_info = psutil.virtual_memory()

def display_meme():
    mem_info = get_mem()
    print("*" * 16, "Disk 信息", "*" * 16)
    fileds = ['total', 'free', 'used']
    for name in mem_info._fields:
        # if name != 'percent':
        if name in fileds:
            value = getattr(mem_info, name)
            value = bytes2human(value)
            print("{:<10s} : {}".format(name.capitalize(), value))


# 获取 DISK 信息
def get_disk_part():
    return psutil.disk_partitions(all=False)


def display_disk():
    disk_fields = ("Device", "Total", "Used", "Free", "Use ", "Type", "Mount")
    temple_title = '{:<23s} {:<8} {:<8} {:<8} {:<3s}% {:>8s}  {:<s}'
    temple = '{:<23s} {:<8s} {:<8s} {:<8s} {:3.1f}% {:>8s}  {:<s}'

    disk_part = get_disk_part()
    disk_detail = temple_title.format(*disk_fields)

    print("*" * 35, "Disk 信息", "*" * 35)
    print(disk_detail)
    for part in disk_part:
        usage = psutil.disk_usage(part.mountpoint)  # 获取磁盘使用率
        """
        注意: UNIX通常为root用户保留总磁盘空间的5%。
             UNIX上的 Total 和 Used 字段是指总体使用和已用空间,
             而 free 表示用户可用空间, 百分比表示用户使用率(请参阅 源代码)。
             这就是为什么百分比值可能比你期望的要高5%。
        """
        print(temple.format(
            part.device,
            bytes2human(usage.total),
            bytes2human(usage.used),
            bytes2human(usage.free),
            usage.percent,
            part.fstype,
            part.mountpoint))


# 获取网络信息
def get_net_info():
    """获取到网络的基础信息和地址"""
    # 导入 socket 模块,用于识别 ipv4 地址信息
    import socket

    # 定义一个空字典,用于存放获取到的数据
    net_info_dic = {}

    # 获取网卡的状态信息,返回的是个字典
    if_stats_dic = psutil.net_if_stats()

    # 获取网卡的地址信息,返回的是个字典
    if_addrs_dic = psutil.net_if_addrs()

    # 获取网卡的 io 信息,返回的是个字典
    io_counters_obj = psutil.net_io_counters()

    for nic, addrs in if_addrs_dic.items():
        if not nic.startswith('lo'):
            # 首先得到网卡的状态,并把数据填充到字典中
            net_info_dic[nic] = {'nic_stat': if_stats_dic[nic].isup}
            # 示例:net_info_dic = {'eth0': {'nic_stat': True}

            for addr in addrs:  # 循环每块网卡地址的每类信息

                if addr.family == socket.AF_INET:  # 我们只需要 ipv4 的信息
                    # 更新相关信息到每个网卡的字典中
                    net_info_dic[nic].update({
                        'ip': addr.address,
                        'netmask': addr.netmask
                     })

    # 假如某个网卡不正常,它的 ip 地址信息可能不存在,
    # 这样的话,这个网卡的字典信息中将会缺失 ip 和 netmask 的键;
    # 为了后期取数方便,所以在此处进行处理,
    # 把这两个键添加到字典中,并且赋值为空字符串

    for item in net_info_dic.values():
        item.setdefault('ip', '')
        item.setdefault('netmask', '')


    # 更新网卡 io 信息到字典中
    net_info_dic['io_info'] = {
        # 发送字节数(bytes),除以 1024 得到 kb
        'bytes_sent': bytes2human(io_counters_obj.bytes_sent),
        'bytes_recv': bytes2human(io_counters_obj.bytes_recv),  # 接收字节数
        'packe_sent': io_counters_obj.packets_sent,  # 发送数据包数
        'packe_recv': io_counters_obj.packets_recv}

    return net_info_dic

def display_net():
    """
    获取到网卡格式化后的信息,并格式化打印到屏幕上
    :return:
    """
    net_info_dic = get_net_info()
    print(net_info_dic)
    temple_addr = """
网卡名: {nic}  状态: {stat}
     IP: {ip} 掩码: {net_mask}
      """
    temple_io = """
    
当前系统网络 IO 信息(统计的是所有网卡的信息)
      当前发送字节数: {bytes_sent}  当前接收字节数: {bytes_recv}
    """

    print("*" * 30, "Network 信息", "*" * 30)
    print(temple_io.format(bytes_sent=net_info_dic['io_info'].get('bytes_sent', ''),
                           bytes_recv=net_info_dic['io_info'].get('bytes_recv', '')
                          )
    )

    net_info_dic.pop('io_info')

    for nic, item in net_info_dic.items():
        print(temple_addr.format(nic=nic,
                                 stat=item['nic_stat'],
                                 ip=item.get('ip', ''),
                                 net_mask=item.get('netmask', '')
                                 )
              )


def man():
    import sys
    display_dic = {
        "1": {"title": "查看 CPU 信息", "func": display_cpu},
        "2": {"title": "查看 Memory 信息", "func": display_meme},
        "3": {"title": "查看 Disk 信息", "func": display_disk},
        "4": {"title": "查看 Network 信息", "func": display_net}
    }
    print("{}Python系统性能信息收集".format('*' * 10))  # 首先打印出菜单标题
    for k, item in display_dic.items():
        print(k, item['title'])
    while True:
        inp = input('请选择>>:')
        if inp == 'q':
            sys.exit("系统退出")
        if inp in display_dic.keys():
            # python3.6+
            print(f"{'*' * 10}Python 系统性能信息收集程序")         
            # python3.x
            print("{}Python 系统性能信息收集程序".format('*' * 10))          
            for k, item in display_dic.items():
                print(k, item['title'])
            print()
            exec_func = display_dic[inp]['func']
            exec_func()
            print()

if __name__ == "__main__":
    man()


###########################

"""
{'eth0': snetio(bytes_sent=101643418, bytes_recv=86163253, packets_sent=286285, packets_recv=326059, errin=0, errout=0, dropin=0, dropout=0),
 'lo': snetio(bytes_sent=224151, bytes_recv=224151, packets_sent=3347, packets_recv=3347, errin=0, errout=0, dropin=0, dropout=0)}
"""

"""
psutil.net_if_addrs()
将与安装在系统上的每个NIC(网络接口卡)关联的地址作为字典返回,该字典的关键字是NIC名称,值是分配给NIC的每个地址的命名元组列表。每个命名的元组包括5个字段:

系列:地址系列, AF_INET, AF_INET6 或psutil.AF_LINK,指MAC地址。
地址:主NIC地址(始终设置)。
网络掩码:网络掩码地址(可能是None)。
广播:广播地址(可能None)。
ptp:代表“点对点”; 它是点对点接口(通常是VPN)的目标地址。广播和PT是互斥的。可能是None。
"""

"""
psutil.net_if_stats()
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=1000, mtu=1500),
 'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
将安装在系统上的每个NIC(网络接口卡)的信息作为字典(其关键字是NIC名称和值)返回,其中包含以下字段的命名元组:

isup:表示NIC是否启动并运行的布尔值。  这里我们只关心 是否是启动状态
duplex:双工通信类型; 它可以是NIC_DUPLEX_FULL,NIC_DUPLEX_HALF或者 NIC_DUPLEX_UNKNOWN。
speed:以兆位(MB)表示的NIC速度,如果无法确定(例如'localhost'),则将其设置为0。
mtu:NIC的最大传输单位,以字节表示。
"""

"""
我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,
它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信
python 的 socket 包中有 网卡接口的类型,利用这个可以实现一个映射关系

socket.AF_INET = <AddressFamily.AF_INET: 2>
psutil.AF_LINK = <AddressFamily.AF_LINK: 17>


"""
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容