阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

细述使用 Python 获取 Linux 系统信息

259次阅读
没有评论

共计 12166 个字符,预计需要花费 31 分钟才能阅读完成。

在本文中,我们将会探索使用 Python 编程语言工具来检索 Linux 系统各种信息。

哪个 Python 版本?

当我提及 Python,所指的就是 CPython 2(准确的是 2.7). 我会显式提醒那些相同的代码在 CPython 3 (3.3) 上是不工作的,以及提供一份解释不同之处的备选代码。请确保你已经安装了 CPython, 在终端上输入 python 或者 python3 回车,然后你在终端上应该能看到 python 的提示符 (prompt)。

请注意,所有的程序在它们第一行都是 #!/usr/bin/env/python,也就是说,我们想要 Python 的解释器来执行这些脚本。因此,如果你想你的脚本具有执行性,请使用 chmod +x your-script.py,那么你就可以使用./your-script.py 来执行它了(在本文中你将会看到这种方式)

探索 platform 模块

platform 模块在标准库中,它有很多运行我们获得众多系统信息的函数。让我们运行 Python 解释器来探索它们中的一些函数,那就从 platform.uname() 函数开始吧:

>>> import platform
>>> platform.uname()
('Linux', 'Fedora.echorand', '3.7.4-204.fc18.x86_64', '#1 SMP Wed Jan 23 16:44:29 UTC 2013', 'x86_64')

如果你已知道 linux 上的 uname 命令,那么你就会认出来这个函数就是这个命令的一个接口。在 Python 2 上,它会返回一个包含系统类型 (或者内核版本),主机名,版本,发布版本,机器的硬件以及处理器信息元组 (tuple)。你可以使用下标访问个别属性,像这样:

>>> platform.uname()[0]
'Linux'

在 Python 3 上,这个函数返回的是一个命名元组:

