在 Python 中进行网络编程可以通过标准库或第三方库实现。
1,发送 HTTP 请求与处理响应
1.1 使用标准库 urllib
python
from urllib import request, parse
from urllib.error import URLError
from urllib.error import HTTPError
# GET 请求
# https://httpbin.org/ is A simple HTTP Request & Response Service.
try:
response = request.urlopen("https://httpbin.org/get")
print(f"GET:status:{response.status}") # 读取响应状态码
print(f"GET:header:\n{response.info()}") # 读取响应头部信息
print(f"GET:content:\n{response.read().decode("utf-8")}") # 获取响应内容
except HTTPError as he:
print("HTTP Error:", he.reason)
except URLError as ue:
print("URL Error:%s" % ue.reason)
# POST 请求
data = parse.urlencode({"key1": "value1", "key2": "value2"}).encode()
req = request.Request("https://httpbin.org/post", data=data)
response = request.urlopen(req)
print(f"POST:status:{response.status}")
print(f"POST:header:\n{response.info()}")
print(f"POST:content:\n{response.read().decode()}")
上面的代码打印内容如下:
makefile
GET:status:200
GET:header:
Date: Sat, 08 Feb 2025 06:51:01 GMT
Content-Type: application/json
Content-Length: 275
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
GET:content:
{
"args": {},
"headers": {
"Accept-Encoding": "identity",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.12",
"X-Amzn-Trace-Id": "Root=1-67a6fed5-48cc7cfd46a3aa5908836d06"
},
"origin": "45.62.172.72",
"url": "https://httpbin.org/get"
}
POST:status:200
POST:info:
Date: Sat, 08 Feb 2025 06:51:01 GMT
Content-Type: application/json
Content-Length: 473
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
POST:content:
{
"args": {},
"data": "",
"files": {},
"form": {
"key1": "value1",
"key2": "value2"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "23",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.12",
"X-Amzn-Trace-Id": "Root=1-67a6fed5-41dc5e1b28b2e7ac268676bb"
},
"json": null,
"origin": "45.62.172.72",
"url": "https://httpbin.org/post"
}
在Python中,urlopen 和 urlencode 是处理网络请求的两个常用函数,但它们属于不同的库和用途。
urlopen 是 urllib.request 模块中的一个函数,用于发起HTTP或HTTPS请求。它返回一个类文件对象,可以像操作文件一样读取响应的内容。
urlopen 默认发起GET请求。如果需要发送POST请求,可以使用 Request 对象并设置数据和方法。
urlencode 是 urllib.parse 模块中的一个函数,用于将字典或两个元组的参数编码为URL查询字符串。这通常用于构造GET请求或POST请求的数据部分。
1.2 使用第三方库 requests
python
# requests是Python 中一个用于发送 HTTP 请求的第三方库
import requests
# GET 请求
response = requests.get("https://httpbin.org/get")
print(f"GET:status:{response.status_code}") # 响应状态码
print(f"GET:json:\n{response.json()}") # 解析 JSON 响应
# POST 请求
# 创建了一个字典 data,它将被作为 POST 请求的数据发送
data = {"key": "value"}
response = requests.post("https://httpbin.org/post", data=data)
print(f"POST:status:{response.status_code}")
print(f"POST:text:\n{response.text}")
print(f"POST:json:\n{response.json()}")
上面代码的打印输出如下:
css
GET:status:200
GET:json:
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.32.3', 'X-Amzn-Trace-Id': 'Root=1-67a7126c-477ffef231992df37fefbb9d'}, 'origin': '114.222.23.184', 'url': 'https://httpbin.org/get'}
POST:status:200
POST:text:
{
"args": {},
"data": "",
"files": {},
"form": {
"key": "value"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "9",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.32.3",
"X-Amzn-Trace-Id": "Root=1-67a7126d-393c94657af77b184c4e173d"
},
"json": null,
"origin": "114.222.23.184",
"url": "https://httpbin.org/post"
}
POST:json:
{'args': {}, 'data': '', 'files': {}, 'form': {'key': 'value'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '9', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.32.3', 'X-Amzn-Trace-Id': 'Root=1-67a7126d-393c94657af77b184c4e173d'}, 'json': None, 'origin': '114.222.23.184', 'url': 'https://httpbin.org/post'}
2,网络传输数据
2.1,采用TCP传输
服务端代码示例如下:
perl
import socket
import logging
# 设置日志消息的格式。格式字符串中的 %() 是格式化操作符,用于从日志记录中获取特定的信息。
logging.basicConfig(level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S")
# 创建服务器
# 创建一个服务器套接字(server_socket)并希望它监听来自网络上的连接请求时,
# 需要将套接字绑定到一个特定的IP地址和端口号上。
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 0.0.0.0是一个特殊的IP地址,它表示所有可用的IPv4地址,能够接受来自任何网络接口(网卡)的连接请求。
# 8888是端口号,表示服务器将在这个端口上监听传入的连接请求。
server_socket.bind(('0.0.0.0', 8888)) # 绑定所有网卡的 8888 端口
# listen():是套接字对象的一个方法,用于将套接字置于被动监听状态,等待客户端的连接请求
# 传入参数5,该参数称为 backlog。它指定了操作系统应该为等待接受的连接请求排队的最大数量。
# backlog是一个提示值,实际数量可能会因操作系统而异。
server_socket.listen(5) # 开始监听
print("Server is listening...")
# 下面的日志将输出:2025-02-08 16:30:31 [INFO] Server is listening...logging info
logging.info("Server is listening...logging info")
# while True: 创建了一个无限循环,服务器将不断地接受客户端的连接请求
while True:
# accept函数代码会阻塞,直到有一个客户端尝试连接到服务器。
# 一旦有连接请求,accept 方法会创建一个新的套接字对象 client_socket,用于与这个特定的客户端通信,
# 并且 addr 会包含客户端的IP地址和端口号。
client_socket, addr = server_socket.accept() # 接受客户端连接
print(f"Server:Connected by {addr}")
# 服务器通过新创建的 client_socket 套接字对象发送一条消息给客户端。
# 发送的是字节串(以 b 前缀表示),因为套接字通信是在字节级别进行的。
client_socket.send(b"Hello from server!") # 发送字节串数据
# 服务器调用 recv 方法从 client_socket 接收数据。这里的 1024 指定了最多可以接收的字节数。
# recv 方法会阻塞,直到有数据到达或连接被关闭
data = client_socket.recv(1024) # 接收数据(最多 1024 字节)
# 在打印接收到的数据之前,使用 decode() 方法将其从字节串解码为字符串。
# 这是因为 recv 方法返回的是字节串,而 print 函数通常用于打印字符串。
print(f"Server:Received: {data.decode()}")
client_socket.close() # 关闭与客户端的连接
客户端代码示例如下:
python
import socket
# 创建客户端套接字
# socket.AF_INET:指定地址族为IPv4(Internet地址)。这是最常用的地址族,用于IPv4网络通信
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
# 127.0.0.1:这是一个特殊的IP地址,称为回环地址(loopback address),用于指代本机。
# 当客户端和服务器运行在同一台机器上时,可以使用这个地址进行连接。
# 8888:这是服务器监听的端口号。客户端需要连接到这个端口才能与服务器进行通信。
client_socket.connect(('127.0.0.1', 8888)) # 连接服务器
data = client_socket.recv(1024) # 接收数据
print(f"Server says: {data.decode()}")
client_socket.send(b"Hello from client!") # 发送数据
client_socket.close()
上面代码的输出如下:
服务端:
vbnet
Server is listening...
2025-02-10 09:31:37 [INFO] Server is listening...logging info
Connected by ('127.0.0.1', 55484)
Received: Hello from client!
客户端:
vbscript
Server says: Hello from server!
2.2,采用UDP传输
服务端代码示例如下:
python
import socket
# 创建一个UDP套接字。
# socket.AF_INET指定了地址族为IPv4,socket.SOCK_DGRAM指定了套接字类型为数据报(即UDP)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 监听所有IPv4地址上的8888端口
server_socket.bind(('0.0.0.0', 8888))
# 循环使服务器持续运行,等待接收数据。
# 函数recvfrom(1024)方法接收最多1024字节的数据,并返回两个值:
# 接收到的数据和发送方的地址(一个元组,包含IP地址和端口号)
while True:
print("waiting for client data...")
data, addr = server_socket.recvfrom(1024) # 接收数据和客户端地址
print(f"UDP Server:Received from {addr}: {data.decode()}")
# sendto方法需要两个参数:要发送的数据(这里是b"ACK",表示字节字符串形式的确认消息)和目标地址(addr)
server_socket.sendto(b"ACK", addr) # 发送响应
客户端代码示例如下:
python
import socket
# 创建一个UDP套接字。
# socket.AF_INET指定了地址族为IPv4,socket.SOCK_DGRAM指定了套接字类型为数据报(即UDP)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 使用sendto方法发送一个字节字符串"Hello UDP!"到指定的服务器地址和端口。
client_socket.sendto(b"Hello UDP!", ('127.0.0.1', 8888)) # 发送数据
# recvfrom方法接收最多1024个字节的数据,并返回两个值:接收到的数据和发送方的地址
data, addr = client_socket.recvfrom(1024) # 接收响应
print(f"Received from server: {data.decode()}")
上面代码的输出如下:
服务端:
kotlin
waiting for client data...
UDP Server:Received from ('127.0.0.1', 61373): Hello UDP!
waiting for client data...
客户端:
csharp
Received from server: ACK
3,异步http请求
python
"""
aiohttp 是一个用于异步 HTTP 客户端和服务器的库,
它允许在 Python 的异步编程模型(基于 asyncio)中执行 HTTP 请求。
asyncio 是 Python 的异步 I/O 框架,提供了编写单线程并发代码的基础设施。
"""
import aiohttp
import asyncio
# 定义了一个异步函数 fetch_data。在 Python 中,异步函数使用 async def 而不是普通的 def 来定义。
async def fetch_data():
try:
# 在Python的异步编程中,async with语句是一个上下文管理器(context manager)的异步版本,
# 它用于包裹一个异步执行的代码块,并确保在进入和退出该代码块时执行特定的设置和清理操作。
# aiohttp.ClientSession() 创建一个会话对象,该对象用于执行 HTTP 请求。
async with aiohttp.ClientSession() as session:
async with session.get("https://httpbin.org/get") as response:
response.raise_for_status() # Check for HTTP errors
# await 关键字用于等待异步操作完成,并获取其结果。
return await response.json() # Parse JSON directly
except aiohttp.ClientError as e:
print(f"Request failed: {e}")
return None
# 在Python中,if __name__ == "__main__": 这行代码有一个非常特定的用途。
# 它用于判断当前脚本是作为主程序运行还是被其他脚本作为模块导入。
# 当你直接运行一个Python脚本时,Python解释器会将该脚本的__name__变量设置为"__main__"。
# 但是,如果该脚本被其他脚本通过import语句导入,那么__name__变量将被设置为该脚本的文件名(不包含.py扩展名)
# if __name__ == "__main__": 这行代码后面的代码块只有在该脚本作为主程序运行时才会执行。
# 这允许一个Python文件既可以作为脚本直接运行,执行一些操作(比如运行测试或启动一个应用程序),也可以作为模块被其他脚本导入,提供函数、类和变量等。
if __name__ == "__main__":
# asyncio.run()是一个高级API,用于运行顶级入口点的异步程序,它会创建一个事件循环,运行传入的协程,并在协程完成后关闭事件循环。
result = asyncio.run(fetch_data())
# 如果fetch_data()函数返回了一个"真值"
# (在Python中,除了False、None、0、""(空字符串)和特定的空数据结构如空列表、空字典等之外,几乎所有值都被视为真值),
# 那么会打印出返回的数据。
if result:
print("Fetched Data:\n", result)
上面代码的输出是:
css
Fetched Data:
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'Python/3.12 aiohttp/3.11.12', 'X-Amzn-Trace-Id': 'Root=1-67a96f07-3238a8d53991033e0bd17b36'}, 'origin': '114.222.23.184', 'url': 'https://httpbin.org/get'}
4,处理Json
javascript
import requests
# 发送 JSON 数据
# 使用 requests.post 方法发送一个 POST 请求到 https://httpbin.org/post。
# json 参数将字典 {"name": "Alice", "age": 30} 自动编码为 JSON 格式,并作为请求体发送
response = requests.post(
"https://httpbin.org/post",
json={"name": "Alice", "age": 30}
)
# response.json()用于将响应体(即服务器返回的内容)从 JSON 格式解析为 Python 字典(或列表,取决于 JSON 数据的结构)。
data = response.json()
print(f"response.json:\n{data}")
# 执行 data["headers"]["Host"] 时,首先访问 data 字典中的 "headers" 键对应的值(即另一个字典),
# 然后在这个内部字典中访问 "Host" 键对应的值
print(f"headersHost:\t{data["headers"]["Host"]}") # 访问响应中的字段
上面的代码输出如下:
arduino
response.json:
{
'args': {},
'data': '
{
"name": "Alice",
"age": 30
}',
'files': {},
'form': {},
'headers': {
'Accept': '*/*',
'Accept-Encoding': 'gzip,
deflate',
'Content-Length': '28',
'Content-Type': 'application/json',
'Host': 'httpbin.org',
'User-Agent': 'python-requests/2.32.3',
'X-Amzn-Trace-Id': 'Root=1-67a9c136-437c5dd12a3ad44a53901926'
},
'json':
{
'age': 30,
'name': 'Alice'
},
'origin': '114.222.23.184',
'url': 'https://httpbin.org/post'
}
headersHost: httpbin.org