在现代 Web 开发的广阔天地中,数据交互是构建动态应用程序的核心。无论是为了从服务器获取最新的天气信息,还是向远程服务提交用户表单,HTTP 请求都是客户端与服务器之间沟通的桥梁。在这篇文章中,我们将深入探讨两种最基础也最重要的 HTTP 请求方法——GET 和 POST,并学习如何利用 Python 中优雅的 requests 库来轻松实现它们。
通过阅读这篇文章,你将不仅能掌握这两种请求的基本用法,还能理解它们背后的工作原理、参数传递方式以及在实际项目中的最佳实践。让我们开始这段探索之旅吧。
HTTP 协议与请求方法概览
HTTP(超文本传输协议)是互联网上客户端(如浏览器)与服务器之间进行通信的基础规则。我们可以把它想象成一种通用的语言,双方通过这种语言来交换信息。在这个协议中,请求方法定义了我们希望对资源执行的操作类型。
虽然 HTTP 定义了多种请求方法(如 PUT、DELETE 等),但在日常开发中,我们接触最多的无疑是 GET 和 POST。
- GET 请求:通常用于从服务器获取数据。就像你从图书馆借书,你只是去“拿”信息,并不会改变图书馆里的藏书状态。GET 请求的参数通常会显示在 URL 中,因此可以被缓存或收藏为书签。
- POST 请求:通常用于向服务器提交数据以进行处理。这就像你在图书馆填写一张借书申请表或捐赠一本书,你的行为会触发服务器端的某些变化(如更新数据库)。POST 请求的参数包含在请求体中,比 GET 更适合传输敏感信息或大量数据。
为什么选择 Requests 库?
Python 的标准库(如 INLINECODE590ed6f8)虽然也能处理 HTTP 请求,但它们的代码往往繁琐且不够直观。对于现代开发者来说,INLINECODE944fe92a 库是处理 HTTP 请求的“事实标准”。
它的 motto 就是“HTTP for Humans”。正如其名,requests 设计得极其优雅,让我们能够用极少的代码完成复杂的操作。在开始之前,请确保你的环境中已经安装了这个库。你可以在终端或命令行中运行以下命令来安装:
pip install requests
安装完成后,我们就可以正式开始了。
发起 GET 请求:获取数据的艺术
GET 请求是我们与 API 交互最常见的方式。让我们从一个实际的场景出发:假设我们需要根据地址获取地理坐标(经纬度)。这在前端开发中非常常见,比如我们需要在地图上标记一个位置。
场景示例:地理编码 API
我们将模拟向地图服务 API 发送请求,查询“delhi technological university”的坐标信息。API(应用程序接口)允许我们以一种受限且结构化的方式访问远程程序的功能。大多数现代 API 会以 JSON(JavaScript 对象表示法)格式返回数据,而在 Python 中,JSON 对象会被自动转换为字典,这使得数据处理变得非常方便。
以下是完整的代码实现:
# 导入 requests 库
import requests
# 定义 API 端点
# 注意:实际开发中请替换为可用的 API 地址
URL = "http://maps.googleapis.com/maps/api/geocode/json"
# 定义我们要查询的位置
location = "delhi technological university"
# 定义参数字典
# requests 会自动将这些参数附加到 URL 后面
PARAMS = {‘address‘: location}
# 发送 GET 请求
# 我们将 URL 和参数传递给 get 方法
r = requests.get(url=URL, params=PARAMS)
# 检查请求是否成功
# 状态码 200 表示成功
if r.status_code == 200:
# 将响应内容解析为 JSON 格式
data = r.json()
# 提取我们需要的数据
# 注意:这里使用了字典的嵌套访问
try:
latitude = data[‘results‘][0][‘geometry‘][‘location‘][‘lat‘]
longitude = data[‘results‘][0][‘geometry‘][‘location‘][‘lng‘]
formatted_address = data[‘results‘][0][‘formatted_address‘]
# 打印结果
print(f"纬度: {latitude}")
print(f"经度: {longitude}")
print(f"格式化地址: {formatted_address}")
except (KeyError, IndexError):
print("无法解析返回的数据,请检查 API 响应结构。")
else:
print(f"请求失败,状态码: {r.status_code}")
深入解析:GET 请求的工作原理
在上述代码中,有几个关键点值得我们深入探讨,这有助于你更好地理解 HTTP 请求的机制。
1. 参数的处理 (params)
你可能注意到了 INLINECODE22f84fe0 字典。在代码中,我们定义了一个字典 INLINECODE731b48e6。requests 库非常智能,它会自动将这个字典转换为 URL 查询字符串。
如果你在代码中打印 r.url,你会看到实际发送的请求 URL 变成了这样:
http://maps.googleapis.com/maps/api/geocode/json?address=delhi+technological+university
这就是浏览器地址栏里常见的格式。INLINECODE1a57120c 帮我们处理了 URL 编码(例如将空格转换为 INLINECODE2b97443e 或 %20),这在手动拼接 URL 时非常容易出错。
2. 响应对象 (r)
INLINECODE2b0ccb85 返回的是一个 INLINECODEd80e2550 对象。这个对象包含了服务器返回的所有信息,包括:
- 状态码 (
r.status_code):告诉我们请求是成功 (200)、重定向 (3xx)、客户端错误 (4xx) 还是服务器错误 (5xx)。 - 响应头 (
r.headers):包含了服务器类型、内容类型等元数据。 - 响应体 (INLINECODEe5f7150c 或 INLINECODEfde93904):这是服务器返回的原始数据。
- JSON 数据 (
r.json()):如果响应头声明了是 JSON,我们可以直接用这个方法将其解析为 Python 字典。
发起 POST 请求:向服务器发送数据
当我们需要上传文件、提交表单或发送敏感信息(如密码)时,GET 请求就不太适用了,因为它的参数是暴露在 URL 中的。这时,POST 请求 就派上用场了。POST 将数据放在“请求体”中传输,对于用户来说是不可见的,也更安全。
场景示例:代码上传服务
让我们来看一个实际的例子。假设我们要开发一个功能,将本地的代码片段自动上传到 Pastebin(一个代码粘贴网站)并获取分享链接。这需要我们向其 API 发送 POST 请求。
> 注意:在使用此类 API 前,你通常需要注册账号并获取一个 API 密钥。这是服务器识别你是谁的凭证。
以下是实现这一功能的代码:
import requests
# API 端点
API_ENDPOINT = "https://pastebin.com/api/api_post.php"
# 你的 API 密钥(请替换为你自己的真实密钥)
API_KEY = "XXXXXXXXXXXXXXXXX"
# 你想粘贴的源代码
source_code = ‘‘‘
def greet(name):
print(f"Hello, {name}!")
if __name__ == "__main__":
greet("Developer")
‘‘‘
# 准备要发送的数据
# 对于 POST 请求,数据通常作为字典发送
# requests 库会自动对其进行编码
data = {
‘api_dev_key‘: API_KEY,
‘api_option‘: ‘paste‘,
‘api_paste_code‘: source_code,
‘api_paste_format‘: ‘python‘
}
# 发送 POST 请求
try:
r = requests.post(url=API_ENDPOINT, data=data)
# 提取响应文本
# 如果是 Pastebin API,成功时它直接返回新粘贴页面的 URL
if r.ok:
pastebin_url = r.text
print(f"代码已成功上传!访问链接: {pastebin_url}")
else:
# 很多 API 会在出错时返回错误信息
print(f"上传失败,状态码: {r.status_code}")
print(f"错误详情: {r.text}")
except requests.exceptions.RequestException as e:
# 捕获网络相关的异常(如连接超时、DNS查询失败等)
print(f"发生网络错误: {e}")
深入解析:POST 请求的关键要素
在这个例子中,我们使用了 requests.post() 方法。让我们看看它与 GET 有什么不同。
1. data 参数
在 GET 请求中,我们使用 INLINECODEf5dcbce7 来附加 URL 参数;而在 POST 请求中,我们通常使用 INLINECODEc4a71a70 来发送请求体数据。
在上面的代码中,INLINECODE2e5514df 字典包含了 API 所需的各种字段(API 密钥、代码内容、格式等)。默认情况下,INLINECODEf39d1238 会将这个字典编码为 application/x-www-form-urlencoded 格式,这就像我们在网页上提交 HTML 表单一样。
2. 读取响应 (r.text)
请注意这里我们使用的是 INLINECODE84ea1ab2 而不是 INLINECODEb7e59c13。这是因为 Pastebin 的 API 在成功创建粘贴时,直接在响应体中返回一个纯文本的 URL 字符串,而不是一个 JSON 对象。这提醒我们,在处理 API 时,必须仔细阅读文档,了解服务器返回的数据格式。
进阶话题:处理 JSON 数据与异常
在实际工作中,我们经常需要与 RESTful API 交互,这些 API 绝大多数都接受和发送 JSON 数据。虽然 data 参数处理表单编码很好用,但在发送 JSON 时,我们需要更精确的控制。
发送 JSON 数据的示例
假设我们在与一个现代化的 Web 服务交互,它要求接收 JSON 格式的数据。我们可以这样做:
import requests
import json
URL = "https://httpbin.org/post"
# 这是一个复杂的字典,包含嵌套信息
payload = {
‘user_id‘: 123,
‘details‘: {
‘name‘: ‘Alice‘,
‘role‘: ‘Admin‘,
‘preferences‘: [‘notifications‘, ‘dark_mode‘]
},
‘timestamp‘: ‘2023-10-27T10:00:00‘
}
# 方式一:手动转 JSON 并设置 Content-Type
headers = {‘Content-Type‘: ‘application/json‘}
r = requests.post(URL, data=json.dumps(payload), headers=headers)
# 方式二(推荐):使用 json 参数
# requests 会自动进行序列化并添加正确的头信息
r = requests.post(URL, json=payload)
if r.status_code == 200:
response_data = r.json()
print("服务器返回的 JSON 数据:", json.dumps(response_data, indent=2))
关键点解析:
使用 INLINECODEb12ca262 参数是最佳实践。它不仅帮我们把 Python 字典转换成 JSON 字符串,还自动设置了请求头中的 INLINECODEc22100f8。这告诉服务器:“嘿,我发过来的数据是 JSON 格式的,请用相应的解析器来处理它。”
健壮的异常处理
网络是不可靠的。任何网络请求都可能因为各种原因失败(断网、服务器宕机、超时)。一个专业的开发者必须预料到这些情况。
我们可以使用 INLINECODEa796d95a 块来捕获 INLINECODEe34b57a7 可能抛出的异常:
-
ConnectionError:网络连接问题(如 DNS 查询失败、拒绝连接)。 -
Timeout:服务器在指定时间内没有响应。 -
TooManyRedirects:请求超过了配置的最大重定向次数。 - INLINECODE15b4c400:虽然这不是默认抛出的,但我们可以使用 INLINECODEe35e60f5 来检查 4xx 或 5xx 错误。
try:
# 设置超时时间为 5 秒
response = requests.get(‘https://api.github.com/invalid‘, timeout=5)
# 如果状态码是 4xx 或 5xx,这将抛出 HTTPError
response.raise_for_status()
except requests.exceptions.HTTPError as errh:
print(f"Http Error: {errh}")
except requests.exceptions.ConnectionError as errc:
print(f"Error Connecting: {errc}")
except requests.exceptions.Timeout as errt:
print(f"Timeout Error: {errt}")
except requests.exceptions.RequestException as err:
print(f"OOps: Something Else: {err}")
常见问题与最佳实践
在掌握基本用法后,让我们来看看一些进阶技巧和常见的“坑”。
1. 设置 User-Agent
有些网站会拒绝来自脚本的请求(它们通过 User-Agent 识别是浏览器还是脚本)。为了模拟浏览器访问,我们可以自定义请求头:
headers = {
‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36‘
}
r = requests.get(‘https://example.com‘, headers=headers)
2. 处理会话
如果你需要向同一个网站发送多个请求(比如先登录,然后访问个人页面),使用 Session 对象可以保持 Cookie 等状态信息,还能利用 TCP 连接复用来提高性能(HTTP Keep-Alive)。
with requests.Session() as session:
# 第一次请求登录
session.post(url=‘https://example.com/login‘, data={‘user‘: ‘me‘, ‘pass‘: ‘123‘})
# 第二次请求会自动带上登录后的 Cookie
profile = session.get(‘https://example.com/profile‘)
3. 超时设置
永远不要让你的请求无限期等待。你应该总是设置 INLINECODE44443ac2 参数,它是一个元组 INLINECODE2e9df47a。例如 timeout=(3.05, 27) 表示连接必须在 3.05 秒内建立,服务器必须在 27 秒内返回数据。
总结
在这篇文章中,我们深入探讨了如何使用 Python 的 requests 库来处理 GET 和 POST 请求。我们不仅学习了基本的语法,还了解了参数传递、JSON 处理、异常捕获以及如何模拟浏览器行为。
掌握这些技能后,你可以轻松地与大多数 Web API 进行交互,无论是抓取网页数据、自动化测试,还是构建复杂的后端服务。记住,实践出真知,尝试修改上面的代码,去调用一些你感兴趣的公开 API(如天气服务、电影数据库等),你会对 HTTP 通信有更深刻的理解。
祝你编码愉快!