文章目录
多进程编程
- windows系统不支持
- 通过os.fork()实现子进程
- os.fork()它的返回值是数字,在父进程中,这个数字是非0值(子进程的pid);在子进程中,值是0
- 多进程编程思路
- 父进程只负责fork子进程
- 子进程做具体的工作
- 子进程工作结束后,务必彻底退出
forking工作原理
什么是forking
进程的生命周期
僵尸进程
- 当子进程没有任何可执行代码后,就变成了僵尸进程
- 短暂存在的程序不需要处理僵尸进程,因为systemd会处理
forking编程
forking编程思路
对于python3
解决zombie问题
import os
import time
print('starting')
rc = os.fork()
if rc:
print('父进程')
# 挂起父进程,处理僵尸进程后才会继续执行
result = os.waitpid(-1, 0) # 处理僵尸进程后的返回值是: (子进程pid, 0)
print(result)
time.sleep(15)
print('父进程结束')
else:
print('子进程')
time.sleep(15)
print('子进程结束')
import os
import time
print('starting')
rc = os.fork()
if rc:
print('父进程')
# 不挂起父进程,如果子进程刚好是僵尸进程,则处理;如果不是,父进程也要继续向下执行
result = os.waitpid(-1, 1) # 子进程不是僵尸进程,返回值是: (0, 0)
print(result)
time.sleep(30)
print('父进程结束')
else:
print('子进程')
time.sleep(15)
print('子进程结束')
forking应用示例
import os
print('starting')
rc = os.fork()
if rc: # 返回值rc是一个数字,非0为真,0为假
print('父进程')
else:
print('子进程')
print('Hello World!')
- ping主机
import subprocess
import time
import os
def ping_pong(ip):
res = subprocess.run('ping -c 2 %s &> /dev/null' % ip,shell=True)
if res.returncode == 0:
print('%s:up' % ip)
else:
print('%s:down' % ip)
if __name__ == '__main__':
host = ['192.168.1.%s' % i for i in range(1, 255)]
print(time.ctime())
for ip in host:
rc=os.fork()
if not rc:
ping_pong(ip)
exit()
print(time.ctime())
多线程编程
- 程序就是存储在磁盘上的一些可执行文件
- 当程序运行时,就会产生一到多个进程。可以认为进程是加载到内存的一系列指令
- 进程之中又可以包含一到多个线程
- 每个进程都拥有自己独立的运行空间
- 所有的线程共享进程的运行空间
- 各种系统都支持多线程
时分复用:将CPU时间分成很多小的片段,叫时间片。每个程序都分得一些时间片,当它的时间片用光了,就要重新排队,等待下一次运行机会。
多线程编程思路:
- 主线程(类似于父进程)只负责生成工作线程(类似于子进程)
- 工作线程做具体的工作
多线程工作原理
多线程的动机
多线程任务的工作特点
什么是进程
什么是线程
多线程编程
多线程相关模块
传递函数给Thread类
传递可调用类给Thread类
多线程ping主机示例
import subprocess
import threading
def ping_pong(ip):
res = subprocess.run('ping -c 2 %s &> /dev/null' % ip,shell=True)
if res.returncode == 0:
print('%s:up' % ip)
else:
print('%s:down' % ip)
if __name__ == '__main__':
host = ['192.168.1.%s' % i for i in range(1, 255)]
for ip in host:
t=threading.Thread(target=ping_pong,args=(ip,))
t.start()
- 使用oop(面向对象编程)ping主机
import subprocess
import time
import threading
class Ping:
def __call__(self, ip):
res = subprocess.run('ping -c 2 %s &> /dev/null' % ip, shell=True)
if res.returncode == 0:
print('%s:up' % ip)
else:
print('%s:down' % ip)
if __name__ == '__main__':
host = ['192.168.1.%s' % i for i in range(1, 255)]
print(time.ctime())
for ip in host:
t = threading.Thread(target=Ping(), args=[ip])
t.start()
print(time.ctime())
import subprocess
import time
import threading
class Ping:
def __init__(self, ip):
self.ip = ip
def __call__(self):
res = subprocess.run('ping -c 2 %s &> /dev/null' % ip, shell=True)
if res.returncode == 0:
print('%s:up' % self.ip)
else:
print('%s:down' % self.ip)
if __name__ == '__main__':
host = ['192.168.1.%s' % i for i in range(1, 255)]
print(time.ctime())
for ip in host:
t = threading.Thread(target=Ping(ip))
t.start()
print(time.ctime())
urllib模块
urllib基础
>>> from urllib import request
>>> html = request.urlopen('http://www.163.com')
>>> html.read(10)
b' <!DOCTYPE'
>>> html.readline()
b' HTML>\n'
>>> html.readlines()
urllib简介
爬取网页
爬取网页示例
import sys
from urllib.request import urlopen
def get_web(url, fname):
html = urlopen(url) #使用urllib模块的urlopen函数打开url,赋值给html
with open(fname, 'wb') as fobj:
while True:
data = html.read(4096)
if not data:
break
fobj.write(data)
html.close()
if __name__ == '__main__':
get_web(sys.argv[1], sys.argv[2]) #让用户在命令行上提供网址和下载数据保存位置
下载网络资源
爬取网站图片示例
import os
import wget
import re
def get_patt(fname, patt, charset=None):
result = []
cpatt = re.compile(patt)
with open(fname, encoding=charset) as fobj:
for line in fobj:
m = cpatt.search(line)
if m:
result.append(m.group())
return result
if __name__ == '__main__':
# 创建下载目录
dst = '/tmp/164'
if not os.path.exists(dst):
os.mkdir(dst)
# 下载首页文件
fname = '/tmp/164/164.html'
url = 'https://www.163.com/'
if not os.path.exists(fname):
wget.download(url, fname)
# 在首页文件中找到所有的图片url
img_patt = '(http|https)://[\w._/-]+\.(jpg|png|jpeg|gif)'
img_list = get_patt(fname, img_patt, 'gbk')
# 下载图片
for img_url in img_list:
wget.download(img_url, dst)
修改请求头
>>> js_url = 'http://www.jianshu.com'
>>> html = request.urlopen(js_url) # 403错误
# 因为简书有基本的反爬虫功能,发现是机器爬虫程序,就拒绝
>>> js_url = 'http://www.jianshu.com'
>>> headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0'}
# 创建一个请求对象,访问简书服务器时,携带修改的请求头发请求
>>> r = request.Request(js_url, headers=headers)
>>> html = request.urlopen(r)
url编码
- URL中,只允许一部分ascii码字符
- 如果使用其他字符,需要转码
>>> url = 'https://www.sogou.com/web?query=北京'
>>> html = request.urlopen(url) # 报错,url中含中文
>>> url = 'https://www.sogou.com/web?query=' + request.quote('武汉')
>>> url
'https://www.sogou.com/web?query=%E6%AD%A6%E6%B1%89'
异常处理
- urllib模块的子模块error定义了可能出现的异常
- 所以在捕获异常时,需要将它导入
>>> js_url = 'http://www.jianshu.com'
>>> from urllib import error
>>> try:
... html = request.urlopen(js_url)
... except error.HTTPError:
... print('无法访问')
...
无法访问
处理下载错误示例
起动一个web服务
在web服务器的文档目录下创建目录ban,权限设置为700
编写python程序访问不存在的路径和ban目录,处理404和403错误
404错误打印“无此页面”,403错误打印“无权访问”
步骤一:启动一个web服务
[root@localhost ~]# systemctl restart httpd
步骤二:在web服务器的文档目录下创建目录ban,权限设置为700
[root@localhost ~]# mkdir -m 700 /var/www/html/ban
步骤三:如果访问的页面不存在或拒绝访问,程序将抛出异常
执行案例2中get_web.py文件,访问不存在页面,抛出404异常如下:
[root@localhost day11]# python3 get_web.py http://127.0.0.1/abc/ /tmp/abc.html
Traceback (most recent call last):
...
...
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 404: Not Found
执行案例2中get_web.py文件,访问存在页面ban目录,抛出403权限异常如下:
[root@localhost day11]# python3 get_web.py http://127.0.0.1/ban/ /tmp/abc.html
Traceback (most recent call last):
...
...
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden
步骤三:编写python程序捕获异常
创建get_web3.py文件,实现访问不存在的路径和ban目录时,捕获404和403错误
,同时404错误打印“无此页面”,403错误打印“无权访问”,代码如下:
import sys
from urllib.request import urlopen
from urllib.error import HTTPError #导入urllib.error模块,用HTTPError捕获异常信息
def get_web(url, fname):
try:
html = urlopen(url) #打开网址时即可知道是否有异常,所以将本语句放入try语句
except HTTPError as e: #捕获返回HTTPError类的实例e
print(e)
if e.code == 403: #捕获异常状态码如果等于403
print('权限不足') #输出'权限不足'
elif e.code == 404: #捕获异常状态码如果等于404
print('没有那个地址') #输出'没有那个地址'
return #return后面代码均不执行
with open(fname, 'wb') as fobj:
while True:
data = html.read(4096)
if not data:
break
fobj.write(data)
html.close()
if __name__ == '__main__':
get_web(sys.argv[1], sys.argv[2])
测试脚本执行:
访问不存在页面:
[root@localhost day11]# python3 get_web.py http://127.0.0.1/abc/ /tmp/abc.html
HTTP Error 404: Not Found
没有那个地址
访问ban目录:
[root@localhost day11]# python3 get_web.py http://127.0.0.1/ban/ /tmp/abc.html
HTTP Error 403: Forbidden
权限不足
paramiko模块
基础使用说明
paramiko实现的是ssh功能
# 本地安装
yum install -y gcc gcc-c++ python-devel
tar -xf paramiko-1.15.4.tar.gz
python3 setup.py install
# 在线安装
[root@localhost day02]# pip3 install paramiko
>>> import paramiko
>>> ssh = paramiko.SSHClient() # 创建客户端实例
# 设置自动接受密钥
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 登陆服务器
>>> ssh.connect('192.168.113.133', username='root', password='redhat')
# 执行命令
>>> result = ssh.exec_command('id root; id dingjie')
>>> len(result)
3
# 执行命令的返回值是一个3元素元组。这3项分别是输入、输出和错误的类文件对象。类文
件对象提供了read方法,可以读取其中的内容
>>> stdin, stdout, stderr = ssh.exec_command('id root; id dingjie')
>>> out = stdout.read()
>>> err = stderr.read()
>>> out
b'uid=0(root) gid=0(root) \xe7\xbb\x84=0(root)\n'
>>> err
b'id: dingjie: no such user\n'
>>> ssh.close() # 关闭
>>> out.decode() # 将bytes类型转为str类型
'uid=0(root) gid=0(root) 组=0(root)\n'
paramiko示例
- 使用多线程ssh连接主机执行命令
import paramiko
import sys
import getpass
import os
import threading
def rcmd(host, user, passwd, port=22, cmds=None):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=user, password=passwd, port=port)
stdin, stdout, stderr = ssh.exec_command(cmds)
out = stdout.read()
err = stderr.read()
if out: # 如果命令有输出
print('[%s] \033[32;1mOUT\033[0m:\n%s' % (host, out.decode()))
if err: # 如果命令执行错误
print('[%s] \033[31;1mERROR\033[0m:\n%s' % (host, err.decode()))
ssh.close()
if __name__ == '__main__':
if len(sys.argv) != 3:
print("Usage: %s ipfile 'commands'" % sys.argv[0])
exit(1) # 1就是$?值
if not os.path.isfile(sys.argv[1]):
print('No such file:', sys.argv[1])
exit(2)
ipfile = sys.argv[1]
passwd = getpass.getpass()
cmds = sys.argv[2]
with open(ipfile) as fobj:
for line in fobj:
ip = line.strip() # srtip()字段去除前后的空格,文件每一行是一个ip地址,但是要去除行尾的\n
t = threading.Thread(target=rcmd, args=(ip, 'root', passwd, 22, cmds))
t.start()
# python3 rcmd.py servers.txt 'sleep 3; id root'