>>> platform.uname()
uname_result(system='Linux', node='fedora.echorand',
release='3.7.4-204.fc18.x86_64', version='#1 SMP Wed Jan 23 16:44:29
UTC 2013', machine='x86_64', processor='x86_64')

因为返回结果是一个命名元组,这就可以简单地通过名字来指定特定的属性,而不是必须记住下标,像这样:

>>> platform.uname().system
'Linux'

platform 模块还有一些上面属性的直接接口,像这样:

>>> platform.system()
'Linux'
>>> platform.release()
'3.7.4-204.fc18.x86_64'

linux_distribution() 函数返回的有关你所在的 linux 发布版本的详细信息。例如,在 Fedora 18 系统上,这个命令会返回如下信息:

>>> platform.linux_distribution()
('Fedora', '18', 'Spherical Cow')

这个返回结果中包含了版本发布名,版本以及代号元组。特定的 Python 版本支持的发布版本上可以通过_supported_dists 显示的值获得。

>>> platform._supported_dists
('SuSE', 'Debian', 'fedora', 'redhat', 'CentOS', 'mandrake',
'mandriva', 'rocks', 'slackware', 'yellowdog', 'Gentoo',
'UnitedLinux', 'turbolinux')

如果你的 linux 发布版本不在其中(或者其中之一的衍生发行版)。那么你很可能调用了上面这个函数而看不到任何有用的信息。

platform 模块的最后一个函数,我们将会看看 architecture() 函数。当你无参的调用这个函数,它会返回包含架构位数以及 python 可执行的格式的元组,像这样:

>>> platform.architecture()
('64bit', 'ELF')

在 32 位的系统上,你将会看到:

>>> platform.architecture()
('32bit', 'ELF')

如果你指定了系统上其他任何可执行的,你都将会获得相似的结果,如同这样:

>>> platform.architecture(executable='/usr/bin/ls')
('64bit', 'ELF')

鼓励探索 platform 模块的除了这些的其它函数,找出你现在运行的 Python 版本。如果你想知道这个模块是如何获取这些信息的,你可以深入查看 PYthon 源码目录下的 Lib/platform.py 文件。

os 和 sys 模块也可以获得一些系统属性,例如原生的字节序。接下来,我们超越 Python 标准库模块,去探索一些在 linux 系统通过 proc 和 sysfs 文件系统使之访问信息成为可能。注意的是通过文件系统来访问信息将会在不同的硬件架构有所不同。所以在读本文或是写脚本时要时刻记住可以试图从这些文件获取信息。

CPU 信息

/proc/cpuinfo 文件包含了你的系统处理器单元的信息。例如,这里就是 python 版的 linux 命令 cat /proc/cpuinfo 所做的事:

#! /usr/bin/env python
""" print out the /proc/cpuinfo
    file
"""

from __future__ import print_function
with open('/proc/cpuinfo') as f:
    for line in f:
        print(line.rstrip('\n'))

当你使用 Python 2 或者 Python 3 执行这个程序时,你会在屏幕上看到所有 /proc/cpuinfo 的内容(在上面的程序里,rstrip() 方法用来删除每行末尾的换行符)

在下面的代码里列举了使用 startwith() 字符串方法来显示你的处理器单元的模式。

#! /usr/bin/env python
""" Print the model of your
    processing units
"""

from __future__ import print_function
with open('/proc/cpuinfo') as f:
    for line in f:
        # Ignore the blank line separating the information between
        # details about two processing units
        if line.strip():

            if line.rstrip('\n').startswith('model name'):
                model_name = line.rstrip('\n').split(':')[1]
                print(model_name)

当你运行这个程序后,你应该会看到你的每个处理器单元的模式名。例如,这里就是在我电脑上所看到的。

Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz

迄今为止,我们已有两种方式来找出我们所使用的系统的架构。从技术上讲是正确的,两个方 式实际上报告了你系统运行的内核架构,所以,如果你的电脑是 64 位的,但是运行的是 32 位的内核,然后上面的方法还是将会显示为 32 位的架构。你可以通过从 /proc/cpuinfo 所列举的标志中查找 lm 标志,来找到你的电 脑的真实的架构。lm 标志代表了长模式,只有 64 位架构的才会显示它。下面的程序将会指导你怎样做:

#! /usr/bin/env python
"""find the real bit architecture"""
from __future__ import print_function
with open('/proc/cpuinfo') as f:
    for line in f:
        # Ignore the blank line separating the information between
        # details about two processing units
        if line.strip():
            if line.rstrip('\n').startswith('flags') \
                    or line.rstrip('\n').startswith('Features'):
                if 'lm' in line.rstrip('\n').split():
                    print('64-bit')
                else:
                    print('32-bit')

如我们所看到那样,读取 /proc/cpuinfo 文件以及使用简单文本处理技术就可以获得我们要查找的数据是可能的。为了给其他程序更好的使用这些数据,一个更好的主意就是使 /proc/cpuinfo 的内容成为标准的数据结构,譬如字典 (dictionary)。这个注意很简单:如果你查看这个文件的内容,你就会发现对于每个处理器单元,都有好些键值对 (在先前的例子中,我们打印了每个处理器的模型名,即模型名就是关键字)。不同的处理器单元的信息可以使用空白行隔开。构造一个字典数据结构包含每个处理器单元的关键字是很简单的。对于每个关键字,对于处理器单元的值都在 /proc/cpuinfo 文件中。下面的代码将会指导你怎么做。

#!/usr/bin/env/ python
"""/proc/cpuinfo as a Python dict"""
from __future__ import print_function
from collections import OrderedDict
import pprint
def cpuinfo():
    ''' Return the information in /proc/cpuinfo
    as a dictionary in the following format:
    cpu_info['proc0']={...}
    cpu_info['proc1']={...}
    '''
    cpuinfo=OrderedDict()
    procinfo=OrderedDict()
    nprocs = 0
    with open('/proc/cpuinfo') as f:
        for line in f:
            if not line.strip():
                # end of one processor
                cpuinfo['proc%s' % nprocs] = procinfo
                nprocs=nprocs+1
                # Reset
                procinfo=OrderedDict()
            else:
                if len(line.split(':')) == 2:
                    procinfo[line.split(':')[0].strip()] = line.split(':')[1].strip()
                else:
                    procinfo[line.split(':')[0].strip()] = ''
    return cpuinfo
if __name__=='__main__':
    cpuinfo = cpuinfo()
    for processor in cpuinfo.keys():
        print(cpuinfo[processor]['model name'])

这段代码中使用了 OrderedDict(有序字典) 而不是常规的字典,能够使用键值有序的存储在文件里。所以,第一个处理器单元的数据之后就是第二个处理器单元的数据,以此类推。你可以使用过滤器来过滤你所查找的信息(如同在 if __name__ ==‘__main__’块中演示的那样)。上面的程序每次执行后都会打印每个处理器单元的模型名(如通过 cpuinfo[processor][‘model name’] 语句表明的那样)

Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
内存信息

和 /proc/cpuinfo 相似,文件 /proc/meminfo 包含了你电脑的主存的信息。下面的这个程序创建了一个使用这个文件的内容填充的字典。

#!/usr/bin/env python
from __future__ import print_function
from collections import OrderedDict
def meminfo():
    ''' Return the information in /proc/meminfo
    as a dictionary '''
    meminfo=OrderedDict()
    with open('/proc/meminfo') as f:
        for line in f:
            meminfo[line.split(':')[0]] = line.split(':')[1].strip()
    return meminfo
if __name__=='__main__':
    #print(meminfo())
    meminfo = meminfo()
    print('Total memory: {0}'.format(meminfo['MemTotal']))
    print('free memory: {0}'.format(meminfo['MemFree']))

像先前的,通过它的关键字,你可以访问任何你查询的指定信息 (在 if __name__==__main__块中有所表示)。当你执行这个程序,你该会看到像下面类似的输出:

Total memory: 7897012 kB
Free memory: 249508 kB
网络统计信息

接下来,我们会探索我们电脑系统的网络设备。我们将会获得系统的网络接口,以及当系统重启之后通过它们数据发送和接受数据的信息。/proc/net/dev 文件让这些信息可用。如果你检查了这个文件的内容,你就会注意到头一两行包含了头信息等等,这个文件第一列是网络接口名,第二和第三列显示了接收和发送的字节数信息(例如总发送字节数,包数,错误等等)。这里我们所感兴趣的就是他哦难过不同的网络设备提取出总发送数据和接收数据。下面的代码展示了怎么从 /proc/net/dev 文件中提取出这些信息。

#!/usr/bin/env python
from __future__ import print_function
from collections import namedtuple
def netdevs():
    '''RX and TX bytes for each of the network devices'''
    with open('/proc/net/dev') as f:
        net_dump = f.readlines()
    device_data={}
    data = namedtuple('data',['rx','tx'])
    for line in net_dump[2:]:
        line = line.split(':')
        if line[0].strip() != 'lo':
            device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
                                                float(line[1].split()[8])/(1024.0*1024.0))
    return device_data
