入门容易精通难,python适合作为第二编程语言(对于运维:Shell,对于开发:Java,对于全栈:nodejs(javascript))
python官网:https://www.python.org/
Python is a programming language that lets you work quicklyand integrate systems more effectively.
python是编程语言界中最神奇的一种编程语言
通常情况下使用python可以用几乎一半不到的代码量实现同等功能,相较于c++,java
python的强大不仅仅是自身,同时python更重要的是丰富的第三方库
python最早是谷歌开始使用的,用于服务器运维
python也是linux操作系统中必备的重要组件(包管理器)
在你使用linux系统的时候,就已经享受了python带来的便捷
绝大多数linux操作系统都默认自带python的环境
python分为两大分支:
两个不兼容,目前python2停止维护,主流版本为python3
部分python老项目停留在python2的版本
很多linux操作系统会同时包含python2和python3环境
我们很多时候使用python更多的去考虑使用虚拟环境(于系统自带的python进行隔离) -> 容器技术(docker),类似于沙盒技术
一般情况下python的虚拟环境我们使用两种方式解决
本次课程使用conda(miniconda) 作为python的部署工具
采用miniconda版本
https://docs.conda.io/en/latest/miniconda.html
下载miniconda的安装脚本
[root@www ~]# curl -O https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py38_4.8.3-Linux-x86_64.sh
或者
[root@www ~]# wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py38_4.8.3-Linux-x86_64.sh
补充知识: 如何将windows的文件推送到windows
win10 默认自带openssh客户端,可以使用scp命令推送文件到linux中
scp windows文件路径 [email protected]:linux系统文件路径
windows到linux的免密ssh登录:(点击打开)
在linux中运行https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py38_4.8.3-Linux-x86_64.sh
vi ./.bashrc 在末尾添加deactivate 或者 echo conda deactivate >> .bashrc
重启终端环境 source .bashrc
下载安装包
双击运行程序
对于国内用户可以通过以下网址
conda info -e #查看所有的虚拟python环境
conda deactivate #关闭被激活的虚拟python环境
conda activate 环境名 #激活虚拟python环境(可用于环境之间的切换)
conda create -n 环境名 python=版本号 #创建一个指定版本号的python虚拟环境
conda remove -n 环境名 --all #完整删除某个环境
conda install 软件名称 #使用conda安装某个软件或者python包(需要先激活目标虚拟环境),会分析当前环境,把软件本身和依赖一起安装
conda remove 软件名称 #卸载某个软件或者python的包(需要先激活目标虚拟环境)
conda search 软件名称 #查找某个软件或者python的包(需要先激活目标虚拟环境)
conda list #显示已经安装的软件或者python包
清华大学镜像站anconda下载地址
https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/
VS Code是一个高级文本编辑器,相较于传统的文本编辑器,可以配置开发环境,用于多种编程语言开发,同时比传统IDE轻量
VS Code是基于浏览器开发的一个工具,配置文件采用jason的形式
VS Code支持远程SSH开发(Windows上使用VS Code通过SSH的方式远程连接到Linux环境中进行开发操作)
另一个常用于python开发的IDE–Pycharm
https://code.visualstudio.com/
运行安装程序
安装扩展包:
Anaconda Extension Pack(python开发套件和yaml辅助套件) ;
远程开发包:Remote Development(wsl:在windos中使用linux,ssh:ssh传输协议, Containers:容器技术)
中文环境包
点击左侧的远程资源管理器,选择ssh模式,输入ssh登录方式,将ssh登录config文件保存在用户主目录
Host 192.168.218.147 # 远程设备名称(给使用看的,可随意起名字)
HostName 192.168.218.147 # ssh远程的目标地址
User root # ssh远程登录的用户
然后通过VS Code远程链接上目标设备,在里面创建一个专门用于放置自己编写代码的文件夹
任何编程语言的第一个程序无外乎Hello, World!
我们怎么来编写运行呢?
通过VS Code创建hello.py文件
在扩展中将Python的扩展安装到远程设备中
在打开python源代码文件的时候会自动的加载python扩展插件
我们需要手动选择一个Python环境用于VS Code快速执行代码文件
然后就可以愉快的编写代码了
print("Hello, World!")
记得保存一下
我们可以通过这些方式来运行我们编写的Python代码
(py38) [root@server code]# python hello.py
Hello, World!
(py38) [root@server code]#
Python对于代码有个较为严格的格式要求
更多有关代码风格的问题我们会在后面具体接触到一些特定语法的时候单独讲
对于变量,首当其冲就是需要解决一个变量位置的问题(变量是程序运行过程中的数据、在内存中)
我们对于变量通常采用的是标识符命名法
标识符规范(Python3):
对于Python中变量,不同于C、C++、Java,Python中的变量更多的是一个快递盒子
静态类型与动态类型
静态类型:会提前设计好不同大小的快递盒子,并且每种盒子可以装什么东西是提前规定好的
动态类型:根据东西定义盒子大小、不限定盒子装什么
静态类型:牺牲用户,提高快递店盒子的使用(代码编写规范要求多,但是往往带来性能层面的提升)
动态类型:方便用户,快递店要定制盒子(规范要求变少了,往往会牺牲较多的性能)
正是因为这个原因,所以如果没有东西,那么没有办法定制盒子(Python中的变量需要先赋值、然后才能被使用)
在Python中,输出语句为print,会将括号中的值输出到终端上(如果说是一个变量,那么会输出变量的值)
print看做是x光检查器
print是Python自带的一个内置函数(方法)
print语句支持多个变量或者数据在括号中,使用英文逗号分隔,那么print将会一次性的打印出这些的值,用空格作为他们直接的分隔
可以在里面添加end参数来控制print结尾的字符
a = 100
b = "Python"
print(a, end="")
print(b)
在Python中,输入语句为input,会接受从终端中输入的值(换行符结束)
input也是Python自带的一个内置函数(方法),返回值为字符串类型
input也有括号,括号可以填入数据或者变量来充当print
print("请输入你的姓名:")
name = input()
print("你好", name)
input("按回车键退出:")
注意事项:输入的内容统统会被当做字符串来处理
整数、浮点数、字符串、布尔
Python中的整数和数学当中对于整数的定义是一致的,Python中整数可以为任意大小
Python中的浮点数就是小数,Python中浮点数的精度是可以无限的
在Python中没有单独的字符类型,对于从终端接收的数据统统视为字符串
在Python中,布尔只有两种值:True、False
100 # 整数
100.0 # 浮点数
"100" # 字符串
'100' # 字符串
True # 布尔
Python对于运算符的支持很强大,提供了大量的运算符
符号 | 作用 |
---|---|
+ | 数字类型求和运算,用于两个字符串直接的合并 |
- | 数学类型求差 |
* | 数字类型求积,用于字符串重复自我整数倍合并 |
/ | 得到浮点数版本的商 |
** | 乘方运算 |
// | 地板除(得到整数商) |
% | 求余数 |
= | 赋值 |
> | 大于(结果为布尔值) |
< | 小于(结果为布尔值) |
>= | 大于等于(结果为布尔值) |
<= | 小于等于(结果为布尔值) |
== | 等于(结果为布尔值) |
!= | 不等于(结果为布尔值) |
and | 与(布尔运算) |
or | 或(布尔运算) |
not | 非(布尔运算) |
is | 判断是否是同一对象 |
in | 判断是否在内(判断字符串中是否有特定的字符) |
在Python中,分支语句使用下面的几个重要关键词
分支语句结构
if bool表达式 :
执行的语句
执行语句
if bool表达式 :
执行的语句
else:
执行的语句
执行语句
if bool表达式 :
执行的语句
elif bool表达式: # 先否定上面的条件,然后判断自己的这个bool表达式
执行的语句
执行语句
if bool表达式 :
执行的语句
elif bool表达式: # 先否定上面的条件,然后判断自己的这个bool表达式
执行的语句
else:
执行的语句
执行语句
三个变量、分别存放用户输入的姓名、性别、职业
提示用户输入自己的姓名、性别、职业
如果用户输入了空的内容,那么对应的姓名、性别、职业应该赋值为——“用户未输入”
最后输出一句话,包含用户的姓名、性别、职业
难点:判断用户输入的为空
a = input()
if a:
print("True") # 当输入不为空时
else:
print("False") # 当输入为空的时候
在python中,有关循环的关键词为for,while
结构
while bool 表达式
重复执行的语句
循环之外的语句
在循环中,有两个关键词用于控制循环:
在Python中,可以用else来判断循环体是否被中断了
while bool表达式:
重复执行的语句
else:
循环条件不满足的时候(循环正常结束)
循环之外的语句
结构
for 变量 in 可迭代对象:
对可迭代对象中的每一个元素进行操作
else:
全部对象都遍历完毕之后的时候
循环之外的语句
range方法:用于快速生成可迭代的纯数字结构
range可接受1、2、3个参数,均为大于0的整数
range(10) # 0、1、2、3、4、5、6、7、8、9
range(2, 5) # 2、3、4
range(1, 10, 2) # 1、3、5、7、9
range从Python3开始以生成器的身份出现(不会一下子把所有的数全部存放到内存中,而是在迭代或 者遍历过程中算出来)
小练习:水仙花数
如果有一个数,它的每一位的值得立方和等于其本身,那么就是水仙花数
例子 :
153 = 1 ^ 3 + 3 ^ 3 + 5 ^ 5 请通过Python求出1到1000范围内所有的水仙花数
总结一个求数字中每一位的通用公式
(num // 1 % 10) # 个位
(num // 10 % 10) # 十位
(num // 100 % 10) # 百位
(num // 1000 % 10) # 千位
https://docs.python.org/zh-cn/3/library/functions.html
Python的内置函数非常的丰富,包含了提供了诸多简单的方式处理问题,这里简单介绍一些内置函数
内置函数 作用
abs 求一个数的绝对值
bool 返回对象的布尔值
ord 将字符转为Unicode 码数字
chr 将Unicode 码数字转为字符
dir 列出包或者模块或者类当中所有的有效属性或者有效方法
id 获取一个对象的唯一标识(等效于内存地址)
len 返回长度(内部有多少元素)
max 求大
min 求小
sum 求和
round 设置精度(非四舍五入,采用银行家舍入,奇数进,偶数舍)
type 查看对象的类型
bin 将一个整数转变为一个前缀为“0b”的二进制字符串(二进制)oct 将一个整数转变为一个前缀为“0o”的二进制字符串(八进制)hex 将一个整数转变为一个前缀为“0x”的二进制字符串(十六进制)
python中对于字符串常用format方法进行格式化操作
"".format()
前面的字符串中需要占位符来限定格式化的操作
当format中有数字的时候,格式化可以在多加一些效果
"{<索引号>:<填充字符><对齐方式><宽度>}"
宽度: 设定字符的输出宽度(如果输出字符超过设定的宽度,会按照整个字符的宽度处理)
对齐方式:
< 左对齐
> 右对齐
^ 居中
填充字符: 填补空白区域,默认是空白
索引号: 对应formant
format中有数字时,格式化可以多加一些效果
"{<索引号>:<填充字符><对齐方式><宽度><,><精度数字><类型>}"
, : 是否显示千位分隔符
精度: 限定输出长度(小数部分或长度)
类型:
b: 二进制
c: unicode字符
d: 十进制
o: 八进制
x: 十六进制
X: 十六进制(大写模式)
e: 科学计数法
E:科学计数法大写
f: 浮点数标准格式
%: 按百分数形式输出
当然,字符串可以有很多额外的操作
r"" #转义字符
f"" #format偷懒方式
replace: 字符串替换
"".replace("被替换的字符串","替换的目标")
split: 字符串分割
"".split(分割依据) #默认非可见字符
strip: 清除左右
"".strip(清除的字符) #默认非可见字符
join: 合并字符串
'间隔符'.join(字符串)
练习: 宝塔生成器
输入宝塔高度,作为宝塔高度
输出三角形塔:
1/3/5
居中,宽度40-60,
切片不光可以用于字符串,列表、元祖也适用
Python中的索引规则
从左往右:0、1、2、3、4、。。。。
从右往左:-1、-2、-3、-4、。。。。
在Python中,切片使用[]来标识
"Python"[]
切片的几种用法
"Python"[1] # 等同于根据索引取值
"Python"[1:] # 从索引为1开始到结尾
"Python"[:3] # 从开头到索引为3截止(左闭右开)
"Python"[:] # 取全部
"Python"[-1] # 从右往左取
"Python"[::2] # 索引每隔2距离取
在Python中有四大基本数据结构
这个是Python中使用率高的一种结构,在结构上类似于其他编程语言的数组,但是是动态的(可自由 伸缩长度),列表中的元素可以是任何类型
关键词list
a = list() #创建空列表
b = [] #
a = list(1, 2, 3)
b = [1, 2, 3]
使用for操作列表
for i in 列表:
操作
操作完毕
在列表中常用的一些方法:
append: 在末尾添加元素
list().append(添加的内容)
pop: 删除末尾元素,并返回元素值
list().pop()
a = [1,2,3,4,5]
while len(a) > 0:
print(a.pop()) #pop默认从后往前推,即栈结构,后入先出
print(a)
b = [1,2,3,4,5]
while len(b) > 0:
print(b.pop(0)) #pop(0)可以实现从前往后推,即队列,先入先出
print(b)
字典是一种key-value的形式,等同于其他语言中的map,hashmap
创建字典 关键词为dict
d = dict() #创建一个空字典
d = {
} #同上
d = {
"key1":任意对象,
"key2":任意对象,
}
什么类型可以作为key:
在字典结构当中,一般用字符串或者整数作为key,一切不可变对象才可以作为key
在字典中,key是唯一存在的,value可以重复
字典中的一些方式
dict()["a"] = 1 #如果不存在key为a的,那么创建并赋值为1,存在就覆盖原值
del dict()['a'] #删除key为a的元素 del可以删除python中的任何对象
字典常用的一个重要方法
dict().items() #将字典转化为列表,列表中的每一个元素变为键值对的元组模式,在字典遍历很常用
元组是特殊的列表结构(只读)
关键词 tuple
创建元组
t = tuple() #创建一个空元组
t = (1, ) #创建单元素元组
t = (1,2) #创建多元素的元组,可不加括号
元组的最大用途: 变量交换
a,b = b,a #a,b的值交换
性质于数学中的一致: 唯一,无序
集合没有value的字典,集合只能保存不可变类型
关键字set
s = set() #创建空集合
s = {
#创建带数据的集合
1,
3,
5,
7,
}
常用方法
set().add() #添加元素
set().remove() #删除元素
在python中的模块调用使用import
import 模块
模块搜索: 当前目录–> python的lib目录–> lib/site-package下
当引入自己编写的模块的时候,会生成一个 __ pycache __ 的文件夹,里面是被引入的模块的pyc版本 (被编译)
补充: python的包(多个模块在一个文件夹中)
https://docs.python.org/zh-cn/3/tutorial/modules.html#packages
在python项目中,会有_ init_.py的文件,用于初始化模块的一些功能(先搜索此文件),也是一个包的标识
了解这些主要的内置库
print(dir(模块名))
os.name #linux 系统的标识
os.uname
print(os.uname().sysname)
print(os.uname().nodename)
print(os.uname().machine)
os.pipe 管道
os.path #重要方法
os.path.isfile 判断是否为文件
os.path.islink 判断是否链接(软)
os.path.ismount 判断是否为挂载点
os.path.samefile(path1, path2)
如果两个路径都指向相同的文件或目录,则返回 True。这由设备号和 inode 号确定,在任一路径上调用 os.stat() 失败则抛出异常。
os.path.join(path, *paths)
合理地拼接一个或多个路径部分。返回值是 path 和 *paths 所有值的连接,每个非空部分后面都紧跟一个目录分隔符 (os.sep),除了最后一部分。这意味着如果最后一部分为空,则结果将以分隔符结尾。如果参数中某个部分是绝对路径,则绝对路径前的路径都将被丢弃,并从绝对路径部分开始连接。
在 Windows 上,遇到绝对路径部分(例如 r’\foo’)时,不会重置盘符。如果某部分路径包含盘符,则会丢弃所有先前的部分,并重置盘符。请注意,由于每个驱动器都有一个“当前目录”,所以 os.path.join(“c:”, “foo”) 表示驱动器 C: 上当前目录的相对路径 (c:foo),而不是 c:\foo。
os.path.split(path)
将路径 path 拆分为一对,即 (head, tail),其中,tail 是路径的最后一部分,而 head 里是除最后部分外的所有内容。tail 部分不会包含斜杠,如果 path 以斜杠结尾,则 tail 将为空。如果 path 中没有斜杠,head 将为空。如果 path 为空,则 head 和 tail 均为空。head 末尾的斜杠会被去掉,除非它是根目录(即它仅包含一个或多个斜杠)。在所有情况下,join(head, tail) 指向的位置都与 path 相同(但字符串可能不同)。另请参见函数 dirname() 和 basename()。
os.listdir() 列出当前工作目录
os.system(“shell命令”) #通过python操作linux
time 模块
time.time() 时间戳
time.localtime() 获取本地时间
time.ctime() 可读日期(国外)
time.strftime("%Y-%m-%d %H-%M-%S",time.localtime())
subprocess: 专门开启新进程
https://docs.python.org/zh-cn/3/library/subprocess.html
returncode
子进程的退出状态码. 通常来说, 一个为 0 的退出码表示进程运行正常.
一个负值 -N 表示子进程被信号 N 中断 (仅 POSIX).
stdout
从子进程捕获到的标准输出. 一个字节序列, 或一个字符串, 如果 run() 是设置了 encoding, errors 或者 text=True 来运行的. 如果未有捕获, 则为 None.
如果你通过 stderr=subprocess.STDOUT 运行, 标准输入和标准错误将被组合在一起, 并且 stderr` 将为 None.
stderr
捕获到的子进程的标准错误. 一个字节序列, 或者一个字符串, 如果 run() 是设置了参数 encoding, errors 或者 text=True 运行的. 如果未有捕获, 则为 None.
shutil 高级文件操作,可以替代很多体系工具
shutil.copy2(src, dst, *, follow_symlinks=True)
类似于 copy(),区别在于 copy2() 还会尝试保留文件的元数据。
shutil.rmtree(’__ pycache __/’) #等效rm-rf
shutil.rmtree(path, ignore_errors=False, οnerrοr=None)
删除一个完整的目录树;path 必须指向一个目录(但不能是一个目录的符号链接)。
shutil.disk_usage(path)
返回给定路径的磁盘使用统计数据,形式为一个 named tuple,其中包含 total, used 和 free 属性,分别表示总计、已使用和未使用空间的字节数。 path 可以是一个文件或是一个目录。
例子:定制化处理数据
import shutil
disk_usage = shutil.disk_usage("/")
print("磁盘使用比:","{:E}".format(int(disk_usage.used)/int(disk_usage.total)))
https://docs.python.org/zh-cn/3/library/shutil.html
#!/bin/bash/env python
import shutil
input("打包名")
input("格式")
input("打包位置")
shutil.make_archive("python","tar","?root/miniconda3/")
官方内置库:自我提升的平台https://docs.python.org/zh-cn/3/library/index.html
练习: 做一个文件分类器
分类指定目录下的多种文件(通过后缀名的方式),复制到归档用的文件夹中,按照后缀名区分文件, 在分类完毕之后归档(zip、tar)
可变类型:
不可变类型:
区别:当变量指向同一个数据时,其中一个变量对数据修改,会不会导致其他变量中对应的值也发生变化
底层: C语言中指针概念
函数: 用于包装部分代码(需要多次使用)
在python中,一个函数的基本结构:
def 函数名(参数信息):
代码语句
return 返回值
例子: 求两数之和
def add(x,y):
return x+y
参数和普通的变量一致,相当于参数=变量
在python中,可以使用特定的符号来限定参数的类型
def add(x: int, y: int) -> int: #开发工具会根据此内容去检查参数传递是否正确
return x+y
在传入参数的时候,可以直接通过对参数赋值来传入数据(可以不按照函数定义的参数顺序从传入参 数)
当使用参数赋值法传入参数后,后面的参数也必须使用此方法
在函数定义的时候可以同时定义默认值:当没有对应参数的时候,使用默认值替代
def add(x: int, y=15) -> int:
return x+y
python中函数没有重载
参数有两个特殊参数
通常情况下的用法
def fun1(*arg): #只能接受普通参数形式,会变成一个元组形式
print(arg)
def fun2(**karg): #只能采用参数赋值形式,会变成一个字典形式
print(karg)
当没有return时,默认返回None类型
在python中,return可以返回多个数据,通过逗号分隔,返回元组
如何使用python操作文件
使用内置函数open
基本流程
f = open(文件名,打开方式)
进行文件操作
f.close()
打开方式 | 解释 |
---|---|
r | 读 |
w | 写 |
a | 写(追加) |
[r,w,a]b | 以二进制方式 |
[[r,w,a]b]+ | 开启读,写 |
常用的几个操作
f.read() #读取文件中的所有数据
f.readline() #读取一行数据(根据换行符) 文本类型使用
f.readlines() #读取所有数据并且根据行分割成为列表 文本类型使用
f.write() #向文件中写入数据
分段读取文件:
f = open("/etc/yum.conf", 'r')
while 1:
t = f.read(10)
if len(t)>0:
print(t)
else:
break
f.close()
二进制数据与文本类型数据的相互转换
t = b'[main]\ngpgcheck=1\ninstallonly_limit=3\nclean_requirements_on_remove=True\nbest=True\n'
t = t.decode("utf-8")
t = [main]\ngpgcheck=1\ninstallonly_limit=3\nclean_requirements_on_remove=True\nbest=True\n'
# 以bytes类型写入
s = s.encode("utf-8") #编码
单独写f.close()容易忘记,怎么办
with open("/etc/yum.conf", 'r')as f:
执行操作
(当离开with区域,会自动关闭文件)
最常用的方式: pip
(py38)# pip
(py38)# python -m pip
pip的基本使用同yum,dnf,apt
pip install 包名
pip search 包名
pip list #显示安装的包
pip unistall 包名
pip update 包名
利用pip生成环境配置文件(尤其是当使用venv方式生成虚拟环境的时候)
pip freeze > requirements.txt #生成一个第三方库的环境列表
pip install -r requirements.txt #根据环境列表安装所有的第三方库
python -m venv my_python 生成一个python环境
python -m pip install --upgrade pip 更新pip环境
当使用conda环境时
conda list -e > requirements.txt #基于conda导出所有第三方库的环境列表
conda install --file requirements.txt #在环境创建好之后基于有第三方库的环境列表安装环境
pip源的网站:https://pypi.org/
awesome——python:Python常用第三方库的综合
https://github.com/jobbole/awesome-python-cn/
https://awesome-python.com/
Python默认自带了urlib库用于处理HTTP相关任务,但是urlib库不是很好用
所以我们使用requests库
pip install requests
conda install requests
引入模块
import requests
利用requests库访问页面
import requests
r = requests.get("https://www.python.org")
print(r.text)
HTTP请求的方式: (RESTful)
GET: 用于获取资源,传递的参数会在url中体现(一般无需用户认证)
POST: 用于提交,上传数据,传递的数据一般在HTTP请求体中(安全性更高)
PUT: 用于创建新数据
DELETE: 用于删除数据
我们案例以 以https://www.sojson.com/api/semantic.html 提供的免费接口来模拟
URL:http://api.qingyunke.com/api.php?key=free&appid=0&msg=鹅鹅鹅
cookie: :HTTP由于是无状态网络会话,cookie是由服务器发出要求保存着浏览器端的一些数据,用于保存会话状态(用户状态)
user-agent: 用于告诉服务器客户端的一些信息,(如浏览器的版本,类型,操作系统)
利用cookie和user-agent可以让我们的程序伪装成真实浏览器去完成相应的操作
然而在很多时候,requests操作有api提供的接口会很方便,但是有时候一些平台没有api接口,那么我 们就需要使用一些技术手段来实现
selenium是一个原本用java编写的一个用于自动化操作浏览器的工具,开始用于网站页面的自动化测试
selenium提供了python的接口,可以让我们用python很轻松的去操作浏览器访问web外部面板
实验将使用cockpit面板来测试
启动面板
systemctl enable --now cockpit.socket
既然要操作浏览器,而且不同的浏览器,需要使用不同的浏览器驱动,本次实验我们使用的是chrome 浏览器
一般来说,我们使用windows来执行
需要安装selenium框架,需要下载对应的浏览器驱动
pip install selenium
conda install selenium
由于谷歌网站访问有难度,所以下载浏览器驱动可能会困难,所以从国内的镜像站下载驱动
https://npm.taobao.org/mirrors/chromedriver/
下载的时候注意与自己浏览器的版本要对应
将驱动和代码放在一个文件夹中
利用Python启动一个浏览器并且打开我们的web面板
# 这是一份样例代码(能跑,但是很多地方没好好的打磨)
from selenium import webdriver
import time
# 让浏览器可以在后台运行(无需界面),这种方式往往会有一些小问题
# from selenium.webdriver.chrome.options import Options
# ch_options = Options()
# ch_options.add_argument("--headless")
# web = webdriver.Chrome(options=ch_options)
web = webdriver.Chrome()
web.get("http://192.168.218.147:9090/")
# 自动点击强行访问不安全链接
time.sleep(1)
web.save_screenshot("1.png")
button = web.find_element_by_xpath("/html/body/div/div[2]/button[3]") button.click()
time.sleep(1)
url_button = web.find_element_by_xpath("/html/body/div/div[3]/p[2]/a") url_button.click()
# 登录
time.sleep(1)
web.save_screenshot("2.png")
user_name = web.find_element_by_xpath("/html/body/div[2]/div/div[2]/div/div[4]/input")
user_name.send_keys("root")
time.sleep(1)
pass_word = web.find_element_by_xpath("/html/body/div[2]/div/div[2]/div/div[5]/input")
pass_word.send_keys("root")
time.sleep(1)
login_button = web.find_element_by_xpath("/html/body/div[2]/div/div[2]/div/div[8]/button")
login_button.click()
time.sleep(1)
# 登录成功了
web.maximize_window() # 最大化
web.save_screenshot("2.png")
time.sleep(1)
web.switch_to_frame("cockpit1:localhost/system") # 当页面中存在iframe框架的时候,需要 通过iframe的id或者name来切换到框架中
count = 0
while True:
time.sleep(0.5)
cpu_info = web.find_element_by_xpath("/html/body/div[1]/div/main/section[2]/div/article[2]/ div[2]/table/tbody/tr[1]/td/div/div[2]/span").text print(cpu_info)
if count < 10:
count = count + 1
else:
break
web.switch_to_default_content() # 从内部的iframe中回到整体页面中
web.close() # 关闭浏览器
案例: day3 3:00-4:00 页面获取监控面板
selenium可以直接操作浏览器,同时可以捕获浏览器上的各种数据,特别适用于没有api接口的网页
可以将部分重复操作通过自动化的方式处理掉(CMBD)
json是一种特殊的字符串,常用于Http级别上的数据交互,json是Javascript中的数据结构,但是被广泛的编程语言支持,在python中有专门的json内置库用于处理json数据,与字典关系密切
json.loads(json字符串) #将json字符串变为字典
json.dump(字典) #将字典编程json字符串
正则表达式是所有编程语言解决处理字符串的第一选择
正则 | 匹配对象 |
---|---|
\d | 单个数字 |
\D | 单个非数字符 |
\s | 单个不可见字符 |
\S | 单个可见字符 |
\w | 单个字母,数字,下划线,汉字 |
\W | 单个符号(下划线除外) |
. | 除换行外所有字符 |
单独的字母或数字 | 对应的匹配 |
^ | 从字符串首位开始 |
$ | 到字符串尾部截止 |
* | 重复0或者多次 |
+ | 重复1次或多次 |
? | 重复0或1 |
{n} | 重复n次 |
{n,} | 重复n次或多次 |
{n,m} | 重复n到m次 |
[] | 匹配字符集 |
https://tool.oschina.net/regex/ 正则匹配在线工具
在正则表达式中,贪婪模式和非贪婪模式
当单独使用* , + , ? , {} 默认情况下使用贪婪模式:尽可能匹配出最长的字符串
贪婪模式在大多数时不满足我们的需求
在上面的符号基础上再加上?实现懒惰模式:尽可能的匹配短字符串
在正则表达式中,小括号可以限定输出内容
在python中用于正则的是re模块
import re
parren = re.compile(r'正则字符串') #获取一个正则规则
paeren.findall(待匹配的字符串) #通过正则处理字符串,符合条件的结果为一个列表
小练习:
172.69.35.5 - - [11/Aug/2020:16:42:01 +0800] “GET / HTTP/1.1” 200 730 “-” "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0
统计出现的ip地址,请求类型,相应码
三个服务器的日志文件,
三个数据单独存放,
保存为网址.txt格式
内容预览:
172.69.35.5,GET/HTTP/1.1,200
.csv 文档格式的表格
程序在执行的过程中,往往会发生一些意外情况
用if分支语句提前处理
让用户输入两个数字,前面被除数,后面是除数,(重点: 除数不能为零)
第一种:正则
第二种:试一试(try)
异常处理对于一个程序的健壮性有着非常重要的作用
异常处理的结构
try:
可能会发生问题的代码
except 捕获什么异常:
针对出现的问题怎么处理
else:
代码try没有发生错误时指定的代码
finally:
不管之前是否出现异常都一定会执行
其他代码
try:
f = open("a.txt", 'r')
result = f.read()
print("文件读取完毕")
print("文件内容为:")
print(result)
except FileNotFoundError as e: #错误码类型(py自带的功能,几乎全部错误码类型)
print("文件不存在")
socket: 套接字
socket是绝大多数实现网络通信的基本
绝大多数编程语言,scoket == TCP/IP
在编程中,Http相关操作基于socket
socket让多台设备之间可以通过网络数据包的形式传输数据(分布式,集群,微服务)
C/S
服务端:
客户端:
案例:
服务端: Linux
客户端:Windows
server.py
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# scoket.AF_INET : IPv4 socket.SOCK_STREAM : 流式socket(TCP)
# scoket.AF_INET6 : IPv6 socket.SOCK_DDGRAM : 报文socket(UDP)
host = "192.168.199.129"
prot = 60000
server.listen(5) #排队的链接最多可以为多少
client_socket,addr = server.accept() # 返回一个元组,第一个为客户端的socket对象,后面为客户端的地址
recvmsg = client_socket.recv(1024) # 因为是数据流的形式,如果不加一次性读取的数据, 那么就会一直等待结束
strmsg = recvmsg.decode("utf-8")
print(strmsg)
server.close()
cleint.py
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = "192.168.199.129"
port = 60000
client.connect((host,port))
client.send("这是从客户端发送过来的一条数据".encode("utf-8"))
client.close()
修改一下,让客户端可以接受用户输入的命令,然后服务器执行,返回执行的结果:
server.py 写在服务端
import socket
import subprocess
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = "192.168.199.129"
port = 40000
server.bind((host,port))
server.listen(5)
while True:
client_socket,addr = server.accept()
recvmsg = client_socket.recv(1024)
strmsg = recvmsg.decode("utf-8")
result = subprocess.run(strmsg,shell=True,capture_output=True)
client_socket.send(result.stdout)
server.close()
client.py 写在客户端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = "192.168.199.129"
port = 40000
client.connect((host,port))
cmd = input("请输入你想要执行的命令:\n")
client.send(cmd.encode("utf-8"))
msg = client.recv(1024)
print(msg.decode('utf-8'))
client.close()
可以通过socket的方式批量与多设备之间交互(saltstack)
对于server而言
import socket
import subprocess
server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
host = "192.168.199.129"
port = 40000
server.bind((host,port))
while True:
recvmsg,addr = server.recvfrom(1024)
strmsg = recvmsg.decode("utf-8")
result = subprocess.run(strmsg,shell=True,capture_output=True)
server.sendto(result.stdout, addr)
server.close()
对于client
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
host = "192.168.199.129"
port = 40000
cmd = input("请输入你想要执行的命令:\n")
client.sendto(cmd.encode("utf-8"),(host,port))
msg = client.recvfrom(1024)
print(msg.decode('utf-8'))
client.close()
day4 10:30~11:30(上面的例子)
优点:速度快(TCP/IP),支持自动发现
缺点: c/s结构, 代码编写有一定的难度
代码封装为一个类,和函数类似,也是代码的复用,不过类比函数多了很多功能
术语
把相似的东西共同的共同点总结在一起
属性: 变量
方法: 函数(行为)
实例:基于一个类的具体实现
定义一个类:
class Human:
pass
实例化一个类
human1 = Human() #造人
给实例添加属性
human1.name = "小明"
通过 __ init __ 方法实现在实例化的同时添加属性
class Human(object):
def __init__(self,name):
self.name = name
补充: self是什么 —(self不是专有词)
self指被实例化的对象,实例
类属性由类和其实例共有,实例属性只有实例才有
class Human(object):
count = 0 # 类属性
class_name = "人类"
def __init__(self, name):
self.name = name # 实例属性
Human.count = Human.count + 1
def go(self):
print(self.name,"跑起来")
human1 = Human("小明")
human2 = Human("小刚")
human3 = Human("小红")
print('造人数量:',Human.count) # 设计模式——单例模式
Pyth支持多继承,继承的都可成为父类,但只有第一个为主要(覆盖后面继承的一些属性或者方法)
面向对象编程:
在于规范后面的代码,使用方便,增添功能方便
继承的层级太多的时候就很麻烦了
对于一些方法或者属性,不希望被调用
通过在方法或属性前面添加两个下划线实现私有封装(强制性): 只能通过类自身或者内部方法处理,子类也无法使用
单个下划线的属性或方法不进行直接访问
前面两个下划线,后面*两个下划线,*创建类时自带的
__ init__ :在类实例化时执行
__ new __ :实例化一个类
__ str__ : 优先影响print语句的输出,实际上是str函数对这个对象的操作的方法
__ repr__ : 次要影响print语句的输出,实际上是repr函数对这个对象的操作的方法
int() -> __ int __
float() -> __ float __
RPC基于socket,是早期实现远程操作的一种方式(高级方式)
RPC对网络层面的操作进行封装,同时通过接口数据的格式实现跨语言调用
RPC的实现:
在Python中,自带了xmlrpc框架,基于xml和http实现的RPC通信手段
RPC也是C/S架构
对应两个库
xmlrpc.server
xmlrpc.client
最简单demo
serverrpc.py
from xmlrpc.server import SimpleXMLRPCServer
import subprocess
host = "192.168.199.129"
port = 9000
server = SimpleXMLRPCServer((host,port))
#定义可用方法
def get_uname():
result = subprocess.run("uname-a",shell = True,capture_output=True)
return result.stdout
server.register_function(get_uname)
server.serve_forever()
clientrpc.py
import xmlrpc.client
server = xmlrpc.client.ServerProxy("http://192.168.199.129:9000")
result = server.get_uname()
print(result)
原始日志分析: 人肉
高级一些日志分析: 电子表格
线代日志分析: 数据库
数据库是什么: 专门用于数据存储的,并且提供了高效的检索能力
数据库有专门的编程语言----SQL
数据库种类:
编程中常用的几种数据库:
Elasticsearch: 日志存储,检索
Logstash: 收集日志
Kibana: 展示
一个数据库内部会包含多个表、每个表内部会有多个字段,我们写在表中的数据成为一条记录,对照 excel
Python是如何操作数据库(sqlit3)的
import sqlite3
db = sqlite3.connect("./python.db")
cur = db.cursor() # 创建一个游标(打开数据库交互界面)
sql = ""
cur.execute(sql)
cur.close()
db.close()
那么sql的写法?
CREATE TABLE log( /* 创建一张表 */
ip char(50), /* 字段和字段的数据类型 int char date float text */
function char(100),
status char(10)
);
DROP TABLE log; /*删除一张表*/
不可以创建一个已经存在的表,或者删除不存在表
INSERT INTO log (ip, function, status) value (v1,v2,v3) /* 标准写法 */
INSERT INTO log values (v1,v2,v3) /*写入的时候,传入的数据个数要和表的列数统一,且同序 */
在插入语句执行之后需要额外执行一句
commit;
让数据能够保存到数据库中
SELECT 列 FROM 表 WHERE 条件;
sql = "SELECT ip,function,status FROM log WHERE status='200';"
result = cur.execute(sql).fetchall()
print('108.162.245.110请求数量为:',len(result))
查询时可用的一些聚合函数
SELECT count(*) FROM log WHERE ip='108.162.245.110';
result = cur.execute(sql).fetchall()
print(result[0][0])
DELETE FROM 表 WHERE 条件
sql = "DELETE FROM log WHERE ip='108.162.245.110';"
result = cur.execute(sql).fetchall()
print(result)
UPDATE 表 SET 字段 = 新的值 WHERE 条件
sql = "UPDATE log status = '200' WHERE status = '404';"
result = cur.execute(sql).fetchall()
print(result)
cur.execute("commit;") /*提交确认
*/
时间: day4 16:00-16:40
为啥我们修改了数据之后,数据没有及时的变更呢?
关系型数据库的事务处理
当增、删、改的时候,需要执行commit
小挑战:
1、统计一下访问域名次数最多的IP地址是哪个(三个log文件的综合) 2、利用socket或者xmlrpc做一个监控(windows作为客户端,linux作为服务端,可交换),监控内存 占用情况(每5秒记录一次)
我们之前写的所有程序都是单进程单线程的,在面对大量任务的时候就会非常耗时间
线程是程序的最小执行单元,一个进程至少有一个线程
线程之间共享进程的内存空间,进程与进程之间的数据是隔离的
一般来说,线程适合IO密集型,进程适合cpu密集型
在Pyth中*, GIL锁机制* (CPython专属)
在Python中虽然可以多线程,但是真实的执行依旧是单线程模式
内置multiprocessing库用于实现跨平台多进程的实现
from multiprocessing import Process
import os
import time
def proc(name):
print("{}进程正在执行,pid为{}".format(name, os.getpid()))
time.sleep(5)
print("{}进程执行完毕,pid为{}".format(name, os.getpid()))
if __name__ == "__main": # 一定要确保这个是主进程
print("{}进程启动,pid为{}".format('主', os.getpid()))
p1 = Process(target=proc, args=('proc1',))
print("proc1进程创建完毕")
p2 = Process(target=proc, args=('proc2',))
print("proc2进程创建完毕")
p1.start()
p2.start()
p1.join()
p2.join()
print("执行完毕")
利用列表来管理多个进程
from multiprocessing import Process
import os
import time
def proc(name):
print("{}进程正在执行,pid为{}".format(name, os.getpid()))
time.sleep(5)
print("{}进程执行完毕,pid为{}".format(name, os.getpid()))
if __name__ == "__main": # 一定要确保这个是主进程
print("{}进程启动,pid为{}".format('主', os.getpid()))
p = []
# 批量创建进程对象
for i in range(20):
p.append(Process(target=proc, args=('proc'+str(i),)))
print("proc{}进程创建完毕".format(i))
for i in p: # 批量启动
i.start()
for i in p: # 等待全部完成
i.join()
p1 = Process(target=proc, args=('proc1',))
print("proc1进程创建完毕")
p2 = Process(target=proc, args=('proc2',))
print("proc2进程创建完毕")
p1.start()
p2.start()
p1.join()
p2.join()
print("执行完毕")
问题思考,如果直接开2000个进程呢?
并发执行的进程数量与cpu核心数一致
进程的创建与销毁是非常占用资源的
解决方案: 进程池
#进程池
from multiprocessing import Pool
import os
import time
def proc(name):
print("{}进程正在执行,pid为{}".format(name,os.getpid()))
time.sleep(10)
print("{}进程执行完毕,pid为{}".format(name,os.getpid()))
if __name__ == "__main__":
print("{}进程启动,pid为{}".format('主',os.getpid()))
p = Pool()
for i in range(20):
p.apply_async(proc,("proc{}".format(i),))
p.close() #不让新的进程进来
p.join() #等待池子里的进程都执行完毕
print("执行完毕")
pool可以传入一个整数,用来控制池子的大小,默认值为cpu核心数
subprocess基于多进程技术
import threading #多线程库
import time
def thred():
print('线程{}开始工作'.format(threading.current_thread().name))
time.sleep(5)
print('线程{}结束工作'.format(threading.current_thread().name))
if __name__ == "__main__":
print("主线程{}开始工作".format(threading.current_thread().name))
t1 = threading.Thread(target=thred)
t2 = threading.Thread(target=thred)
t1.start()
t2.start()
t1.join()
t2.join()
print("主线程{}结束工作".format(threading.current_thread().name))
多线程的安全性:
由于线程之间操作数据的顺序是不一致的,在操作共享数据的时候可能会出现问题
解决方法: 锁机制
锁保证了程序执行的顺序,防止多个线程访问公共数据导致数据混乱
但锁会降低多线程性能,极端情况将多线程编程单线程
#锁
import threading
import time
balance = 1000
lock = threading.Lock()
def change(n):
global balance #在函数中,声明调用外部的变量,让函数可用修改外部的变量
balance = balance + n
balance = balance - n
def run(n):
for i in range(10000000):
lock.acquire() #获取锁
try:
change(n)
except Exception as e:
print(e)
finally:
lock.release()
if __name__ == "__main__":
t1 = threading.Thread(target=run,args=(500,))
t2 = threading.Thread(target=run,args=(800,))
t3 = threading.Thread(target=run,args=(100,))
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(balance)
day5 11:00
两个线程,一个数据共享区模拟生产者和消费者模型
一个线程模拟生产者,一个模拟消费者
列表模拟数据共享区
import threading
import time
import random #随机数库
MAX_LEN = 5
buff = []
lock = threading.Lock()
class Produce(threading.Thread):
def run(self):
global buff #全局调用
while True:
lock.acquire() #上锁
if len(buff) < MAX_LEN:
num = random.randint(0,100)
buff.append(num)
print("生产产品.编号:",num)
lock.release()
time.sleep(random.randint(1,5))
class Consumer(threading.Thread):
def run(self):
global buff
while True:
lock.acquire()
if buff:
num = buff.pop(0)
print("消费产品.编号",num)
lock.release()
time.sleep(random.randint(1,5))
if __name__ == "__main__":
p = Produce()
c = Consumer()
#使用守护线程方式
p.setDaemon(True)
c.setDaemon(True)
try:
p.start()
c.start()
p.join()
c.join()
except KeyboardInterrupt:#按下Ctrl+C
print("运行结束")
Python中提供了一个线程安全的类型: queue(队列)
import threading
import time
import random #随机数库
from queue import Queue #队列
MAX_LEN = 5
buff = Queue(MAX_LEN)
class Produce(threading.Thread):
def run(self):
global buff #全局调用
while True:
num = random.randint(0,100)
buff.put(num)
print("生产产品.编号:",num)
time.sleep(random.randint(1,5))
class Consumer(threading.Thread):
def run(self):
global buff
while True:
num = buff.get()
print("消费产品.编号",num)
time.sleep(random.randint(1,5))
if __name__ == "__main__":
p = Produce()
c = Consumer()
#使用守护线程方式
p.setDaemon(True)
c.setDaemon(True)
try:
p.start()
c.start()
p.join()
c.join()
except KeyboardInterrupt:#按下Ctrl+C
print("运行结束")
补充:
协程(微线程):在单线程上实现多线程的效果,切换可控,协程无需锁机制
同步异步(烧开水例子):
具体: ngnix
Python中很不错的第三方库,方便监控的系统很多信息
由于是第三方库,所有需要额外的安装
pip install psutil
conda install psutil
https://psutil.readthedocs.io/en/latest/
import psutil
while True:
print(psutil.cpu_precent(5)) #获取cpu占用率
print(psutil.virtual_memory().total//1024//1024)#查看内存
SMTP协议: 简单邮件传输协议
在Python中自带了smtplib用于处理SMTP协议相关的任务
email是有格式的
在Python中有emil库,用于邮件类型文件的排版
pip install PyEmail
import smtplib
from email.header import Header #邮件主题
from email.mime.text import MIMEText #文本正文
#构造一个邮件
massage = MIMEText("这是一封测试邮件",'plain','utf-8')
massage['Subject'] = Header("Python发邮件","utf-8")
my_mail = "[email protected]"
my_passwd = "fzyqoubngsvsfgbd"
#登录邮箱服务器,然后发送邮件
mail = smtplib.SMTP_SSL('smtp.qq.com') #有ssl安全
mail.connect("smtp.qq.com",465)
mail.login(my_mail,my_passwd)
mail.sendmail("[email protected]",'[email protected]',massage.as_string()) #("发件人",'收件人')
print("邮件发送成功")
用yagmail库发送邮件
pip install yagmail
import yagmail
my_mail = "[email protected]"
my_passwd = "fzyqoubngsvsfgbd"
contents=[
'在吗'
]
mail = yagmail.SMTP(user=my_mail,password=my_passwd,host='smtp.qq.com')
print("链接成功")
mail.send(to="[email protected]",subject="许亚琪",contents=contents)
print("发送成功")
三种版本
Fabric2:现在新版本的产物,可以更好和代码结合(安装时候的默认)
Fabric3:早期产品的python3实现
http://www.fabfile.org/
这个库基于paramiko库(Ansible也基于这个库)
paramiko–python版本的openssh的实现
安装
conda install fabric
pip install fabric
from fabric import Connection
centos = Connection("192.168.199.129",user='root',connect_kwargs={
"password":'0'})
result = centos.run("yum update -y",hide=True,)
print(result.command)
print(result.stdout)
使用windows操作linux
from fabric import Connection
centos = Connection("192.168.199.129",user='root',connect_kwargs={
"password":'1'})
centos.get('/root/Miniconda3-py38.sh') #从服务器上下载文件
centos.put('python.db','/root/code/python.db') #上传文件
with centos.cd("/root/code"): #执行操作,操作结果返回到终端
centos.run("ls -l")
run: 在目标端执行命令
cd: 配合with使用修改工作路径
put:上传文件
get: 下载文件
sudo: 使用管理员身份运行(最好配置sudo免密)
invoke:从早版本的Fabric中脱离出来的一个新项目,用于与shell交互
http://docs.pyinvoke.org/en/latest/api/context.html#invoke.context.Context.sudo
\
day5 15:30
几乎70%的运维平台由django组成
https://docs.djangoproject.com/zh-hans/3.1/ (文档质量较高)
web开发三层架构: MVC
M: 模型层,将数据库中的表抽象成面向对象编程中的类,ORM技术
V:视图层,基于模板引擎(jinja2),渲染显示页面
C: 控制层,用于处理请求
django开发的三层架构:MVT
M = M
V = C
T = V
安装Django
conda install django
pip install django
在安装之后有一条命令可用
django-admin
django-admin startproject pyweb #创建项目
修改settings.py language 为 zh-hans,时区改为上海
切换到项目目录下
执行python manage.py runserver启动服务器
python manage.py runserver 0.0.0.0:8000
ALLOWED_HOSTS = [] 内添加 ‘192.168.199.129’
重启服务器python manage.py runserver
实际开发功能模块都是在项目中创建app
使用python manage.py startapp 文件名 创建app
写一个web站点版本的helloword
pyweb/myapp/views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def hello(request):
return HttpResponse("你好,这是我们创建的web站点")
通过路由指定我们通过什么方式来访问这个方法
pyweb/urls.py
from django.contrib import admin
from django.urls import path
from myapp import views
urlpatterns = [
path('admin/', admin.site.urls),
path("index",views.hello),
]
一般在myapp里创建urls.py
/myapp/urls.py
from django.urls import path
from . import views #.表示自己
urlpatterns = [
path('',views.hello), #''表示所有
]
在此之前需要修改pyweb/urls.py的内容为
from django.contrib import admin
from django.urls import path
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path("index/",include("myapp.urls")),
]
更好的url管理是在项目中将url管理分配到每一个app中单独管理
用ORM操作数据库
pyweb/myapp/models.py
from django.db import models
# Create your models here.
class Log(models, Model):
ip = models.CharField("IP地址", max_length=30)
function = models.TextField("访问情况", max_length=200)
status_code = models.CharField("响应码", max_length=5)
class Meta:
verbose_name = "访问日志"
verbose_name_plural = "访问日志"
#修改表
def __str__(self):
return 'ip: {},访问方式:{},响应码:{}'.format(self.ip, self.function, self.status_code)
使用命令: 进行表数据迁移
利用Django自带的后台管理界面来操作这个数据表
pyweb/myapp/admin.py
from django.contrib import admin
from .models import Log
# Register your models here.
class LogAdmin(admin.ModelAdmin):
list_display = ('ip','function','status_code',)
list_display_links = ('ip','function','status_code',)
admin.site.Register(Log,LogAdmin)
创建一个后台管理员账号
python manage.py createsuperuser
在pyweb/settings.py中 INSTALLED_APPS 里添加’myapp’
python manage.py makemigrations #导入表
python manage.py migrate
开启服务器,访问admin页面
http://49.234.224.134:8000/admin/
添加数据
在my_app/views.py中添加
def add_info(request):
obj = Log(ip='',function='',status_code='').save()
Django: 模型层 的基本使用:定义查询; 能用视图层 对模型层进行增删改查
https://docs.djangoproject.com/zh-hans/3.1/
Django restful: https://www.django-rest-framework.org/
python 的基本库的使用: requests , os , sys , pathlib , shutil , haslib , logging , concurrent.futures(一个库实现多进程多线程)
自动化运维的前提是需要了解运维,
深入学习需要了解一些工具: elk ,ansible , zabbix