理论模型,分为七层
实际应用,分为四层
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 负载均衡
协议家族
基于文件
基于网络
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())
此模块提供网络服务器框架,可以使开发者更加快捷的开发出相应的网络服务器
服务器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
方法
FTP (FileTransferProtocal) 文件传输协议
用户
Real账户 注册账户
Guest账户 临时账户
Anonymous 匿名账户
端口
21
端口为控制和命令端口
20
端口为数据端口
FTP(host,usr,passwd)类
可以使用上下文管理协议 即with
语句
connect(host,port)
当没有在实例化FTP定义host时,则需要调用connect函数指定host和port
login(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.stdout
rename(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()
邮件传输模式
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
To: you
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)
返回邮件消息中每行内容所组成的列表,选择是否解码,一般需要填入True
walk()
迭代器,迭代邮件消息的每一行
header
构造邮件标头模块
Header(str=None,charset=None,header_name = NONE)
类 创建符合MIME协议的标头
邮件标头可以通过两种方式进行构造
msg['From'] = Header('[email protected]')
add_header(name,value)
函数,使用消息对象的函数进行赋值msg.add_header('From','[email protected]')
邮件头的解码
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 )
从文本流中返回消息对象
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 = '[email protected]'
pwd = 'xxxxx'
to_mail = '[email protected]'
# 构造文本消息邮件
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 = '[email protected]'
pwd = 'xxxxx'
to_mail = '[email protected]'
# 构造html
content ="这是一封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 = '[email protected]'
pwd = 'xxxxx'
to_mail = '[email protected]'
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())
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协议 是Hyper Text Transfer Protocol的缩写,简称为超文本传输协议
HTTP 的默认端口为80
HTTPS的默认端口为443
永远是客户端先发起请求,然后服务器响应请求
工作模式
建立连接
接收数据
结束连接
请求报文 Request
请求行包括了请求方法,请求的url和http版本
请求方法
POST
向服务器提交数据 改
GET
请求数据 查
PUT
向服务器上传数据 增
DELETE
请求服务器删除相应数据 删
请求头是key-value形式的,其中有以下属性
Host
请求资源的主机地址(必须存在)User-Agent
客户端的浏览器类型和版本Accept-Language
客户端申明自己接收的语言Accept
客户端申明自己想要接收数据的类型 Accept-Encoding
客户端申明自己接收的编码,通常指定压缩方法Cookie
发送cookie值Connection
连接方式 keep-alive
持久连接,当访问网页后连接不会关闭close
短连接,访问后就关闭,下次建立新的连接Keep-Alive
保持连接的时间Referer
表示用户从该网页访问服务器Date
此报文产生的日期Authorization
客户端权限空行,请求头和请求体之间必须有一个空行
请求体
响应报文 Response
响应行,包括了服务器软件的版本号,返回的状态码和相应短语
响应头
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
请求的url
request_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 = '''
Server
hello Python!
'''
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文件
'''
My Page
Hello Python3!
'''
# 再次运行服务器,使用浏览器访问,即可以查看结果
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
'''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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 = '''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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
星期几,DD-MM-YY HH:MM:SS GMT
,GMT表示格林尼治时间,如不填该cookie不会保存在硬盘中,该cookie随着浏览器的关闭消失RFC2109中定义的cookie : Set-Cookie: Name = Value; Comment = value; Domain = value; Max-Age = value; Path = Value;Secure; Version = 1 * DIGIT;
.
开始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 )
将接收到的字符串对象解析为cookieSimpleCookie(input) 类
Morsel 类
常用常量
常用方法
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.txt
LWPCookieJar(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中提取cookie
set_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 )
从文件中加载cookie
revert(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')
通常由两个部分组成
print("Content-Type: text/html")
print()
常用的头部信息
Content-type:
请求的资源类型对应的MIME信息Content-Disposition: disposition-type;filename-parm
响应请求资源的下载方式 attachment
弹出对话框下载,或者inline
直接显示在页面上filename = xx
规定下载时的文件名,用于规定下载时的文件名称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)
类
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 ='''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>My First Python CGIh1>
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中的内容
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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 ='''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>获取到的数据是:h1>
<p>{0}p>
<p>{1}p>
body>
html>
'''.format(usr,pwd)
print(html)
POST方式在上面的CGIHTTPRequestHandler
中,不多进行赘述
传递checkbox数据
# index.html内容是
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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 ='''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>获取到的数据是:h1>
<p>{0}p>
<p>{1}p>
body>
html>
'''.format(r1,r2)
print(html)
# index.html中的内容
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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 ='''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>获取到的数据是:h1>
<p>{0}p>
body>
html>
'''.format(value)
print(html)
# index.html中的内容
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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 ='''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>获取到的数据是:h1>
<p>{0}p>
body>
html>
'''.format(value)
print(html)
# index.html中的内容
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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 ='''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>获取到的数据是:h1>
<p>{0}p>
body>
html>
'''.format(value)
print(html)
# 直接访问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 ='''
<html lang="en">
<head>
Title
head>
<body>
cookie已经设置
body>
html>
'''
print(html)
# index.html中的内容
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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 ='''
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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)
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
返回请求的url
host
返回请求的主机地址
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()
返回请求资源的url
info()
返回页面的元信息
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或POST
HTTPSHandler(debuglevel = 0,context = None,check_hostname = None )
类,发送HTTPS请求,可以为GET或者POST
HTTPBasicAuthHandler(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)
from urllib.request import *
url = 'http://www.baidu.com'
response = urlopen(url)
print(response.read().decode())
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())
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'))