if __name__=='__main__':
    netdevs = netdevs()
    for dev in netdevs.keys():
        print('{0}: {1} MiB {2} MiB'.format(dev, netdevs[dev].rx, netdevs[dev].tx)) 

当你运行上面的程序,下面这个输出就会显示从你最近重启之后网络设备总接收和发送的数据,单位为兆。

em1: 0.0 MiB 0.0 MiB
wlan0: 2651.40951061 MiB 183.173976898 MiB

你可以使用持久的数据存储机制来连接,来写出自己的数据使用监控程序。

进程信息

/proc 目录包含了所有正运行的进程目录。这些目录的名字和进程的标识符是一样的。所以,如果你遍历 /proc 目录下那些使用数字作为它们的名字的目录,你就会获得所有现在正在运行的进程列表。在下面的代码中 process_list() 函数返回所有现在正在运行的进程的标识符列表。当你执行这个程序后,这个列表的长度就是在系统上运行的总进程数。

#!/usr/bin/env python
"""List of all process IDs currently active"""
from __future__ import print_function
import os
def process_list():
    pids = []
    for subdir in os.listdir('/proc'):
        if subdir.isdigit():
            pids.append(subdir)
    return pids
if __name__=='__main__':
    pids = process_list()
    print('Total number of running processes:: {0}'.format(len(pids)))

上面的程序当执行后会显示和下面类似的输出:

Total number of running processes:: 229

每个进程目录包含了一些其他文件和目录,如进程命令的调用,它正使用的共享库以及其它的。

块设备

下一个程序通过读 sysfs 虚拟文件系统列出所有块设备。你系统中的块设备可以从 /sys/block 目录中找到。因此可能会有 /sys/block/sda、/sys/block/sdb 等这样的目录。为了获取所有这些设备,我们使用正则表达式对 /sys/block 目录进行扫描提取感兴趣的块设备。

#!/usr/bin/env python
"""read block device data from sysfs"""
from __future__ import print_function
import glob
import re
import os
# Add any other device pattern to read from
dev_pattern = ['sd.*','mmcblk*']
def size(device):
    nr_sectors = open(device+'/size').read().rstrip('\n')
    sect_size = open(device+'/queue/hw_sector_size').read().rstrip('\n')
    # The sect_size is in bytes, so we convert it to GiB and then send it back
    return (float(nr_sectors)*float(sect_size))/(1024.0*1024.0*1024.0)
