技术标签: python
大家好,小编为大家解答python自动化运维需要掌握的技能的问题。很多人还不知道python自动化运维快速入门 pdf,现在让我们一起来看看吧!
Source code download: 本文相关源码
在介绍 telnetlib 中各个 read 函数的意义前,首先了解 telnetlib 的工作原理。
telnetlib 首先通过 socket 连接从网络接收数据,把数据存储到自己的 raw queue 中,然后对其进行(telnet 协议相关的)处理(cook)python用turtle画三角形。处理结果存放在 cooked queue 中供应用程序取用。整个过程如下图所示:
read_until(expected, timeout=None)
读取直到遇到给定的预期字节字符串,或者直到超时时间。
read_all( )
读取所有数据,直到EOF以字节为单位;阻塞直到连接关闭。
netmiko针对不同网络设备做了优化,可以更有效地处理SSH连接,它还支持不同的设备厂商和平台。
在使用netmiko模块时,不可避免地会使用到ConnectHandler函数,ConnectHandler函数提供定义的字典来开始创建连接。
以下是ConnectHandler函数的定义及示例
定义
def ConnectHandler(*args, **kwargs):
"""Factory function selects the proper class and creates object based on device_type."""
device_type = kwargs["device_type"]
if device_type not in platforms:
if device_type is None:
msg_str = platforms_str
else:
msg_str = telnet_platforms_str if "telnet" in device_type else platforms_str
raise ValueError(
"Unsupported 'device_type' "
"currently supported platforms are: {}".format(msg_str)
)
ConnectionClass = ssh_dispatcher(device_type)
return ConnectionClass(*args, **kwargs)
示例
def netmiko_connect(request):
"""Connect to arista1 and return connection object"""
password = os.getenv("PYNET_PASSWORD") if os.getenv("PYNET_PASSWORD") else getpass()
arista1 = {
"device_type": "arista_eos",
"host": "arista1.lasthop.io",
"username": "pyclass",
"password": password,
}
net_connect = ConnectHandler(**arista1)
def fin():
net_connect.disconnect()
request.addfinalizer(fin)
return net_connect
net_connect.send_config_from_file() # 发送从文件加载的配置命令
net_connect.save_config() # 将running#config保存到startup#config
net_connect.send_command_timing() # 沿通道发送命令,返回输出(基于时序)
net_connect.find_prompt() # 返回当前路由器提示符
net_connect.commit() # 在Juniper和IOS#XR上执行提交操作
net_connect.write_channel() # 通道的低级写入
net_connect.read_channel() # 通道的低级写入
YAML是一种直观的能够被电脑识别的的数据序列化格式,是一个专门用来写配置文件的语言,容易被人类阅读,并且容易和脚本语言交互。
# yaml键值对嵌套:即python中字典嵌套字典
usr1:
name: a
psw: 123
usr2:
name: b
psw: 456
python解析该yaml文件后为
{'usr1': {'name': 'a', 'psw': 123}, 'usr2': {'name': 'b', 'psw': 456}}
# yaml键值对中嵌套数组
usr3:
- a
- b
- c
usr4:
- b
python解析该yaml文件后为
{'usr3': ['a', 'b', 'c'], 'usr4': ['b']}
# 分段yaml文件中多个文档
---
animal1: dog
age: 2
---
animal2: cat
age: 3
import yaml
f = open(r'E:\AutomaticTest\Test_Framework\config\config.yml')
y = yaml.load(f)
print (y)
import yaml
f = '''
---
name: James
age: 20
---
name: Lily
age: 19
'''
y = yaml.load_all(f)
for data in y:
print(data)
输出结果为:
{'name': 'James', 'age': 20}
{'name': 'Lily', 'age': 19}
import yaml
aproject = {'name': 'Silenthand Olleander',
'race': 'Human',
'traits': ['ONE_HAND', 'ONE_EYE']
}
print(yaml.dump(aproject,第二个为可选参数))
输出结果为:
name: Silenthand Olleander
race: Human
traits:
- ONE_HAND
- ONE_EYE
yaml.dump接收的第二个参数一定要是一个打开的文本文件或二进制文件,yaml.dump会把生成的yaml文档写到文件里。
import yaml
obj1 = {"name": "James", "age": 20}
obj2 = ["Lily", 19]
with open(r'E:\AutomaticTest\Test_Framework\config\config.yml', 'w') as f:
yaml.dump_all([obj1, obj2], f)
两段数据参数用列表传入
输出结果为:
{age: 20, name: James}
--- [Lily, 19]
defaults: &defaults
adapter: postgres
host: localhost
development:
database: myapp_development
<<: *defaults
test:
database: myapp_test
<<: *defaults
相当于:
defaults:
adapter: postgres
host: localhost
development:
database: myapp_development
adapter: postgres
host: localhost
test:
database: myapp_test
adapter: postgres
host: localhost
& 用来建立锚点(defaults),<< 表示合并到当前数据,* 用来引用锚点。
这个类的实例用于存储配置、全局对象,并用于从文件系统或其它位置加载模板。模板在Python中广泛使用,模板简单来说就是一个其中包涵占位变量表示动态的部分的文件,模板文件在经过动态赋值后,返回给用户(可以理解为渲染)。
jinja2之所以被广泛使用是因为它具有以下优点:
作为一个模板系统,它还提供了特殊的语法,我们按照它支持的语法进行编写之后,就能使用jinja2模块进行渲染。
在jinja2中,存在三种语法:
{# This is jinja code
filenames = {
{ filenames }}
{% for file in filenames %}
...
{% endfor %}
#}
变量可以通过“过滤器”进行修改,过滤器可以理解为是jinja2里面的内置函数和字符串处理函数。
用法示例:
{
{ 'abc' | captialize }}
# Abc
{
{ 'abc' | upper }}
# ABC
{
{ 'hello world' | title }}
# Hello World
{
{ "hello world" | replace('world','daxin') | upper }}
# HELLO DAXIN
{
{ 18.18 | round | int }}
# 18
大多数应用都在初始化的时候撞见一个Environment对象,并用它加载模板。Environment支持两种加载方式:
以PackageLoader为例:
from jinja2 import PackageLoader,Environment
file_loader = PackageLoader('templates') 我们定义一个PackageLoader。 # 从templates目录中检索模板。
env = Environment(loader=PackageLoader('python_project','templates')) # 创建一个包加载器对象
template = env.get_template('bast.html') # 使用get_template()方法获得模板
template.render(name='daxin',age=18) # 渲染
PackageLoader()的两个参数为:python包的名称,以及模板目录名称。
FileSystemLoader:文件系统加载器,不需要模板文件存在某个Python包下,可以直接访问系统中的文件。
以FileSystemLoader为例的继承示例:
from jinja2 import Environment, FileSystemLoader
content = 'This is about page'
file_loader = FileSystemLoader('templates')
env = Environment(loader=file_loader)
template = env.get_template('about.html')
output = template.render(content=content)
print(output)
subprocess使用时,父进程创建子进程去执行一个外部程序,并提供了标准输入输出和管道(pipe)的实现方法,同时获取它们的返回码。
subprocess.Popen类用于在一个新进程中执行一个子程序,程序运行subprocess.Popen()类,父进程创建子进程后,不会等待子进程执行完成。如果需要等待子进程,需要加入wait()方法阻塞父进程。
subprocess.Popen(args[, bufsize, stdin, stdout, stderr, …]):Popen类的构造函数,返回结果为subprocess.Popen对象。
如:PopenObject为subprocess.Popen( )对象
PopenObject.communicate([input, timeout]):与进程进行交互(如发送数据到stdin、读取stdout和stderr数据),它会阻塞父进程,直到子进程完成。
input:表示将发送到子进程的字符串数据,默认为None;
timeout:超时判断,若超过timeout秒后仍未结束则抛出TimeoutExpired异常;
communicate返回值:一个元组(stdout_data, stderr_data)
PopenObject.poll() :用于检查命令是否已经执行结束,若结束返回状态码;若未结束返回None
PopenObject.wait([timeout, endtime]):等待子进程结束,并返回状态码;若超过timeout(s)进程仍未结束,则抛出异常
PopenObject.send_signal(signal):发送信号signal给子进程
PopenObject.terminate():停止子进程
PopenObject.kill():杀死子进程
subprocess.call(args[, stdout, …]):执行args命令,返回值为命令执行状态码(类似os.system);
若未指定stdout,则命令执行后的结果输出到屏幕;
若指定stdout,则命令执行后的结果输出到stdout;
若执行成功,则函数返回值为0;若执行失败,则函数返回值为1;
subprocess.check_call(args[, stdout, …]):执行args命令,返回值为命令执行状态码;
若未指定stdout,则命令执行后的结果输出到屏幕;
若指定stdout,则命令执行后的结果输出到stdout;
若执行成功,则函数返回值为0;若执行失败,抛出异常;
subprocess.check_output(args[, stderr, …]):执行args命令,返回值为命令执行的输出结果;
若执行成功,则函数返回值为命令输出结果;若执行失败,则抛出异常;
以subprocess.call()为例,用法如下:
child = subprocess.call('python --version', shell =True)
print(child)
def subprocess_Popen1():
print("***通过communicate函数分别输出PopenObject对象的输出流和错误流***")
args = [["adb", "devices"], ["adb", "devices11"]]
for arg in args:
popen_object = subprocess.Popen(arg, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
object_stdout, object_stderr = popen_object.communicate()
output = {"popen_object": popen_object,
"object_stdout": object_stdout,
"object_stderr": object_stderr}
print(output)
"""
{'popen_object': <subprocess.Popen object at 0x0000000002212400>, 'object_stdout': b'List of devices attached \r\n106D111805005938\tdevice\r\n\r\n', 'object_stderr': b''}
{'popen_object': <subprocess.Popen object at 0x0000000002577C18>, 'object_stdout': b'', 'object_stderr': b'Android Debug Bridge version 1.0.31\r\n\r\n -a .....}
"""
print("***通过stdout和stderr方法输出PopenObject对象输出流和错误流***")
p0 = subprocess.Popen(["adb", "devices"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
object_stdout = p0.stdout.read()
p0.stdout.close()
object_stderr = p0.stderr.read()
p0.stderr.close()
print(object_stdout) # 结果:b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
print(object_stderr) # 结果:b''
print("***Popen对象stdin写入功能:使用stdout和stderr输出")
args = ["python", "python1"]
for arg in args:
p4 = subprocess.Popen([arg], shell=True, stdout=subprocess.PIPE,
stdin=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
p4.stdin.write("print('hello')")
p4.stdin.close()
out = p4.stdout.read()
p4.stdout.close()
err = p4.stderr.read()
p4.stderr.close()
print("out:%s err:%s" % (out, err))
"""
***Popen对象stdin写入功能
out:hello
err:
out: err:'python1' 不是内部或外部命令,也不是可运行的程序或批处理文件。
"""
print("***Popen对象stdin写入功能:使用communicate输出")
p4 = subprocess.Popen(["python"], stdout=subprocess.PIPE,
stdin=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
p4.stdin.write("print('hello')")
output = p4.communicate()
print(output) # 结果:('hello\n', '')
print("***不含encoding参数***")
p1 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
out1 = p1.stdout.readlines()
print(out1) # 结果: [b'List of devices attached \r\n', b'106D111805005938\tdevice\r\n', b'\r\n']
print("***含encoding参数***")
p2 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE, encoding="utf-8")
out2 = p2.stdout.readlines()
print(out2) # 结果: ['List of devices attached \n', '106D111805005938\tdevice\n', '\n']
print("***Popen对象检查命令是否结束,等待进程结束")
print(p2.poll()) # 结果: None
print(p2.wait()) # 结果: 0
print(p2.poll()) # 结果: 0
print("***Popen对象communicate函数,它会阻塞父进程直至子进程完成")
p3 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
out = p3.communicate()[0]
print(out) # 结果:b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
print(p3.poll()) # 结果:0
subprocess_Popen1()
def subprocess_Popen2():
"""
1. 通过管道功能,实现adb shell ps | findstr top功能
2. 直接为args赋值为一个字符串,实现adb shell ps | findstr top功能
:return:
"""
print("***通过管道方式***")
p1 = subprocess.Popen(["adb", "shell", "ps"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["findstr", "top"], stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p2.communicate()
print(out, err) # 结果:b'shell 8508 8504 2600 1044 c004e5f8 b6f40938 S top\r\r\n' b''
print("***通过传一个字符串方式***")
p3 = subprocess.Popen("adb shell ps | findstr top", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p3.communicate()
print(out, err) # 结果:b'shell 8508 8504 2600 1044 c004e5f8 b6f40938 S top\r\r\n' b''
subprocess_Popen2()
我们创建一个”fabfile.py”文件,”fabfile.py”文件中每个函数就是一个任务,任务名即函数名,例中是”hello”。”fab”命令就是用来执行”fabfile.py”中定义的任务,它必须显式地指定任务名。你可以使用参数”-l”来列出当前”fabfile.py”文件中定义了哪些任务:
def hello():
print "Hello Fabric!"
在”fabfile.py”的目录下执行命令:
$ fab hello
任务可以带参数,比如我们将hello函数改为:
def hello(name, value):
print "Hello Fabric! %s=%s" % (name,value)
此时执行hello任务时,就要传入参数值:
$ fab hello:name=Year,value=2016
“fabric.api”包里的local()方法可以用来执行本地Shell命令,比如让我们列出本地”/home/ckr”目录下的所有文件及目录:
from fabric.api import local
def hello():
local('ls -l /home/ckr/')
local()方法有一个capture参数用来捕获标准输出,比如:
def hello():
output = local('echo Hello', capture=True)
Fabric默认执行的脚本是fabfile.py,如果要换脚本文件需要使用 -f 指定。比如我们将hello任务放到.py中就要执行:
fab -f .py hello
Fabric真正强大之处不是在执行本地命令,而是可以方便的执行远程机器上的Shell命令。它通过SSH实现,你需要的是在脚本中配置远程机器地址及登录信息:
将登陆密码写到脚本文件里是不安全的,推荐的方法是设置SSH KEY自动登陆。
登陆本地机器生成KEY:
$ ssh-keygen -t rsa -f ~/.ssh/id_rsa_fabric
生成密钥对之后将公钥添加到远程服务器的~/.ssh/authorized_keys文件中,就可以实现自动登陆了。
#-*- coding:utf-8 -*-
from fabric.api import env, roles, run, execute, cd
env.hosts = ['10.216.224.65', '10.216.224.66']
env.user = 'user'
env.key_filename = '~/.ssh/id_rsa_fabric'
def taskA():
with cd('/usr/local/webserver'):
run('pwd')
※注意:authorized_keys文件权限只所有者可写,其他用户均无写权限,否则sshd将认为不安全不允许使用该文件导致还需要输入密码认证。
#-*- coding:utf-8 -*-
from fabric.api import run, env
# env被称为环境字典,用来配置一些运行环境相关的信息
env.hosts = ['192.168.1.100', '192.168.1.101']
env.user = 'user'
env.password = 'passwd'
def taskA():
run('cd /usr/local/webserver/php && ls -l')
run('sudo /usr/local/webserver/nginx/sbin/nginx -t')
fabric.api包里的run()方法可以用来执行远程Shell命令。上面的任务会分别到两台服务器”192.168.1.100”和”192.168.1.101”上执行命令。这里假设两台服务器的用户名都是”user”,密码都是“passwd”。
env.hosts是设置机器列表的,也可以把用户直接写到hosts里:
env.hosts = ['[email protected]', '[email protected]']
如果你的env.hosts里没有配置某个服务器,但是你又想在这个服务器上执行任务,你可以在命令行中通过-H指定远程服务器地址,多个服务器地址用逗号分隔:
fab -H 192.168.1.102,192.168.1.103 taskA
如果对于不同的服务器想执行不同的任务,上面的程序就做不到了,我们需要对服务器定义角色:
#-*- coding:utf-8 -*-
from fabric.api import env, roles, run, execute, cd
env.roledefs = {
'dev': ['[email protected]', '[email protected]'],
'online': ['[email protected]']
}
# host strings必须由username@host:port三部分构成,缺一不可,否则运行时还是会要求输入密码
env.passwords = {
'[email protected]:22': 'passwd1',
'[email protected]:22': 'passwd2',
'[email protected]:22': 'passwd3'
}
@roles('dev')
def taskA():
with cd('/usr/local/webserver'):
run('pwd')
@roles('online')
def taskB():
run('pwd')
def task():
execute(taskA)
execute(taskB)
然后执行task任务:
$ fab task
Fabric会在dev机器上执行taskA任务,然后在online机器上执行taskB任务。@roles装饰器指定了它所装饰的任务会被哪个角色的服务器执行。
如果某一任务上没有指定某个角色,但是你又想让这个角色的服务器也能运行该任务,你可以通过-R来指定角色名,多个角色用逗号分隔:
$ fab -R online taskA
到目前为止,我们介绍了local()和run()函数分别用来执行本地和远程Shell命令。Fabric还提供了其他丰富的功能函数来辅助执行命令,这里我们介绍几个常用的:
功能类似于run()方法,区别是它相当于在Shell命令前加上了sudo,所以拥有超级用户的权限。使用此功能前,你需要将你的用户设为sudoer,而且无需输密码。
from fabric.api import env, sudo
env.hosts = ['[email protected]', '[email protected]']
env.password = '111111'
def hello():
sudo('mkdir /var/www/myapp')
它的工作原理是基于scp命令,使用的方法如下:
from fabric.api import env, get
env.hosts = ['[email protected]',]
env.password = '111111'
def hello():
get('/var/log/myapp.log', 'myapp-0301.log')
上述任务将远程机上”/var/log/myapp.log”文件下载到本地当前目录,并命名为”myapp-0301.log”。
同get一样,put方法也是基于scp命令,使用的方法如下:
from fabric.api import env, put
env.hosts = ['[email protected]', '[email protected]']
env.password = '111111'
def hello():
put('/tmp/myapp-0301.tar.gz', '/var/www/myapp.tar.gz')
上述任务将本地”/tmp/myapp-0301.tar.gz”文件分别上传到两台远程机的”/var/www/“目录下,并命名为”myapp.tar.gz”。如果远程机上的目录需要超级用户权限才能放文件,可以在put()方法里加上use_sudo参数:
put('/tmp/myapp-0301.tar.gz', '/var/www/myapp.tar.gz', use_sudo=True)
该方法类似于Shell中的read命令,它会在终端显示一段文字来提示用户输入,并将用户的输入保存在变量里:
from fabric.api import env, get, prompt
env.hosts = ['[email protected]',]
env.password = '111111'
def hello():
filename = prompt('Please input file name: ')
get('/var/log/myapp.log', '%s.log' % filename)
现在下载后的文件名将由用户的输入来决定。我们还可以对用户输入给出默认值及类型检查:
port = prompt('Please input port number: ', default=8080, validate=int)
执行任务后,终端会显示:
Please input port number: [8080]
如果你直接按回车,则”port”变量即为默认值”8080”;如果你输入字符串,终端会提醒你类型验证失败,让你重新输入,直到正确为止。
看方法名就猜到了,有时候安装好环境后,需要重启服务器,这时就要用到reboot()方法,你可以用wait参数来控制其等待多少秒后重启,没有此参数则代表立即重启:
from fabric.api import env, reboot
env.hosts = ['[email protected]',]
env.password = '111111'
def restart():
reboot(wait=60)
上面的restart任务将在一分钟后重启服务器。
Fabric的上下文管理器是一系列与Python的”with”语句配合使用的方法,它可以在”with”语句块内设置当前工作环境的上下文。让我们介绍几个常用的:
cd()方法在之前的范例中出现过,with cd()语句块可以用来设置远程机的工作目录:
from fabric.api import env, cd, put
env.hosts = ['[email protected]', ]
env.password = '111111'
def hello():
with cd('/var/www/'):
put('/tmp/myapp-0301.tar.gz', 'myapp.tar.gz')
上例中的文件会上传到远程机的”/var/www/“目录下。出了with cd()语句块后,工作目录就回到初始的状态,也就是”ckr”用户的根目录。
lcd()就是”local cd”的意思,用法同cd()一样,区别是它设置的是本地的工作目录:
from fabric.api import env, cd, lcd, put
env.hosts = ['[email protected]', ]
env.password = '111111'
def hello():
with cd('/var/www/'):
with lcd('/tmp/'):
put('myapp-0301.tar.gz', 'myapp.tar.gz')
这个例子的执行效果跟上个例子一样。
from fabric.api import env, run, path
env.hosts = ['[email protected]', ]
env.password = '111111'
def hello():
with path('/home/ckr/tmp'):
run('echo $PATH')
run('echo $PATH')
假设我们的PATH环境变量默认是”/sbin:/bin”,在上述with path()语句块内PATH变量将变为”/sbin:/bin:/home/ckr/tmp”。出了with语句块后,PATH又回到原来的值。
Fabric环境变量即是我们例子中一直出现的fabric.api.env,它支持的参数可以从官方文档中查到。
from fabric.api import env, run, settings
env.hosts = ['[email protected]', ]
env.password = '111111'
def hello():
with settings(warn_only=True):
run('echo $USER')
我们将环境参数warn_only暂时设为True,这样遇到错误时任务不会退出。
可以用来临时设置远程和本地机上Shell的环境变量。
from fabric.api import env, run, local, shell_env
env.hosts = ['[email protected]', ]
env.password = '111111'
def hello():
with shell_env(JAVA_HOME='/opt/java'):
run('echo $JAVA_HOME')
local('echo $JAVA_HOME')
from fabric.api import env, run, local, prefix
env.hosts = ['[email protected]', ]
env.password = '111111'
def hello():
with prefix('echo Hi'):
run('pwd')
local('pwd')
在上述with prefix()语句块内,所有的run()或local()方法的执行都会加上echo Hi &&前缀,也就是效果等同于:
run('echo Hi && pwd')
local('echo Hi && pwd')
配合后一节我们会讲到的错误处理,它可以确保在prefix()方法上的命令执行成功后才会执行语句块内的命令。
默认情况下,Fabric在任务遇到错误时就会退出,如果我们希望捕获这个错误而不是退出任务的话,就要开启warn_only参数。在上面介绍settings()上下文管理器时,我们已经看到了临时开启warn_only的方法了,如果要全局开启,有两个办法:
$ fab -w hello
from fabric.api import env
env.warn_only = True
现在遇到错误时,控制台会打出一个警告信息,然后继续执行后续任务。那我们怎么捕获错误并处理呢?像run(), local(), sudo(), get(), put()等SSH功能函数都有返回值。当返回值的succeeded属性为True时,说明执行成功,反之就是失败。你也可以检查返回值的failed属性,为True时就表示执行失败,有错误发生。在开启warn_only后,你可以通过failed属性检查捕获错误,并执行相应的操作。示例如下:
from fabric.api import env, cd, put
env.hosts = ['[email protected]', ]
env.password = '111111'
def hello():
with cd('/var/www/'):
upload = put('/tmp/myapp-0301.tar.gz', 'myapp.tar.gz')
if upload.failed:
sudo('rm myapp.tar.gz')
put('/tmp/myapp-0301.tar.gz', 'myapp.tar.gz', use_sudo=True)
我们在介绍执行远程命令时曾提到过多台机器的任务默认情况下是串行执行的。Fabric支持并行任务,当服务器的任务之间没有依赖时,并行可以有效的加快执行速度。怎么开启并行执行呢?办法也是两个:
$ fab -P hello
from fabric.api import env
env.parallel = True
以上是对任务并行做一个全局控制。如果只想对某一个任务做并行的话,我们可以在任务函数上加上@parallel装饰器,这样即便全局并行未开启,被@parallel装饰的任务也会并行执行:
from fabric.api import parallel
@parallel
def runs_in_parallel():
pass
def runs_serially():
pass
这样即便并行未开启,runs_in_parallel()任务也会并行执行。
反过来,我们可以在任务函数上加上@serial装饰器:
from fabric.api import serial
def runs_in_parallel():
pass
@serial
def runs_serially():
pass
这样即便并行已经开启,runs_serially()任务也会串行执行。
文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...
文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档
文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子
文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud
文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换
文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装
文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者
文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be and th_normalized plane coordinates
文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取
文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面
文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思
文章浏览阅读240次。conan简单使用。_apt install conan