网络
-
理论模型,分为七层
- 物理层
- 数据链路层
- 传输层
- 会话层
- 表示层
- 应用层
-
实际应用,分为四层
- 链路层
- 网络层
- 传输层
- 应用层
-
IP地址
-
IPV4 地址族,4个字段组成,每个字段取值0-255
局域网IP,
192.168.XXX,XXX
本机本地地址,
127.0.0.1
IPV6 地址族,8个字段组成,每个字段取值0000-FFFF
-
-
端口
设备上每个应用需要与外界通信的地址
范围是 0-65535
知名端口 0-1023
非知名端口 1024-65535
-
套接字
我理解的套接字相当于与电话,而人则代表每个设备;当两个人需要通信时,需要电话.这就是套接字,而知道电话是不够的,还需要知道电话号码,这样才能确保电话打到你想通话的哪个人去
套接字对象由addr(host,port)地址定义,host是IP地址,port代表端口
host主要用来确定是IP地址为哪一个的电脑
port主要用来确定是该电脑上的哪个软件
-
域名
网络上计算名,或计算机组的名称
-
浏览器根据域名来查找对应的IP地址
查找本地hsot文件,检查是否有对应的IP地址
如果没有,查找本地DNS服务器.也就是运营商,检查是否有对应的IP
如果没有,本地DNS服务器查找根DNS服务器,检查是否有对应的IP
如果没有,根DNS服务器返回消息给本地DNS服务器,让其到域服务器查找IP
-
DNS 域名服务器系统
DNS将域名映射到对应的IP地址
-
DNS查询
- 递归查询
- 迭代查询
-
DNS 负载均衡
- 在DNS服务器中,为域名配置多个IP地址,根据距离远近,使用距离较近的IP
socket 库
-
协议家族
-
基于文件
- AF_UNIX 同台机器进程之间的通行
-
基于网络
AF__INET IPV4协议
AF_INET6 IPV6协议
-
-
网络协议
SOCK_STREAM
TCP协议 , 连接的套接字,只有当服务器与客户端连接后,才开始传输数据,可以确定数据的先后,也可以确定对方一定能接收到消息SOCK_DGRAM
UDP协议 , 无连接的套接字,服务器不断的监听某个套接字,从这个套接字获取或者发送数据,无法确定数据的先后顺序,也无法确定对方是否收到消息
-
直接调用的函数
getfqdn(name)
返回name的域名gethostbyname(hostname)
返回主机名的IPV4地址gethostname()
返回正在执行当前解释器的机器的主机名sethostname(name)
将本机主机名设置为name
-
socket(family,type)
套接字对象类-
函数
-
通用函数
bind(addr)
服务器绑定套接字,addr为(host,port)shuntdown()
关闭连接setblocking(boolean)
设置是否为阻塞模式-
settimeout(second)
设置超时时间-
None
阻塞模式 -
0
非阻塞模式 -
非0值
在规定时间后抛出异常
-
close()
关闭套接字
-
TCP 函数
listen()
监听地址,阻塞式的,不断循环监听地址accept()
服务器接收TCP客户端连接,返回新的连接的套接字和客户端的地址send(data)
发送数据sendall(data)
发送所有数据-
recv(bufsize)
接收TCP指定字节数的数据,一旦超过指定字节,就需要使用循环接收的方式接收完整的数据短链接法,发送数据完毕后关闭连接,让
recv()
函数获取连接关闭后自动取消阻塞模式末尾标志法,在末尾添加相应哨兵值,在
recv()
函数接收到哨兵值之后跳出接收数据的死循环,进行下一步操作负载长度法,提前告知长度,后根据长度判断是否跳出接收数据的死循环
connect(addr) 发起连接,向addr(host,port)发起连接
# 设置TCP服务器 import socket,time server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind(('127.0.0.1',12345)) server.listen() con,addr = server.accept() data = con.recv(1024) text = data.decode() print(text) data = '{0} : {1}'.format(time.ctime(),text).encode() con.sendall(data) con.close() server.close() # 设置TCP客户端 import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',12345)) text = 'Hello' client.sendall(text.encode()) data = client.recv(1024) print(data.decode()) client.close()
-
UDP 函数
recvfrom(bufsize)
接收UDP消息,返回连接的套接字地址sendto(data,addr)
将data数据发送到指定addr地址
# 设置UDP服务器 import socket,time server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) server.bind(('127.0.0.1',12345)) data,addr = server.recvfrom(1024) text = data.decode() print(text) server.sendto('{0} : {1}'.format(time.ctime(),text).encode(),addr) server.close() # 设置UDP客户端 import socket client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) text = 'Hello' client.sendto(text.encode(),('127.0.0.1',12345)) data,addr = client.recvfrom(1024) print(data.decode())
-
-
socketserver 网络服务器框架模块
此模块提供网络服务器框架,可以使开发者更加快捷的开发出相应的网络服务器
-
服务器server对象
-
BaseServer(server_address,RequestHandlerClass)
所有Server对象的超类,同步处理请求,只有当一个请求处理完成之后才能处理下一个请求,每次只能完成一个请求RequestHandlerClass
处理请求类get_request()
接收客户端请求,并返回一个和客户端连接的套接字和客户端地址组成的元组server_bind(addr)
绑定地址serve_forever()
永远处理请求shutdown()
停止处理请求server_close()
关闭服务器
TCPServer (server_address,RequestHandlerClass)
继承于BaseServer,完善了TCP的相关方法,用于TCP服务器的创建,需要重写RequestHandlerClass
# 改写的上面采用socket库编写的TCP服务器 import socketserver,time class Server(socketserver.TCPServer): pass class MyRequestHandler(socketserver.StreamRequestHandler): def handle(self): data = self.request.recv(1024) text = data.decode() print(text) data = '{0} : {1}'.format(time.ctime(),text).encode() self.request.sendall(data) server = Server(('127.0.0.1',12345),MyRequestHandler) server.serve_forever() # 客户端 import socket with socket.socket(socket.AF_INET,socket.SOCK_STREAM)as client: client.connect(('127.0.0.1',12345)) client.sendall('hello'.encode()) data = client.recv(1024) print(data.decode())
-
UDPServer (server_address,RequestHandlerClass)
继承于BaseServer,完善了TCP的相关方法,用于UDP服务器的创建,需要重写RequestHandlerClass
# 服务器端 import socketserver,time class Server(socketserver.UDPServer): pass class MyRequestHandler(socketserver.DatagramRequestHandler): def handle(self): data,con = self.request print(data.decode()) data = '{0} : {1}'.format(time.ctime(),data.decode()).encode() con.sendto(data,self.client_address) server = Server(('127.0.0.1',12345),MyRequestHandler) server.serve_forever() # 客户端 import socket with socket.socket(socket.AF_INET,socket.SOCK_DGRAM)as client: data = 'hello'.encode() client.sendto(data,('127.0.0.1',12345)) data = client.recv(1024) print(data.decode())
-
适用于Unix平台的服务器,
UnixStreamServer (server_address,RequestHandlerClass)
UnixDatagramServer (server_address,RequestHandlerClass)
-
-
扩展功能的Mixin类
ForkingMixIn
多进程MIXIN类 ,可以与其他Server对象进行组合,适用于Linux 平台ThreadingMixIn
多线程MIXIN类,可以与其他Server对象进行组合
-
模块中已组合的扩展功能的服务器Server类
ForkingTCPServer(server_address,RequestHandlerClass)
多进程TCP服务器类,ForkingMixIn与TCPServer的组合ForkingUDPServer(server_address,RequestHandlerClass)
多进程UDP服务器类,ForkingMixIn与UDPServer的组合ThreadingTCPServer(server_address,RequestHandlerClass)
多线程TCP服务器类,ThreadingMixIn与TCPServer的组合ThreadingUDPServer(server_address,RequestHandlerClass)
多线程UDP服务器类,ThreadingMixIn与UDPServer的组合
-
请求处理类
-
BaseRequestHandler
处理请求类,其中定义了三个方法:setup
、handle
、finish
,都默认什么都不做,需要进行重写才能使用,是其他处理请求类的超类setup()
在handle方法之前调用的操作-
handle()
处理客户端请求的方法-
self.request
在不同Server服务器对象中具有不同的含义在TCPServer中,返回的是连接的客户端的套接字
在UDPServer中,返回的数据和连接的客户端套接字的一个元组
self.client_address
返回连接的客户端的地址self.rfile
可以从此属性中读取客户端发送的数据self.wfile
可以从此属性中写入服务器发给客户端的数据
-
finish()
在handle方法之后调用的操作
StreamRequestHandler
TCP处理请求类,是BaseRequestHandler
的子类,实现了关于TCP的相关方法,但需要实现handle
方法DatagramRequestHandler
UDP处理请求类,是BaseRequestHandler
的子类,实现了关于UDP的相关方法,但需要实现handle
方法
-
ftplib 模块
FTP (FileTransferProtocal) 文件传输协议
-
用户
Real账户 注册账户
Guest账户 临时账户
Anonymous 匿名账户
-
端口
21
端口为控制和命令端口20
端口为数据端口
-
FTP(host,usr,passwd)类
可以使用上下文管理协议 即
with
语句connect(host,port)
当没有在实例化FTP定义host时,则需要调用connect函数指定host和portlogin(usr,passwd)
给定账号密码登录,默认usr为anonymous,密码为anonymous@abort()
中断传输的文件sendcmd(cmd)
向服务器发送字符串命令,并返回响应代码retrbinary(cmd,callback)
以二进制形式接收文件,callback为用于接收文件的回调函数storbinary(cmd,fp)
以二进制形式上传文件,fp为二进制流retrlines(cmd,callback)
文本形式接收文件storlines(cmd,fp)
文本形式上传文件nlst()
返回文件名列表dir()
输出文件名列表到sys.stdoutrename(old,new)
重命名delete(filename)
删除文件pwd()
返回当前目录路径cwd(path)
将path设置为当前路径mkd(path)
创建新目录rmd(dirname)
删除dirname目录size(file)
返回文件大小quit()
关闭连接
import ftplib
#定义回调函数,将retrbinary函数接收到的数据写入本地文件中
def file(data):
with open(r'1.txt','wb')as f:
f.write(data)
# 指定FTP的host,获得套接字连接
con = ftplib.FTP('ftp.acc.umu.se')
# 连接FTP服务器
con.connect()
# 匿名账户登录
con.login()
con.dir()
# 下载文件,并调用file函数,将数据写入本地文件
con.retrbinary('RETR robots.txt',file)
# 关闭连接
con.close()
email 电子邮件模块
-
邮件传输模式
MUA 客户端程序
MTA (Mail Transfer Agent) 邮件传输代理,将发件人的邮件传输到发件人邮箱所在的服务器
MDA (Mail Delivery Agent) 邮件投递代理,发件人邮箱所在的服务器将邮件传输到收件人邮箱所在的服务器
MRA (Mail retrieva Agent) 邮件获取代理,收件人邮箱所在的服务器将邮件获取到收件人的邮箱地址中去
-
邮件传输使用MIME协议(多用途互联网邮件扩展),即电子邮件需要符合相应的MIME格式,才能进行发送
MIME协议中包括邮件标头、邮件消息体两个部分
邮件标头是key-value形式的字符串,每个标头独占一行
-
标头属性
-
From
发件人地址 -
To
收件人地址 -
Cc
抄送地址 -
Subject
主题 -
Content-Type
邮件体中包含的内容类型 -
Content-Disposition: "attachment;filename='name.type'"
设置附件的下载方式和显示名称,其中attachment为附件方式打开,inline在邮件中打开
-
标头后跟着空行,下面为邮件消息体
消息体为邮件的具体内容
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
From: mine<xxxx@163.com>
To: you<xxx@qq.com>
Subject: =?utf-8?b?6YKu5Lu25qCH6aKY?=
6L+Z5piv5LiA5Lu95paH5pys5raI5oGv6YKu5Lu2
-
mime
构造邮件消息模块每个MIME类型的邮件消息对象只需要添加标头就可以作为邮件进行发送
multipart.MIMEMultipart(subtype ='mixed',boundary = None,spartparts = None,policy = compat32)
构造多个消息组成的总消息application.MIMEApplication(data,subtype = '八位字节流',encoder = email.encoders.encode_base64)
构造MIME邮件的Application消息audio.MIMEAudio(audiodata,subtype = None,encoder = email.encoders.encode_base64)
构造MIME邮件的Audio消息image.MIMEImage(imagedata,subtype = None,encoder = email.encoders.encode_base64)
构造MIME邮件的Image消息text.MIMEText(text,subtype ='plain',charset = None,*,policy = compat32)
构造一个MIME邮件的文本消息
-
message
邮件消息操作模块-
EmailMessage
类- 同下
-
Message
类as_string()
将消息对象作为字符串返回as_bytes()
将消息对象作为二进制流返回attach(message)
将message消息对象添加到当前消息对象items()
返回消息字段标题和值的元组的列表add_header(name,value)
添加邮件标头
get_payload(i=None, decode=False)
返回邮件消息中每行内容所组成的列表,选择是否解码,一般需要填入Truewalk()
迭代器,迭代邮件消息的每一行
-
-
header
构造邮件标头模块Header(str=None,charset=None,header_name = NONE)
类 创建符合MIME协议的标头-
邮件标头可以通过两种方式进行构造
- 使用Header类进行构造,使用消息对象的属性进行赋值
msg['From'] = Header('xxxx@xx.com')
-
add_header(name,value)
函数,使用消息对象的函数进行赋值
msg.add_header('From','xxxx@xx.com')
-
邮件头的解码
-
decode_header(_header)
解码标头值,返回(decode_string,charset)组成的元组的列表
-
-
parse 邮件解码模块
-
BytesParser
二进制数据解析类parse(fp,headersonly = False )
解析二进制流,生成消息对象parsebytes(bytes,headersonly = False )
解析二进制数据,生成消息对象BytesHeaderParser()
解析标头二进制数据,返回标头对象
-
Parser
文本解析类parse(fp,headersonly = False )
解析文本流,生成消息对象parsestr(text,headersonly = False )
解析字符串,生成消息对象HeaderParser()
解析标头文本数据,返回标头对象
-
-
email模块下直接使用的解析类
message_from_bytes(s,_class = None,*,policy = policy.compat32 )
从二进制数据返回消息对象message_from_binary_file(fp,_class = None,*,policy = policy.compat32 )
从二进制流返回消息对象message_from_string(s,_class = None,*,policy = policy.compat32 )
从字符串返回消息对象message_from_file(fp,_class = None,*,policy = policy.compat32 )
从文本流中返回消息对象
smtplib SMTP简单邮件发送协议模块
SMTP 是负责邮件发送的协议
-
SMTP(host,port)
未加密的SMTP类可以使用上下文管理协议,即
with
语句connect(host,port)
连接到邮件服务器login(usr,pwd)
登录sendmail(from_addr,to_addr,msg)
发送邮件 msg为字符串,也就是需要通过消息对象调用as_string()方法quit()
关闭连接
-
SMTP_SSL(host,port)
ssl加密的SMTP类- 方法同上
-
发送一封纯文本格式的邮件
import smtplib from email.mime.text import MIMEText usr = 'xxx@163.com' pwd = 'xxxxx' to_mail = 'xxxxx@qq.com' # 构造文本消息邮件 msg = MIMEText('这是一份文本消息邮件') # 添加标头,使之变为邮件 msg['From'] = 'mine<{0}>'.format(usr) msg['To'] ='you<{0}>'.format(to_mail) msg['Subject'] = '邮件标题' # 发送邮件 with smtplib.SMTP()as con: # 变为debug模式,输出信息到控制台 con.set_debuglevel(1) # 连接邮件服务器 con.connect('smtp.163.com',25) # 登录 con.login(usr,pwd) # 发送邮件 con.sendmail(usr,to_mail,msg.as_string())
-
发送一封html格式的邮件
import smtplib from email.mime.text import MIMEText usr = 'xxx@163.com' pwd = 'xxxxx' to_mail = 'xxxxx@qq.com' # 构造html content ="<html><h1>这是一封html邮件</h1></html>" # 构造文本消息邮件 msg = MIMEText(content,'html','utf-8') # 添加标头,使之变为邮件 msg['From'] = 'mine<{0}>'.format(usr) msg['To'] ='you<{0}>'.format(to_mail) msg['Subject'] = '邮件标题' # 发送邮件 with smtplib.SMTP()as con: # 变为debug模式,输出信息到控制台 con.set_debuglevel(1) # 连接邮件服务器 con.connect('smtp.163.com', 25) # 登录 con.login(usr, pwd) # 发送邮件 con.sendmail(usr, to_mail, msg.as_string())
-
发送一封带有附件的邮件
import smtplib from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.text import MIMEText usr = 'xxx@163.com' pwd = 'xxxxx' to_mail = 'xxxxx@qq.com' file = r'C:\Users\wudiz\Desktop\BaseServer.png' # 构造文本消息邮件 msg = MIMEMultipart('组合邮件') # 添加标头,使之变为邮件 msg['From'] = 'mine<{0}>'.format(usr) msg['To'] ='you<{0}>'.format(to_mail) msg['Subject'] = '邮件标题' # 构造文本 text = MIMEText('这是一封组合邮件') # 添加到msg组合消息对象中 msg.attach(text) # 构造附件 data = MIMEApplication(open(file,'rb').read()) # 添加MIME类型 data.add_header('Content-Type','application/octet-stream') # 设置附件 data.add_header('Content-Disposition',"attachment;filename='1.png'") # 添加到msg组合消息对象中 msg.attach(data) # 发送邮件 with smtplib.SMTP()as con: # 变为debug模式,输出信息到控制台 con.set_debuglevel(1) # 连接邮件服务器 con.connect('smtp.163.com', 25) # 登录 con.login(usr, pwd) # 发送邮件 con.sendmail(usr, to_mail, msg.as_string())
poplib 邮局协议模块
POP3 (Post Office Protocol - Version 3) 邮局协议版本3
-
POP3(host,port)
非加密POP3协议类set_debuglevel(1)
设置为调试模式stls()
以tls验证服务器getwelcome()
返回服务器的问候语字符串capa()
查询服务器的功能user(usr)
发送用户名pass_(pwd)
发送密码apop(usr,pwd)
使用APOP身份验证登录邮箱rpop(usr,pwd)
使用RPOP身份验证登录邮箱stat()
获取邮箱状态,返回(message_count,mailbox_size)的元组list(num)
获取邮件列表,如果设置了数字,则为数字所在编号邮件的内容,返回(response,num,octets)组成的元组 response为响应代码,num为邮件数量,octets为邮件大小retr(num)
检索邮件号,返回(response,lines,octets)组成的元组 lines为邮件每行组成的一个二进制列表,需要将其每个一行的组合起来才能变成二进制邮件,二进制邮件解码才能变为邮件dele(num)
标记邮件号,退出登录后删除rset()
立即删除标记的邮件号quit()
关闭连接
-
POP3_SSL(host,port)
SSL加密POP3协议类- 方法同上,现在一般使用该类
import poplib import email.header # 指定连接POP3服务器的host和port con = poplib.POP3('pop3.163.com',110) con.set_debuglevel(1) con.user('xxx') con.pass_('xxx') print(con.getwelcome()) # 选定邮箱中的第三封邮件 list = con.retr(3) # 设置二进制对象 data = b'' # 将二进制邮件的每一行写入data中,构建完整的邮件,按每行进行写入 for i in list[1]: data = data + i + b'\r\n' con.quit() # 解析为MIME消息对象 mail = email.message_from_bytes(data) # 解析标头中的标题 subject = email.header.decode_header(mail.get('Subject')) # 解码Subject标头值的字符串,并打印 print(subject[0][0].decode(subject[0][1])) # 按base64解码消息中的内容 content = mail.get_payload(decode=True) # 按UTF-8解码内容 print(content.decode())
http 超文本传输协议模块
-
http协议 是Hyper Text Transfer Protocol的缩写,简称为超文本传输协议
HTTP 的默认端口为80
HTTPS的默认端口为443
永远是客户端先发起请求,然后服务器响应请求
-
工作模式
-
建立连接
- 需要进行三次握手
- 客户端发送一个请求给服务端要求建立连接,进入等待状态(SYN_SEND)
- 服务端同意连接,发送一个响应给客户端,进入等待状态(SYN_SEND)
- 客户端接收这个响应,并与之建立连接(ESTABLISHED)
- 需要进行三次握手
接收数据
结束连接
-
-
请求报文
Request
[图片上传失败...(image-49e11e-1536041654038)]
-
请求行包括了请求方法,请求的url和http版本
-
请求方法
POST
向服务器提交数据 改GET
请求数据 查PUT
向服务器上传数据 增DELETE
请求服务器删除相应数据 删
-
-
请求头是key-value形式的,其中有以下属性
-
Host
请求资源的主机地址(必须存在) -
User-Agent
客户端的浏览器类型和版本 -
Accept-Language
客户端申明自己接收的语言 -
Accept
客户端申明自己想要接收数据的类型- gzip
- deflate
-
Accept-Encoding
客户端申明自己接收的编码,通常指定压缩方法 -
Cookie
发送cookie值 -
Connection
连接方式-
keep-alive
持久连接,当访问网页后连接不会关闭 -
close
短连接,访问后就关闭,下次建立新的连接
-
-
Keep-Alive
保持连接的时间 -
Referer
表示用户从该网页访问服务器 -
Date
此报文产生的日期 -
Authorization
客户端权限
-
空行,请求头和请求体之间必须有一个空行
请求体
-
-
响应报文
Response
[图片上传失败...(image-8a1169-1536041654038)]
-
响应行,包括了服务器软件的版本号,返回的状态码和相应短语
- 1XX 服务器已接收请求,继续处理
- 2XX 服务器请求已被处理
- 3XX 重定向
- 4XX 客户端错误
- 5XX 服务器错误
-
响应头
-
Location
重定向到另一个位置 -
Server
服务器软件 -
Date
此报文产生的日期 -
Content-Length
响应体的长度 -
Content-Type
声明发送响应体的类型和编码
-
空行
响应体,也就是服务器返回的请求资源
-
-
client
HTTP客户端模块模块-
HTTPConnection(host,port = None)
使用http协议连接服务器,返回一个HTTPConnection对象request(method,url,body = None,headers = {})
向服务器发送请求getresponse()
返回服务器相应set_debuglevel(1)
设置调试,将输出打印到控制台close()
关闭连接
-
HTTPSConnection(host,port = None)
使用https协议简介服务器,返回一个HTTPSConnection对象- 同上
-
HTTPResponse
对象read()
读取响应内容getheaders()
返回(属性,值)组成的元组列表getheader(name)
返回属性为name的值version
返回协议版本status
返回状态码
from http.client import * con = HTTPConnection('www.baidu.com') con.set_debuglevel(1) con.request('GET','http://www.baidu.com') response = con.getresponse() print(response.read()) response.close() con.close()
-
-
server
HTTP服务器模块-
服务器框架,此模块继承于socketserver.TCPServer
HTTPServer(server_address,RequestHandlerClass )
ThreadingHTTPServer(server_address,RequestHandlerClass )
-
处理HTTP请求类
-
BaseHTTPRequestHandler(request,client_address,server )
处理http请求的基本类command
请求形式path
请求的urlrequest_version
请求的http版本headers
请求报文的标头rfile
读取流wfile
写入流-
protocol_version
设置http版本协议默认为HTTP/1.0 短连接
HTTP/1.1 持久连接
send_response(code, message=None)
将响应状态码添加到缓冲区send_header(keyword, value)
将响应头添加到缓冲区end_headers()
发送空行version_string()
返回服务器软件的版本号date_time_string()
返回当前时间address_string()
返回呼叫的客户端地址
# 使用BaseHTTPRequestHandler创建HTTP服务器 from http.server import * html = ''' <html> <head> <title>Server</title> </head> <body> hello Python! </body> </html> ''' class myhttpserver(HTTPServer): pass class myhttphandler(BaseHTTPRequestHandler): def do_GET(self): url = self.path print(url) self.send_response(200) self.send_header('Hello','from server s welcome') self.end_headers() self.wfile.write(html.encode()) server = myhttpserver(('127.0.0.1',8888),myhttphandler) server.serve_forever() # 现在使用http://127.0.0.1:8888/打开网站吧
-
SimpleHTTPRequestHandler(request,client_address,server,directory = None )
普通HTTP请求处理类-
除了和
BaseHTTPRequestHandler
函数一致时,还另外定义了directory
属性,do_HEAD()
,do_GET()
方法directory
属性: 如果未指定,则代表提供的文件的目录是当前目录do_HEAD()
默认给定Server, Date, Connection, Content-Type, Content-Length, Last-Modified的标头do_GET()
如果代码所在位置有index.html,则会发送这个网页给客户端,否则将建立一个基于当前目录的类似于FTP的服务器
-
-
# 类似于FTP服务器 from http.server import * class myhttpserver(HTTPServer): pass class myhttphandler(SimpleHTTPRequestHandler): pass server = myhttpserver(('127.0.0.1',8888),myhttphandler) server.serve_forever() # 使用index.html # 在代码所在目录编写index.html文件 ''' <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>My Page</title> </head> <body> <h1>Hello Python3!</h1> </body> </html> ''' # 再次运行服务器,使用浏览器访问,即可以查看结果
-
CGIHTTPRequestHandler(request,client_address,server )
调用CGI程序处理请求修改了
SimpleHTTPRequestHandler
定义的do_GET和do_HEAD方法,更改为使用CGI程序输出的方法 如果没有CGI程序,就会像SimpleHTTPRequestHandler
一样,建立一个类似于FTP的服务器cgi_directories
包含CGI程序的目录,默认为当前目录下的['/cgi-bin', '/htbin']do_POST()
定义了POST方法,允许客户端发送信息到服务器得CGI程序中,如果POST到非CGI程序上,会提示501错误
# 先定义一个能POST请求的html页面,命名为index.html ''' <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>请输入文字</h1> <form action="http://127.0.0.1:8888/cgi-bin/cc.py" method="post" id="myform"> <p><input type="text" name="text"></p> </form> <button type="submit" form="myform">发送</button> </body> </html> ''' # CGI服务器 from http.server import * class myhttpserver(HTTPServer): pass class myhttphandler(CGIHTTPRequestHandler): pass server = myhttpserver(('127.0.0.1',8888),myhttphandler) server.serve_forever() # 编写CGI程序,放入cgi-bin目录下 import cgi import cgitb cgitb.enable() html = ''' <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>你提交的是:</h1> <h2>{0}</h2> </body> </html> '''.format(cgi.FieldStorage().getfirst('text')) print(html) # 运行程序,会输出你在页面上输入的信息
-
-
cookies HTTP状态管理,主要用于服务器端创建cookie
-
Netscape形式的cookie :
Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
- NAME为该cookie的名称,为必填选项
- Expires为该cookie的终止日期 形式为
星期几,DD-MM-YY HH:MM:SS GMT
,GMT表示格林尼治时间,如不填该cookie不会保存在硬盘中,该cookie随着浏览器的关闭消失 - Domain为该cookie的作用域,如果不填,则为该服务器的域名
- Path为该服务器下那些页面可以获取该cookie,填'/'为该服务器下所有页面
- 加密协议,当前只有一种,即HTTPS
-
RFC2109中定义的cookie :
Set-Cookie: Name = Value; Comment = value; Domain = value; Max-Age = value; Path = Value;Secure; Version = 1 * DIGIT;
- NAME必须为一个JSESSIONID,必填
- Domain为该cookie的作用域,必须以
.
开始 - Max-Age为该cookie的生存时间,以秒为单位
- Secure必填
-
BaseCookie(input) 类
该类用于创建cookie,是一个类似于字典的对象,每向其中添加一个key,value值就会创建一个
Set-Cookie: key:value
的响应头信息,其中key必须是一个字符串,value是一个Morsel对象,可以向其中添加其他头信息操作-
定义的方法:
-
value_decode(val )
待续 -
value_encode(val )
待续 -
output(attrs = None,header ='Set-Cookie:',sep ='\ r \ n' )
将cookie对象作为符合html标准的字符串输出 -
load(rawdata )
将接收到的字符串对象解析为cookie
-
-
SimpleCookie(input) 类
- BaseCookie的子类,重写实现了value_decode,value_encode方法
-
Morsel 类
-
常用常量
- expires
- path
- comment
- domain
- max-age
- secure
- version
- httponly
-
常用方法
-
set(key,value,coded_value )
添加key,设置value值 -
output(attrs = None,header ='Set-Cookie:' )
作为html形式输出 -
update(dict)
将字典中的key和value添加到对象中
-
-
-
# 创建一个cookie,使用了几种不同的方式
from http.cookies import *
cookie = SimpleCookie()
cookie["name"] = "mycookie"
dict = {'path':'/','comment':'这是cookie'}
cookie['name'].update(dict)
cookie['name']['domain'] = '127.0.0.1'
cookie['whatever'] = 'i dont know'
print(cookie)
-
cookiejar 持久化的cookie操作模块,主要用于客户端的操作,如爬虫
具体应用在urllib模块中
-
CookieJar 类,该类用来操作储存在内存中的cookie
MozillaCookieJar(filename,delayload = None,policy = None )
类 可以从加载和保存的Cookie到磁盘Mozilla的cookies.txtLWPCookieJar(filename,delayload = None,policy = None )
类 可以从加载和cookie保存到磁盘与的libwww-perl的库的兼容格式Set-Cookie3的文件格式add_cookie_header(requst)
向request对象中添加一个cookie对象extract_cookies(response,request)
从http的response中提取cookie并储存在cookieJar对象中make_cookies(response,request)
从http的response中提取cookieset_cookie(cookie)
向cookieJar添加cookie对象clear(keys)
清除名为key的cookie参数
# 获取cookie from urllib.request import * from http.cookiejar import * url = 'http://www.baidu.com' headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36' } request = Request(url=url, headers=headers) response = urlopen(request) cookie = CookieJar() cookie.extract_cookies(response,request) print(cookie)
-
FileCookieJar 类,该类主要用于操作已经持久到文件中的cookie
具有以上CookieJar的所有函数之外,额外添加了以下函数
filename
默认保存cookie的文件save(filename = None,ignore_discard = False,ignore_expires = False )
将cookie保存在文件中,方法未实现,但是在CookieJar的子类LWPCookieJar
,MozillaCookieJar
实现了其方法load(filename = None,ignore_discard = False,ignore_expires = False )
从文件中加载cookierevert(filename = None,ignore_discard = False,ignore_expires = False )
清除所有cookie,并从文件中重新加载cookie
# 以LWPCookieJar为例,将cookie保存到文件中 from urllib.request import * from http.cookiejar import LWPCookieJar url = 'http://www.baidu.com' headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36' } request = Request(url=url, headers=headers) response = urlopen(request) filecookie = LWPCookieJar() filecookie.extract_cookies(response,request) filecookie.save(r'a.txt')
cgi 通用网关接口支持模块、cgitb CGI脚本的回溯管理器模块
cgitb用于调试cgi脚本程序
- enable() 将错误信息输出到访问的html页面
cgi是服务器运行时调用的外部程序,通过通用CGI接口与服务器通信,默认放在['/cgi-bin', '/htbin']目录下
-
通常由两个部分组成
- 第一部分为响应头,用于告知客户端传输数据的类型,后面跟空行,用于将响应体分开
print("Content-Type: text/html") print()
- 第二部分为响应的数据
-
常用的头部信息
-
Content-type:
请求的资源类型对应的MIME信息 -
Content-Disposition: disposition-type;filename-parm
响应请求资源的下载方式- 其中disposition-type可以为
attachment
弹出对话框下载,或者inline
直接显示在页面上 - 其中filename-parm是
filename = xx
规定下载时的文件名,用于规定下载时的文件名称
- 其中disposition-type可以为
-
Expires:
响应过期的日期和时间 -
Location:
重定向到url的新的资源 -
Last-modified:
请求资源的最后修改日期 -
Content-length:
请求的内容长度 -
Set-Cookie:
设置cookie
-
-
常用方法
-
parse_header(str)
将MIME标头解析为字典 -
parse_multipart(fp,pdict,encoding =“utf-8”,errors =“replace” )
返回{字段名称:数据}的字典 -
print_form(form)
将接收的表格以html形式格式化 -
print_directory()
以html形式格式化当前目录 -
test()
将cgi作为主程序进行测试
-
-
FieldStorage(,key,filename,value)
类- 此类用于获取html中form输出的表单数据,仅需要实例化一次
-
FiledStorage()[key]
代表了表单中名为key的标签整体 -
FiledStorage()[key].value
代表了表单中key标签的值 -
getvalue(key)
当有多个值时,返回一个字符串列表 -
getlist(key)
返回名key标签下的所有字符串组成的列表
- 编写一个最简单的CGI程序,如果需要访问该CGI程序,需要先启动一个CGI服务器,在前面已经学到过,在
HTTPServer
中导入CGIHTTPRequestHandler
创建一个最简单的CGI服务器
import cgi
import cgitb
cgitb.enable()
print("Content-Type: text/html")
print()
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>My First Python CGI</h1>
</body>
</html>
'''
print(html)
-
CGI获取客户端使用
GET
方式发送的数据请求的url为
http://127.0.0.1:8888/cgi-bin/cc.py?usr=jack&pwd=123456
,可以看出,传递的数据以明文方式出现在url中传递的数据包含在请求头中
在GET方式中,不应包含敏感数据,敏感数据应使用POST方式发送
# index.html中的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>请输入文字</h1>
<form action="http://127.0.0.1:8888/cgi-bin/cc.py" method="GET" id="myform">
<h2>账户:<input type="text" name="usr"></h2>
<h2>密码:<input type="text" name="pwd"></h2>
<button type="submit">发送</button>
</form>
</body>
</html>
# CGI程序
import cgi
import cgitb
cgitb.enable()
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
usr = form.getvalue('usr')
pwd = form.getvalue('pwd')
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>获取到的数据是:</h1>
<p>{0}</p>
<p>{1}</p>
</body>
</html>
'''.format(usr,pwd)
print(html)
-
POST方式在上面的
CGIHTTPRequestHandler
中,不多进行赘述- POST方式发送数据,不会明文出现在url中,会存在于请求体的form-data中,所以相对于GET方式,要安全的多
- 传递checkbox数据
# index.html内容是
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>请勾选</h1>
<form action="/cgi-bin/cc.py" method="POST" id="myform">
<input type="checkbox" name="usr" value="on" > usr
<input type="checkbox" name="pwd" value="on" > pwd
<button type="submit">发送</button>
</form>
</body>
</html>
# cgi程序
import cgi
import cgitb
cgitb.enable()
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
google = form.getvalue('google')
if google == on:
r1 = 'google被选中'
else:
r1 = 'google没有被选中'
baidu = form.getvalue('baidu')
if baidu == 'on':
r2 = 'baidu被选中'
else:
r2 = 'baidu没有被选中'
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>获取到的数据是:</h1>
<p>{0}</p>
<p>{1}</p>
</body>
</html>
'''.format(r1,r2)
print(html)
- 传递radio数据
# index.html中的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>请勾选</h1>
<form action="/cgi-bin/cc.py" method="POST" id="myform">
<input type="radio" name="site" value="google" > 谷歌
<input type="radio" name="site" value="baidu" > 百度
<button type="submit">发送</button>
</form>
</body>
# cgi程序内容
import cgi
import cgitb
cgitb.enable()
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
value = form.getvalue('site')
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>获取到的数据是:</h1>
<p>{0}</p>
</body>
</html>
'''.format(value)
print(html)
- 传递Textatrea数据
# index.html中的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>请输入内容</h1>
<form action="/cgi-bin/cc.py" method="post">
<Textarea name="text" cols="40" rows="4" >在这里输入内容....
</Textarea>
<input type="submit">
</form>
</body>
</html>
# cgi程序中的内容
import cgi
import cgitb
cgitb.enable()
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
value = form.getvalue('text')
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>获取到的数据是:</h1>
<p>{0}</p>
</body>
</html>
'''.format(value)
print(html)
- 传递下拉数据
# index.html中的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>请输入内容</h1>
<form action="/cgi-bin/cc.py" method="post">
<select name="sel" >
<option value="baidu">百度</option>
<option value="google">谷歌</option>
</select>
<input type="submit">
</form>
</body>
</html>
# cgi程序中的内容
import cgi
import cgitb
cgitb.enable()
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
value = form.getvalue('sel')
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>获取到的数据是:</h1>
<p>{0}</p>
</body>
</html>
'''.format(value)
print(html)
- 设置cookie
# 直接访问cgi程序,设置cookie,通过chrome即可查看设置的cookie
# cgi程序为:
import cgi,datetime
import cgitb
from http.cookies import *
cgitb.enable()
name = 'cgicookie'
now = datetime.datetime.utcnow()
time = (now + datetime.timedelta(days=10)).strftime('%a,%d-%m-%Y %H:%M:%S')
path = '/'
domain = '127.0.0.1'
cookie = SimpleCookie()
cookie['NAME'] = name
cookie['NAME']['expires'] = time
cookie['NAME']['path'] = path
cookie['NAME']['domain'] = domain
print("Content-Type: text/html")
print(cookie)
print()
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>cookie已经设置</h1>
</body>
</html>
'''
print(html)
- 文件上传
# index.html中的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>文件上传</h1>
<form action="/cgi-bin/cc.py" method="post" enctype="multipart/form-data">
<p><input type="file" name="upload"></p>
<p><input type="submit"></p>
</form>
</body>
</html>
# cgi程序为:
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
file = form['upload']
open(file.filename,'wb').write(file.value)
print("Content-Type: text/html")
print()
html ='''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>已接收上传文件</h1>
</body>
</html>
'''
print(html)
- 文件下载
# 直接访问cgi程序,以下为cgi程序的内容
import cgi
import cgitb
cgitb.enable()
data = open(r'chromedriver.exe','rb').read()
print("Content-Disposition: attachment;filename=chromedriver.exe")
print()
print(data)
urlib URL处理模块
-
url 同一资源定位符
-
格式:
prot_sch://net_loc/path;params?query#frag
prot_sch 网络协议
-
net_loc
服务器所在地址 可进一步分割为多个组件-
user
用户名 -
passwd
用户密码 -
host
服务器所在地址或服务器计算机名称(必须) -
port
端口号(默认80)
-
path
文件或者CGI应用的路径params
可选参数query
连接符(&)分割的键值对frag
文档中的特定锚点
-
-
request
请求url模块-
Request(url,data = None,headers = {})
类 构造一个复杂的请求对象,可以供urlopen函数使用full_url
返回请求的urlhost
返回请求的主机地址method
返回请求的方法add_header(key,value)
添加请求标头has_header(key)
检查是否有key请求标头remove_header(key)
删除名为key的请求标头get_header(key)
返回名为key的标头值header_items()
返回所有请求标头和值
-
-
urlopen(url,data)
打开一个url,发送data,返回HTTPResponse对象在HTTPResponse的基础上添加了以下方法
geturl()
返回请求资源的urlinfo()
返回页面的元信息getcode()
返回响应的状态码
build_opener([handler,])
返回一个OpenerDirector对象install_opener(OpenerDirector对象)
将OpenerDirector对象设置为全局默认-
OpenerDirector
类 该类主要用于通过添加相应的Handler构建一个自定义的urlopen对象,实现各种不同的访问需求add_handler(Handler)
添加一个处理行为给OpenerDirector对象open(url)
打开URL,返回HTTPResponse对象error(proto,* args)
给定相应的参数处理错误
HTTPRedirectHandler
类,重定向处理程序HTTPHandler
类,发送HTTP请求,可以为GET或POSTHTTPSHandler(debuglevel = 0,context = None,check_hostname = None )
类,发送HTTPS请求,可以为GET或者POSTHTTPBasicAuthHandler(password_mgr = None )
类,请求时需要账户密码登录ProxyHandler(proxies = None )
类,代理请求,需要在实例化的时候添加代理字典ProxyBasicAuthHandler(password_mgr = None )
类,需要用户名密码登录的代理HTTPCookieProcessor(cookiejar)
类,Cookie处理FileHandler
类,打开文件FTPHandler
类,打开FTP文件-
HTTPErrorProcessor
类,处理HTTP异常http_response(req,reply)
对于错误,返回reply对象https_response(req,reply)
对于错误,返回reply对象
-
密码管理器对象,用于添加到各项需要认证的处理程序中
-
HTTPPasswordMgr
类,映射数据库,通过(realm, uri) -> (user, password)add_password(realm, uri, user, passwd)
添加相应的账户,密码到管理器对象中,realm是指主机服务器的域信息一般为None,uri指服务器find_user_password(realm, authuri)
返回指定服务器域中是否有定义的账户,如果有返回(账户,密码)元组,没有返回None
-
HTTPPasswordMgrWithDefaultRealm
类- 同上两个方法
HTTPPasswordMgrWithPriorAuth
类同上两个方法
update_authenticated(self, uri, is_authenticated=False)
is_authenticated(self, authuri)
-
使用默认函数访问url
from urllib.request import *
url = 'http://www.baidu.com'
response = urlopen(url)
print(response.read().decode())
使用Request对象构造请求
from urllib.request import *
url = 'http://www.baidu.com'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
'Host': 'www.baidu.com'
}
request = Request(url,headers=headers)
response = urlopen(request)
print(response.read().decode())
构造自定的访问器,获取cookie
from urllib.request import *
from http.cookiejar import *
url = 'http://www.baidu.com'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
'Host': 'www.baidu.com'
}
cookie = CookieJar()
openr = build_opener(HTTPCookieProcessor(cookie))
request = Request(url,headers=headers)
response = openr.open(request)
print(cookie)
print(response.read().decode())
# 或者
from urllib.request import *
from http.cookiejar import *
url = 'http://www.baidu.com'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
'Host': 'www.baidu.com'
}
cookie = CookieJar()
openr = OpenerDirector()
openr.add_handler(HTTPCookieProcessor(cookie))
openr.add_handler(HTTPHandler())
request = Request(url,headers=headers)
response = openr.open(request)
print(cookie)
构造自定访问器,使用用户名、密码登录
from urllib.request import *
from urllib.parse import *
login_url = r'https://www.douban.com/accounts/login'
data = urlencode({
'source': 'index_nav',
'form_email': 'XXXXX',
'form_password': 'XXXXX'
}).encode()
request = Request(url=login_url,data=data)
response = urlopen(request)
print(response.read().decode('utf-8','ignore'))