def detect_devs():
    for device in glob.glob('/sys/block/*'):
        for pattern in dev_pattern:
            if re.compile(pattern).match(os.path.basename(device)):
                print('Device:: {0}, Size:: {1} GiB'.format(device, size(device)))
if __name__=='__main__':
    detect_devs()

如果你运行该程序,你将会看到下述类似的输出:

Device:: /sys/block/sda, Size:: 465.761741638 GiB

Device:: /sys/block/mmcblk0, Size:: 3.70703125 GiB

当我运行该程序的时候,有个 SD 内存卡插在电脑上,因此你会看到程序检测到了它。你也可以扩展该程序识别其它块设备(比如虚拟硬盘)。

建立命令行实用工具

linux 中命令行使用工具是无所不在的 [@Lesus 注:曾有人说过:linux 没有了命令行就是个渣。,它允许人么指定命令行参数来定制程序的默认行为。argparse 模块就提供了和 linux 命令行实用工具类似的接口。下面的代码展示了程序如何获得系统上的所有用户以及打印它们的登录 Shell( 使用了 pwd 标准库模块):

#!/usr/bin/env python
"""Print all the users and their login shells"""
from __future__ import print_function
import pwd
# Get the users from /etc/passwd
def getusers():
    users = pwd.getpwall()
    for user in users:
        print('{0}:{1}'.format(user.pw_name, user.pw_shell))
if __name__=='__main__':

    getusers()

当运行这个程序之后,它会打印系统上所有的用户以及他们登录 shell 名。

现在,你想要程序的用户能够选择是否想看系统用户 (像 daemon, apache)。我们扩展前面的代码,第一次使用 argparse 模块来实现这个特性,如下。

#!/usr/bin/env python
"""Utility to play around with users and passwords on a Linux system"""
from __future__ import print_function
import pwd
import argparse
import os
def read_login_defs():
    uid_min = None
    uid_max = None
    if os.path.exists('/etc/login.defs'):
        with open('/etc/login.defs') as f:
            login_data = f.readlines()
        for line in login_data:
            if line.startswith('UID_MIN'):
                uid_min = int(line.split()[1].strip())
            if line.startswith('UID_MAX'):
                uid_max = int(line.split()[1].strip())
    return uid_min, uid_max
# Get the users from /etc/passwd
def getusers(no_system=False):
    uid_min, uid_max = read_login_defs()
    if uid_min is None:
        uid_min = 1000
    if uid_max is None:
        uid_max = 60000
    users = pwd.getpwall()
    for user in users:
        if no_system:
            if user.pw_uid >= uid_min and user.pw_uid 

使用 --help 选项执行上面的程序,你会看到友好的帮助信息:可选项以及它们的作用。

$ ./getusers.py --help
usage: getusers.py [-h] [--no-system]
User/Password Utility
optional arguments:
  -h, --help   show this help message and exit
  --no-system  Specify to omit system users

上面程序使用的一个例子,如下所示:

$ ./getusers.py --no-system
gene:/bin/bash

当你传入一个非法的参数,这个程序就会发牢骚 (报错)

$ ./getusers.py --param
usage: getusers.py [-h] [--no-system]
getusers.py: error: unrecognized arguments: --param

在上面的程序中,我们简单的理解了如何使用 argparse 模块。parser = argparse.ArgumentParser(description="User/Password Utility") 语句创建了一个带说明程序是做什么的可选描述的 ArgumentParser 对象,

然后, 我们添加参数。我们想要程序能够识别接下来这条语句 add_argument()。parser.add_argument('--no-system', action='store_true', dest='no_system', default = False, help='Specify toomit system users')。第一个方法的参数是当系统调用这个程序,程序使用着将要提供这个参数的名称,接下来的参数 acton=store_true 表明它是一个布尔选择。那就是说, 它真或假影响程序的某些行为。dest 为可定制化参数,它的值可以提供给程序使用。假如这个值用户不提供,这个值默认 false。最后的参数程序显示的帮助信息。最后,参数被解析通过 args=parser.parse_args() 方法。一旦解析方法被做, 用户选项的值能够被抓取到通过相应的语法参数 option_dest,当你配置参数的时候,option_dest 是一个你指定的目的变量。getusers(args.no_system) 这条语句使用用户提供参数的值将会回调 getusers() 方法。

下面的程序展示了如何指定非布尔类型的选项。该程序是对第 6 个程序的重写,附加了一个选项用于指定你感兴趣的网络设备。

#!/usr/bin/env python
from __future__ import print_function
from collections import namedtuple
import argparse
def netdevs(iface=None):
    '''RX and TX bytes for each of the network devices'''
    with open('/proc/net/dev') as f:
        net_dump = f.readlines()
    device_data={}
    data = namedtuple('data',['rx','tx'])
    for line in net_dump[2:]:
        line = line.split(':')
        if not iface:
            if line[0].strip() != 'lo':
                device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
                                                    float(line[1].split()[8])/(1024.0*1024.0))
        else:
            if line[0].strip() == iface:
                device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
                                                    float(line[1].split()[8])/(1024.0*1024.0))   
    return device_data
