基于Python的网络编程
现代的应用程序都离不开网络,网络编程是非常重要的技术。Python提供了两个不同层次的网络编程API:基于Socket的低层次网络编程和基于URL的高层次网络编程。Sockrt采用TCP、UDP等协议,这些协议属于低层次的通信协议;URL采用HTTP和HTTPS,这些属于高层次的协议。
网络基础
网络编程需要程序员掌握一些基础的网络知识,如果想要学的深入一点,可以学习“计算机网络”的相关课程。
网络结构
网络结构是网络的构建方式,目前流行的有客户端服务器结构网络和对等结构网络。
(1)客户端服务器结构网络
客户端服务器(Client Server,C/S)结构网络是一种主从结构网络。服务器一般处于等待状态,如果有客户端请求,服务器响应请求,建立连接提供服务。服务器是被动的,有点像在餐厅吃饭时的服务员,而客户端是主动的,像在餐厅吃饭的顾客。
事实上,生活中很多网络服务都采用这种结构,如Web服务、文件传输服务和邮件服务等。虽然他们存在的目的不一样,但基本结构是一样的。这种网络结构与设备类型无关,服务器不一定是计算机,也可能是手机等移动设备。
(2)对等结构网络
对等结构网络也称为点对点网络(Peer to Peer,P2P),每个节点之间是对等的。每个节点既是服务器又是客户端。对等结构网络分布范围比较小,通常在一间办公室或一个家庭内,因此它非常适合移动设备间的网络通信,网络链路层由蓝牙和WiFi实现。
网络基础知识
1.TCP(传输控制协议,Transmission Control Protocol)
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。在TCP连接中,两台计算机之间会先建立一条连接(三次握手),然后在这条连接上发送数据,最后关闭连接(四次挥手)。TCP通过序列号、确认应答、数据校验和重发控制等机制确保数据的可靠传输,例如:如果有些数据包没有收到会重发,并对数据包内容的准确性进行检查并保证数据包顺序。TCP适用于对数据完整性要求较高的应用场景,如文件传输、网页浏览等。
TCP/IP是由TCP和IP两个协议构成的。IP(Internet Protocol)是一种低级的路由协议,它将数据拆分在许多小的数据包中,并通过网络将他们发送到某一特定地址,但无法保证所有包都抵达目的地,也不能保证包的顺序。由于IP传输数据的不安全性,网络通信时还需要TCP。
2. UDP(用户数据报协议,User Datagram Protocol)
与TCP不同,UDP是一种无连接的传输层协议,它不建立连接,直接发送数据。UDP发送的数据包被称为“数据报”,每个数据报的大小在8字节到65535字节之间。UDP不提供数据包的排序、错误检查、重发等机制,因此它的传输效率较高,但数据可靠性不如TCP。UDP适用于对实时性要求较高,但允许少量数据丢失的应用场景,如视频播放、在线游戏等。
3. HTTP(超文本传输协议,HyperText Transfer Protocol)
HTTP是应用层协议,主要用于在万维网(WWW)上传输超媒体文档(如HTML)。HTTP是客户端和服务器之间请求-响应模式的协议。客户端(如浏览器)发送HTTP请求到服务器,请求指定的资源(如网页),服务器响应请求并返回相应的资源。HTTP协议支持 C/S 网络结构,是无连接协议,即每次请求时建立连接,服务器处理完客户端的请求后,应答给客户端然后断开连接,不会一直占用网络资源。HTTP 1.1是目前广泛使用的版本,它支持持久连接、请求管道化、缓存控制等特性。HTTP本身不加密数据,因此数据在传输过程中可能被窃听或篡改。
HTTP/1.1 协议共定义了 8 种请求方法:OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE和CONNECT。在HTTP访问中,一般使用POST和GET方法。
- GET方法:向指定的资源发出请求,发送的信息“显式”地跟在URL后面。GET方法只用在读取数据,例如静态图片。GET方法有点像使用明信片给别人写信,“信内容”写在外面,接触到的人都可以看到,因此是不安全的。
- POST方法:向指定资源提交数据,请求服务器进行处理,例如:提交表单或者上传文件等。数据被包含在请求体中。POST方法像是把“信内容”装入信封中,接触到的人都看不到,因此是安全的。
4. HTTPS(安全超文本传输协议,HyperText Transfer Protocol Secure)
HTTPS是HTTP的安全版本,它通过SSL(安全套接层)或TLS(传输层安全)协议在HTTP的基础上增加了数据加密的功能。HTTPS的URL以https://开头,表示该网页使用了加密传输。HTTPS能够确保数据在客户端和服务器之间的传输过程中保持机密性和完整性,防止数据被窃听或篡改。HTTPS广泛应用于网银、电子商务、在线支付等对安全性要求较高的场景。(SSL 使用40位关键字作为RC4流加密算法,这对于商业信息的加密是合适的。HTTPS和SSL支持使用X.509数字认证,如果需要,用户可以确认发送者是谁)
5.通信协议
通信协议是指在网络中,计算机之间或计算机与终端之间传输数据的一组规则或约定。这些规则或约定包括数据的格式、数据的编码、同步方式、传输速度、错误控制等。通信协议是网络通信的基础,不同的协议适用于不同的应用场景和需求。在计算机网络中,从物理层到应用层,每一层都有自己的协议,这些协议共同构成了计算机网络的通信框架。
6.IP地址
为实现网络中不同计算机之间的通信,每台计算机都必须有一个与众不同的标识,这就是IP地址,TCP/IP使用IP地址来标识源地址和目的地址。最初所有的IP地址都是32位的数字,由4个8位的二进制数组成,每8位之间用圆点隔开,如192.168.1.1,这种类型的地址通过IPv4指定。而现在有一种新的地址模式称为IPv6,IPv6使用128位数字表示一个地址,分为8个16位块。尽管IPv6比IPv4有很多优势,但是由于习惯、历史等原因,很多设备还是采用IPv4.不过Python语言同时支持IPv4和1IPv6。
在IPv4地址模式中IP地址分为A、B、C、D、E 5类。
- A类地址用于大型网络,地址范围:1.0.0.1~126.155.255.254。
- B类地址用于中型网络,地址范围:128.0.0.1~191.255.255.254。
- C类地址用于小规模网络,地址范围:192.0.0.1~223.255.255.254。
- D类地址用于多目的地信息的传输和备用。
- E类地址保留仅作实验和开发使用。
此外,还有特殊的IP地址 127.0.0.1,称为回送地址,指本机。该地址主要用于网络软件测试以及本地机进程间的通信,使用回送地址发送数据,不进行任何的网络传输,只在本机进程间通信。
7.端口
一个IP地址标识一台计算机,每台计算机又有很多网络通信程序在运行,提供网络服务或进行通信,这就需要不同的端口进行通信。如果把IP地址比作电话号码,那么端口就是分机号码,进行网络通信时不仅要指定IP地址,还要指定端口号。
TCP/IP系统中的端口号是一个16位的数字,它的范围是:0~65535。小于1024的端口号保留给预定义的服务,如HTTP是80,FTP是21,Email是25等,除非要和那些服务进行通信,否则不应该使用小于1024的端口。
TCP Socket低层次网络编程
TCP/IP协议的传输层有两种传输协议:TCP(传输控制协议)和UDP(用户数据报协议)。TCP是面向连接的可靠数据传输协议。TCP就好比电话,电话接通后双方才能通话,在挂断电话之前,电话一直占线。TCP连接一旦建立起来,一直占用,直到连接关闭。另外,TCP为了保证数据的正确性,会重发一切没有收到的数据,还会对数据内容进行验证,并保证数据传输的正确顺序。因此TCP协议对系统资源的要求较多。
TCP Socket通信概述
Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换。这个双向链路的一端称为一个Socket。Socket通常用来实现客户端和服务端的连接。Socket是TCP/IP协议的一个十分流行的编程接口,一个Socket由一个IP地址和一个端口号唯一确定,一旦建立连接,Socket还会包含本机和远程主机的IP地址和端口号,即Socket是成对出现的。
TCP Socket通信过程
使用TCP Socket进行C/S结构编程的通信过程如下图所示
从上图可以知道:服务器首先绑定本地的IP和端口,如果端口已经被其他程序占用则抛出异常。如果绑定成功则接听该端口。服务器端调用 socket.accept() 方法阻塞程序,等待客户端连接请求。当客户端向服务器发出连接建立请求,服务器接收客户端请求建立连接。一旦连接建立起来,服务器与客户端就可以通过 Socket 进行双向通信了,最后关闭 Socket 释放资源。
TCP Socket编程API
Python提供了两个socket模块:socket 和 socketserver。socket模块提供了标准的BSD Socket (BSD Socket,也称伯克利套接字,是由加州大学伯克利分校的学生开发的。BSD Socket是UNIX平台下广泛使用的Socket 编程)API;socketserver重点是网络服务器开发,它提供了4个基本服务类,可以简化服务器开发。接下来重点介绍socket模块实现Socket编程。
1.创建TCP Socket
socket模块提供了一个 socket() 函数可以创建多种形式的socket对象,示例代码如下
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
参数 socket.AF_INET 设置IP地址类型是IPv4,如果采用IPv6地址类型参数是 socket.AF_INET6,。参数 socket.SOCK_STREAM 设置Socket 通信类型是TCP。
2.TCP Socket 编程方法
socket 对象有很多方法,其中与TCP Socket服务器编程有关的方法如下:
- socket.bind(address):绑定地址和端口,address是包含主机名(或IP地址)和端口的二元组对象。
- socket.listen(backlog):监听端口,backlog是最大连接数,其默认值为1.
- socket.accept():等待客户端连接,连接成功返回二元组对象(conn,address),其中conn是新的socket对象,可以用来接收和发送数据,address是客户端的地址。
3.客户端编程socket方法
socket对象中与 TCP Socket 客户端编程有关的方法如下:
socket.connect(address):连接服务器socket,address是包含主机名(或IP地址)和端口的二元组对象。
4.服务器和客户端编程socket共用方法
socket对象中有一些方法是服务器和客户端编程共用方法,这些方法如下:
- socket.recv(buffsize):接收 TCP Socket数据,该方法返回字节序列对象。参数buffsize指定一次接收的最大字节数,因此如果要接收的数据量大于buffsize,则需要多次调用该方法进行接收。
- socket.send(bytes):发送TCP Socket数据,将bytes数据发送到远程Socket,返回成功发送的字节数。如果要发送的数据量很大,需要多次调用该方法发送数据。
- socket.sendall(bytes):发送TCP Socket数据,将bytes数据发送到远程Socket,如果发送成功返回None,如果失败则抛出异常。与 socket.send(bytes) 不同的是,该方法连续发送数据,直到发完所有数据或发生异常。
- socket.settimeout(timeout):设置Socket超时时间,timeout是一个浮点数,单位是s,值为None则表示永远不会超时。一般超时时间应在刚创建Socket时设置。
- socket.close():关闭Socket,该方法虽然可以释放资源,但不一定立即关闭连接,如果要及时关闭连接,需要在调用该方法之前调用 shutdown() 方法。
注意:Python中的 socket 对象是可以被垃圾回收的,当 socket 对象被垃圾回收,则 socket 对象会自动关闭,但建议显式地调用 close() 方法关闭 socket 对象。
实例:简单聊天工具
该实例实现了从客户端发送字符串给服务器,然后服务器再返回字符串给客户端。
服务器端代码如下:
import socket
# 创建一个socket对象
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定本机IP地址和端口,其中IP地址为空字符串,系统会自动为其分配可用的本机IP地址,8888是绑定的端口
s.bind(('',8888))
# 监听8888端口
s.listen()
print('服务器启动...')
# 等待客户端连接;使用accept方法阻塞程序,该方法返回二元组
# conn是一个全新的socket对象,address是当前客户端地址
conn,address = s.accept()
# 客户端连接成功
print(address)
# 从客户端接收数据
data = conn.recv(1024)
# 接收数据,默认接受的数据字符集为UTF-8
# decode()方法是将字节序列转化为字符串
print('从客户端接收信息:{0}'.format(data.decode()))
# 给客户端发送数据,参数是字节序列对象
# 如果发送字符串则需要转换为字节序列,使用字符串的encode()方法进行转换
# encode()方法也可以指定字符集,默认字符集为UTF-8
conn.send('你好'.encode())
# 释放资源
conn.close()
s.close()
客户端代码如下:
import socket
# 创建一个socket对象
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 连接服务器,其中参数 '127.0.0.1' 为远程服务器IP地址或主机名,8888是远程服务器端口
s.connect(('127.0.0.1',8888))
# 给服务器端发送数据,在字符串前面加 b 可以将字符串转换为字节序列对象
# 但是该方法只适合ASCII字符串,非ASCII字符串会引发异常
s.send(b'Hello')
# 从服务器端接收数据
data = s.recv(1024)
print('从服务器端接收消息:{0}'.format(data.decode()))
# 释放资源
s.close()
注意:运行时先运行服务器,再运行客户端
服务器端输出如下:
服务器启动...
('127.0.0.1', 42723)
从客户端接收信息:Hello
Process finished with exit code 0
客户端输出如下:
从服务器端接收消息:你好
Process finished with exit code 0
实例:文件上传工具
该实例实现了文件上传功能,客户端读取本地文件,然后通过 Socket 通信发给服务器,服务器接收数据保存到本地。
服务器端代码如下:
import socket
Host = ''
port = 8888
png = 'CSDN.png'
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
s.bind((Host,port))
s.listen(10)
print('服务器启动...')
while True:
with s.accept()[0] as conn:
# 由于一次从客户端接受的数据只是一部分,需要将接收的字节数据收集到bufffer中
# 创建字节序列对象列表,作为接收数据的缓冲区;
buffer = []
while True: # 反复接收数据
data = conn.recv(1024)
if data:
# 接收的数据添加到缓冲区
buffer.append(data)
else:
# 没有接收到数据则退出
break
# 将接收的字节序列对象列表合并为一个字节序列对象
# bytes()是创建一个空的字节序列对象,字节序列对象的join方法可以将buffer连接起来
b = bytes().join(buffer)
with open(png,'wb') as f: # 以写入模式打开二进制本地文件
f.write(b)
print('服务器接收完成')
客户端代码如下:
import socket
Host = '127.0.0.1'
port = 8888
png = 'CSDN.png'
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
s.connect((Host,port))
with open(png,'rb') as f:
b = f.read() # f.read()方法会读取全部的文件内容
s.sendall(b)
print('客户端上传数据完成。')
服务器端代码输出结果如下:
服务器启动...
服务器接收完成
服务器接收完成
服务器接收完成
服务器接收完成
服务器接收完成
服务器接收完成
服务器接收完成
服务器接收完成
客户端代码输出结果如下:
客户端上传数据完成。
Process finished with exit code 0
UDP Socket低层次网络编程
UDP(用户数据报协议)就像日常生活中的邮件投递,是不可能保证可靠地寄到目的地。UDP是无连接的,对系统资源要求较少,UDP可能丢包,不保证数据顺序。但是对于网络游戏和在线视频等要求传输快、实时性高、质量可稍微差一点的数据传输,UDP还是非常不错的。
UDP Socket 网络编程比 TCP S ocket 编程简单得多,UDP是无连接协议,不需要像TCP一样监听端口,建立连接,然后才能进行通信。
UDP Socket 编程API
socket 模块中UDP Socket编程API与TCP Socket 编程API是类似的,都是使用socket对象,只是有些参数时不同的。
1.创建 UDP Socket
创建UDP Socekt对象也是使用 socket() 函数,创建代码如下:
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
2.UDP Socket 服务器编程方法
socket 对象中与 UDP Socket 服务器编程有关的方法是 bind() 方法,注意不需要 listen() 和 accept(),这是因为UDP通信不需要像TCP一样监听端口,建立连接。
3.服务器和客户端编程socket共用方法
socket 对象中有一些方法是服务器和客户端编程的共用方法,这些方法如下:
socket.recvfrom(buffsize):接收UDP Socket数据,该方法返回二元组对象(data,address),data是接收的字节序列对象;address发送数据的远程Socket地址,参数 buffsize 指定一次接收的最大字节数,因此如果要接收的数据量大于buffsize,则需要多次调用该方法进行接收。
socket.sendto(bytes,address):发送UDP Socket数据,将 bytes 数据发送到地址为 address 的远程 Socket,返回成功发送的字节数。如果要发送的数据量很大,需要多次调用该方法发送数据。
socket.settimeout(timeout):同上面提到的TCP Socket。
socket.close():关闭socket,同上面提到的TCP Socket。
实例:简单聊天工具
将上面的用TCP Socket 编程API实现的简单聊天工具改为用 UDP Scoket编程API实现。
服务器端示例代码如下:
import socket
# 创建一个UDP Socket对象
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定本机IP和端口
s.bind(('',8888))
print('服务器启动...')
# 从客户端接收数据
data,client_address = s.recvfrom(1024)
print('从客户端接收消息:{0}'.format(data.decode()))
# 给客户端发送数据
s.sendto('你好'.encode(),client_address)
# 释放资源
s.close()
客户端示例代码如下:
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server_address = ('127.0.0.1',8888)
# 给服务端发送数据
s.sendto(b'Hello',server_address)
# 从服务器端接收数据
data,adress_server = s.recvfrom(1024)
print('从服务器端接收消息:{0}'.format(data.decode()))
# 释放资源
s.close()
服务器端代码运行结果:
服务器启动...
从客户端接收消息:Hello
Process finished with exit code 0
客户端代码运行结果:
从服务器端接收消息:你好
Process finished with exit code 0
实例:文本文件上传工具
首先在项目的文件下新建一个“test.txt”文档,文档中的测试数据可以任写。此处我写的测试数据如下(为方便如果想复制的人也复制该代码,因此将数据放在下面):
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字,
这是一段用于测试的文字。
接下来为具体的代码,服务器端示例代码如下:
import socket
host = '127.0.0.1'
port = 8888
f_name = 'test_copy.txt'
with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as s:
s.bind((host,port))
print('服务器启动...')
# 创建字节序列对象,作为接收数据的缓冲区
buffer = []
# 反复接收数据
while True:
data,_ = s.recvfrom(1024)
if data:
# 解码数据包
flag = data.decode()
# 判断这个标志是否为'bye'
if flag == 'bye':
break
buffer.append(data)
else:
# 没有接收到数据,进入下次循环继续接收
continue
# 将接收的字节序列对象列表合并为一个字节序列对象
b = bytes().join(buffer)
with open(f_name,'w',encoding='utf-8') as f:
f.write(b.decode())
print('服务器接收完成')
客户端示例代码如下:
import socket
host = '127.0.0.1'
port = 8888
f_name = 'test.txt'
# 服务器地址
server_address = (host,port)
with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as s:
with open(f_name,'r',encoding='utf-8') as f:
# 反复从文件中读取数据
while True:
data = f.read(1024)
if data:
# 发送数据
s.sendto(data.encode(),server_address)
else:
# 发送结束标志
s.sendto(b'bye',server_address)
# 文件中没有可读取的数据则退出
break
print('客户端上传数据完成')
注意事项:在服务端代码中 f_name 的文件名为自己定义的,可任取;客户端的 f_name 必须是已经存在的文件,文件的路径可以用绝对路径或相对路径,此处由于我的文件和我的运行项目在同一个文件夹下,所以采用相对路径更方便。 此外,一定要注意先启动服务器端的py文件,再启动客户端的py文件。
服务器端运行结果:
服务器启动...
服务器接收完成
Process finished with exit code 0
客户端运行结果:
客户端上传数据完成
Process finished with exit code 0
在文件运行之后可以看到在同一目录下生成文件 test_copy.txt ,且文件的内容与上面的测试数据的内容一样(此处不在作展示)。
访问互联网资源
Python的 urllib 库提供了高层次的网络编程API,通过 urllib 库可以访问互联网资源。使用 urllib 库进行网络编程,不需要对协议本身有太多的了解,相对与前面的内容比较简单。
URL概念
URL(Uniform Resource Locator,统一资源定位符)是一种用于在万维网(WWW)上定位和访问资源(如网页、文件、图片、视频等)的标准地址格式。URL 是互联网上的一个基础组成部分,它允许用户通过点击链接或输入地址的方式,轻松访问和浏览网络资源。
URL 的结构
一个典型的 URL 遵循以下结构:
协议://主机名[:端口号]/路径[?查询字符串][#片段标识符]
-
协议(Protocol):指定了用于访问资源的应用程序协议类型,最常见的协议是 HTTP(超文本传输协议)和 HTTPS(安全超文本传输协议)。其他协议还包括 FTP(文件传输协议)、mailto(电子邮件)、gopher、file等。
-
主机名(Hostname):定义了资源所在的服务器地址。它可以是域名(如 www.csdn.net 或IP 地址(如 192.0.2.1)。
-
端口号(Port):是一个可选部分,用于指定服务器上的特定服务端口。HTTP 服务的默认端口是 80,HTTPS 服务的默认端口是 443。如果使用的是默认端口,则可以省略端口号。
-
路径(Path):定义了服务器上资源的具体位置。它通常表示一个文件或资源在服务器上的层次结构路径。路径以“/”开头,是可选的,但如果不指定路径,则通常访问服务器的根目录或默认页面。
-
查询字符串(Query String):是一个可选部分,它以“?”开头,用于向服务器传递额外的信息。查询字符串中的每个参数以“&”分隔,格式为“键=值”。这些信息对于服务器来说是可选的,并且可以用来动态生成内容。
-
片段标识符(Fragment Identifier):是一个可选部分,它以“#”开头,用于指向页面内的一个特定部分(如一个段落、一个图片等)。这部分不会发送到服务器,仅由浏览器内部处理。
搭建自己的Web服务器
本节的相关软件的安装可以自行参考其他资源进行安装;若大家不会安装或需要我提供一下安装的方法,可以在本文的评论区进行评论。搭建Web服务器的步骤如下:
- 安装JDK(Java开发工具包):因为本节安装的 Web 服务器是 Apache Tomcat,它是支持 Java Web 技术的 Web 服务器。 Apache Tomcat 的运行环境需要Java运行环境,而JDK中包含了Java运行环境,因此需要先安装JDK。
- 配置Java环境变量
- 安装 Apache Tomcat 服务器。在 Apache Tomcat 目录中找到 startup.bat 文件,双击该文件即可启动服务器。(启动服务器后可以通过在浏览器输入网址:http://localhost:8080/ 其中8080为默认端口号,若没有更改过端口号则输入8080即可;若改过端口号则需要将上述网址的端口号改为对应的端口号)
启动startup.bat 文件后如下图:
全部配置成功后在浏览器输入网址后会出现下图:
使用 urllib 库
Python 的 urllib 库其中包含了如下4个模块
- urllib.request模块:用于打开和读写URL资源。
- urllib.error模块:包含了由 urllib.request 引发的异常。
- urllib.parse模块:用于解析URL。
- urllib.robotparser模块:分析 robots.txt 文件(各大搜索引擎都会有一个工具——搜索引擎机器人,也称为“蜘蛛”,他会自动抓取网站信息、而 robots.txt 文件是放在网站根目录下,告诉搜索引擎机器人哪些页面可以抓取,哪些页面不可用抓取)。
在访问互联网资源时主要主要使用的模块是 urllib.request、urllib.error、urllib.parse模块,其中最核心的是urllib.request模块。在urllib.request模块中访问互联网资源主要使用 urllib.request.urlopen()函数 和 urllib.request.Request对象,urllib.request.urlopen()函数可以用于简单的网络资源访问,而 urllib.request.Request对象可以访问复杂的网络资源。
使用urllib.request.urlopen()函数最简单形式如下:
import urllib.request
# 使用urlopen()函数打开http://www.sina.com.cn网站
with urllib.request.urlopen('http://www.sina.com.cn/') as response:
# 使用read()方法读取数据,只是该数据为字节序列数据
data = response.read()
# 将字节序列数据转为字符串
html = data.decode()
print(html)
代码运行结果如下:
上述代码中upload()函数返回一个应答对象,应答对象是一种类似文件对象(file-like object),该对象可以像使用文件一样使用,可以使用 with as 代码块自动管理资源释放。
发送GET请求
对于复杂的需求,需要使用urllib.request.Request对象才能满足。Request对象需要与urlopen()函数结合使用。下面示例代码展示了通过Request对象发送HTTP/HTTPS的GET请求。
import urllib.request
# 请求参数action为query表示进行查询请求
url = 'http://localhost:8080/NoteWebService/note.do?action=query&ID=10'
# 创建Request对象,在该构造方法中还有data参数,如果不指定则为GET请求,否则是POST请求
req = urllib.request.Request(url)
# 通过urllib.request.urlopen(req)发送网络请求
with urllib.request.urlopen(req) as response:
data = response.read()
json_data = data.decode()
print(json_data)
将本节例子与上个例子进行对比可以发现,本节中urlopen()传递的是Request对象,而上个例子中是URL字符串;实际上,urlopen()可以接受两种类型的参数,即字符串和Request对象参数。
发送POST请求
示例代码如下:
import urllib.request
import urllib.parse
# 请求参数action为query表示进行查询请求
url = 'http://localhost:8080/NoteWebService/note.do'
# 准备HTTP参数
params_dict = {'ID':10,'action':'query'}
params_str = urllib.parse.urlencode(params_dict)
print(params_str)
params_bytes = params_str.encode()
req = urllib.request.Request(url,data=params_bytes) # 发送POST请求
with urllib.request.urlopen(req) as response:
data = response.read()
json_data = data.decode()
print(json_data)
实例:图片下载器
import urllib.request
url = 'http://localhost:8080/NoteWebService/logo.png'
with urllib.request.urlopen(url) as response:
data = response.read()
f_name = 'logo.png'
with open(f_name,'wb') as f:
f.write(data)
print('下载文件成功')
参考书籍:《python从小白到大牛》(第2版)关东升 编著
文章创作不易,本文13000+字,为了大家能理解,写的很详细,这也让我花了很多时间。最后,如果觉得本文对大家有帮助的话,还请给我点个赞和关注;如果有能力的话还请打赏一下;谢谢大家!!!