if __name__=='__main__':
    parser = argparse.ArgumentParser(description='Network Interface Usage Monitor')
    parser.add_argument('-i','--interface', dest='iface',
                        help='Network interface')
    args = parser.parse_args()
    netdevs = netdevs(iface = args.iface)
    for dev in netdevs.keys():
        print('{0}: {1} MiB {2} MiB'.format(dev, netdevs[dev].rx, netdevs[dev].tx))

当你不带任何参数执行程序的时候,程序的行为与之前的版本完全一致。然后,你也可以指定感兴趣的网络设备。例如:

$ ./net_devs_2.py
em1: 0.0 MiB 0.0 MiB
wlan0: 146.099492073 MiB 12.9737148285 MiB
virbr1: 0.0 MiB 0.0 MiB
virbr1-nic: 0.0 MiB 0.0 MiB
$ ./net_devs_2.py  --help
usage: net_devs_2.py [-h] [-i IFACE]
Network Interface Usage Monitor
optional arguments:
  -h, --help            show this help message and exit
  -i IFACE, --interface IFACE
                        Network interface
$ ./net_devs_2.py  -i wlan0
wlan0: 146.100307465 MiB 12.9777050018 MiB
脚本的系统范围可用性

在本文的帮助下,你可能已经可以写一个或多个有用的脚本,就像其它 linux 命令一样,你想要每天都使用它们。最简单的方式是将脚本设置为可执行的,然后为脚本设置一个 BASH 别名。你也可以移除.py 扩展名,然后将脚本放在诸如 /usr/local/sbin 这样的标准位置。

其它有用的标准库模组

除了本文中已经提到的标准库模组,还有很多其它有用的标准模组:subprocess、ConfigParser、readline 和 curses。

接下来做什么?

在这个阶段,依靠你自己使用 Python 的经验,探索 Linux 内部,你可以参考下面的任一方式。如果你曾经需要写很多 shell 脚本 / 命令流水线来

探索 Linux 内部,那么试一下 Python。如果你想要一个更简单的方式来编写执行很多任务的实用程序脚本,那么试一下 Python。最后,如果你已经使用 Python 在 Linux 上别写其它目的的程序,那么试一下用 Python 探索 Linux 内部。

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-12-14发表,共计12166字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7998340
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
Prometheus:监控系统的部署与指标收集

Prometheus:监控系统的部署与指标收集

Prometheus:监控系统的部署与指标收集 在云原生体系中,Prometheus 已成为最主流的监控与报警...
240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

  240 元左右!五盘位 NAS 主机,7 代 U 硬解 4K 稳如狗,拓展性碾压同价位 在 NA...
免费领取huggingface的2核16G云服务器,超简单教程

免费领取huggingface的2核16G云服务器,超简单教程

免费领取 huggingface 的 2 核 16G 云服务器,超简单教程 前言 HuggingFace.co...
恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击 PHP-FPM(FastCGl Process M...
颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

  颠覆 AI 开发效率!开源工具一站式管控 30+ 大模型 ApiKey,秘钥付费 + 负载均衡全...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...
星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的 NAS 中! 大家对「数据安全感」的需求越来越高 ...
星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛 NAS-11:咪咕视频订阅部署全攻略 前言 在家庭影音系统里,NAS 不仅是存储中心,更是内容...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
还在找免费服务器?无广告免费主机,新手也能轻松上手!

还在找免费服务器?无广告免费主机,新手也能轻松上手!

还在找免费服务器?无广告免费主机,新手也能轻松上手! 前言 对于个人开发者、建站新手或是想搭建测试站点的从业者...