Requests 发送请求

Requests库提供了简单直观的API来发送HTTP请求。本章将详细介绍如何使用Requests发送各种类型的HTTP请求。

HTTP请求方法概述

HTTP协议定义了多种请求方法,用于指定对资源执行的操作类型。Requests库支持所有常见的HTTP方法:

方法 Requests函数 描述
GET requests.get() 请求指定资源,用于获取数据
POST requests.post() 向指定资源提交数据,用于创建新资源
PUT requests.put() 替换指定资源的所有内容,用于更新资源
PATCH requests.patch() 部分修改指定资源的内容
DELETE requests.delete() 删除指定资源
HEAD requests.head() 获取资源的元数据(响应头),不返回响应体
OPTIONS requests.options() 获取服务器支持的HTTP方法

所有请求方法都返回一个Response对象,包含服务器返回的所有信息。

基本GET请求

GET请求是最常见的HTTP请求方法,用于从服务器获取数据。

基本语法:
import requests

# 发送GET请求
response = requests.get('https://api.example.com/data')

# 检查请求是否成功
if response.status_code == 200:
    # 获取响应内容
    data = response.text
    print(f"响应内容: {data}")
else:
    print(f"请求失败,状态码: {response.status_code}")
重要属性说明:
  • response.status_code - HTTP状态码(200表示成功)
  • response.text - 响应内容(字符串格式)
  • response.content - 响应内容(字节格式)
  • response.json() - 将JSON响应解析为Python对象
  • response.headers - 响应头信息

完整的GET请求示例

import requests

# 发送GET请求到测试API
url = "https://jsonplaceholder.typicode.com/posts/1"
response = requests.get(url)

# 输出响应信息
print(f"URL: {response.url}")
print(f"状态码: {response.status_code}")
print(f"响应头: {response.headers['content-type']}")
print(f"编码: {response.encoding}")
print(f"内容长度: {len(response.text)} 字符")

# 输出响应内容
print("\n响应内容:")
print(response.text)
import requests
from requests.exceptions import HTTPError, Timeout, RequestException

url = "https://jsonplaceholder.typicode.com/posts/1"

try:
    # 设置超时时间为5秒
    response = requests.get(url, timeout=5)

    # 如果响应成功,没有抛出异常
    response.raise_for_status()

except HTTPError as http_err:
    print(f"HTTP错误发生: {http_err}")
except Timeout as timeout_err:
    print(f"请求超时: {timeout_err}")
except RequestException as req_err:
    print(f"请求异常: {req_err}")
except Exception as err:
    print(f"其他错误: {err}")
else:
    # 请求成功
    print("请求成功!")
    print(f"状态码: {response.status_code}")
    print(f"响应内容前100字符: {response.text[:100]}...")
import requests

# 从API获取JSON数据
url = "https://jsonplaceholder.typicode.com/posts/1"

response = requests.get(url)

if response.status_code == 200:
    # 解析JSON响应
    data = response.json()

    print("获取到的数据:")
    print(f"用户ID: {data['userId']}")
    print(f"文章ID: {data['id']}")
    print(f"标题: {data['title']}")
    print(f"内容: {data['body'][:50]}...")  # 只显示前50个字符

    # 也可以访问响应头信息
    print(f"\n响应头信息:")
    print(f"内容类型: {response.headers.get('content-type')}")
    print(f"服务器: {response.headers.get('server')}")
    print(f"日期: {response.headers.get('date')}")
else:
    print(f"请求失败,状态码: {response.status_code}")

传递URL参数

在GET请求中,经常需要向URL添加查询参数。Requests提供了两种方式来添加参数:

方法1:手动构建URL
import requests

# 手动构建带参数的URL
base_url = "https://api.example.com/search"
params = "?q=python&page=2&limit=10"
url = base_url + params

response = requests.get(url)
方法2:使用params参数(推荐)
import requests

# 使用params参数自动编码
url = "https://api.example.com/search"
params = {
    "q": "python",
    "page": 2,
    "limit": 10
}

response = requests.get(url, params=params)
print(f"实际请求URL: {response.url}")

URL参数示例

import requests

# 使用params传递多个参数
url = "https://httpbin.org/get"

params = {
    "name": "张三",
    "age": 25,
    "skills": ["python", "javascript", "sql"],
    "page": 1,
    "per_page": 20
}

response = requests.get(url, params=params)

print(f"请求URL: {response.url}")
print(f"状态码: {response.status_code}")

# 查看服务器收到的参数
if response.status_code == 200:
    data = response.json()
    print("\n服务器收到的参数:")
    print(data['args'])
服务器响应示例:
{
  "args": {
    "age": "25",
    "name": "张三",
    "page": "1",
    "per_page": "20",
    "skills": ["python", "javascript", "sql"]
  },
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Host": "httpbin.org",
    "User-Agent": "python-requests/2.28.1"
  },
  "origin": "123.45.67.89",
  "url": "https://httpbin.org/get?name=张三&age=25&skills=python&skills=javascript&skills=sql&page=1&per_page=20"
}
注意:
  • 使用params参数时,Requests会自动对参数进行URL编码
  • 对于列表参数,Requests会将其转换为多个同名参数(如skills=python&skills=javascript
  • 特殊字符和中文字符会自动进行编码,无需手动处理

基本POST请求

POST请求用于向服务器提交数据,通常用于创建新资源或提交表单数据。

POST请求的常见数据格式:
  • 表单数据 - 使用data参数,Content-Type为application/x-www-form-urlencoded
  • JSON数据 - 使用json参数,Content-Type为application/json
  • 文件上传 - 使用files参数,Content-Type为multipart/form-data

1. 发送表单数据

import requests

url = "https://httpbin.org/post"

# 表单数据
form_data = {
    "username": "john_doe",
    "password": "secret123",
    "email": "john@example.com"
}

# 发送POST请求(表单数据)
response = requests.post(url, data=form_data)

print(f"状态码: {response.status_code}")
print(f"响应头Content-Type: {response.headers['content-type']}")

if response.status_code == 200:
    result = response.json()
    print("\n服务器收到的表单数据:")
    print(result['form'])

2. 发送JSON数据

import requests
import json

url = "https://httpbin.org/post"

# JSON数据
json_data = {
    "title": "Python Requests教程",
    "content": "这是关于Requests库的教程",
    "author": {
        "name": "张三",
        "email": "zhangsan@example.com"
    },
    "tags": ["python", "http", "requests"],
    "published": True
}

# 方法1:使用json参数(推荐)
response = requests.post(url, json=json_data)

print(f"状态码: {response.status_code}")
print(f"响应头Content-Type: {response.headers['content-type']}")

if response.status_code == 200:
    result = response.json()
    print("\n服务器收到的JSON数据:")
    print(json.dumps(result['json'], indent=2, ensure_ascii=False))
方法2:手动序列化JSON
# 方法2:手动序列化并设置请求头
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json.dumps(json_data), headers=headers)

3. 文件上传

import requests

url = "https://httpbin.org/post"

# 准备文件
files = {
    'file': ('example.txt', open('example.txt', 'rb'), 'text/plain'),
    'image': ('photo.jpg', open('photo.jpg', 'rb'), 'image/jpeg')
}

# 其他表单字段
data = {
    'description': '这是上传的文件',
    'category': 'documents'
}

# 发送带文件的POST请求
response = requests.post(url, files=files, data=data)

print(f"状态码: {response.status_code}")

if response.status_code == 200:
    result = response.json()
    print("\n上传的文件信息:")
    print(f"文件名: {result['files']['file']}")
    print(f"图片名: {result['files']['image']}")
    print(f"表单字段: {result['form']}")
POST请求的最佳实践:
  • 发送JSON数据时,优先使用json参数而不是手动序列化
  • 上传文件时,使用files参数,Requests会自动设置正确的Content-Type
  • 对于复杂的表单数据,可以同时使用datafiles参数

其他请求方法

方法 示例代码 用途说明
PUT
requests.put(url, data=form_data)
替换整个资源,用于更新操作
PATCH
requests.patch(url, json=partial_data)
部分更新资源,只发送需要修改的字段
DELETE
requests.delete(url)
删除指定资源
HEAD
requests.head(url)
获取资源元数据(响应头),不返回响应体
OPTIONS
requests.options(url)
获取服务器支持的HTTP方法

完整示例:CRUD操作

import requests

base_url = "https://jsonplaceholder.typicode.com/posts"

print("=== 1. 获取所有文章 (GET) ===")
response = requests.get(base_url)
print(f"状态码: {response.status_code}, 文章数量: {len(response.json())}")

print("\n=== 2. 创建新文章 (POST) ===")
new_post = {
    "title": "Python Requests教程",
    "body": "这是关于Requests库的详细教程",
    "userId": 1
}
response = requests.post(base_url, json=new_post)
print(f"状态码: {response.status_code}")
if response.status_code == 201:  # 201表示资源创建成功
    created_post = response.json()
    post_id = created_post['id']
    print(f"创建成功! 文章ID: {post_id}")

print("\n=== 3. 更新文章 (PUT) ===")
update_url = f"{base_url}/{post_id}"
updated_post = {
    "id": post_id,
    "title": "更新后的标题",
    "body": "更新后的内容",
    "userId": 1
}
response = requests.put(update_url, json=updated_post)
print(f"状态码: {response.status_code}")
if response.status_code == 200:
    print("更新成功!")

print("\n=== 4. 部分更新文章 (PATCH) ===")
partial_update = {
    "title": "再次更新的标题"
}
response = requests.patch(update_url, json=partial_update)
print(f"状态码: {response.status_code}")
if response.status_code == 200:
    print("部分更新成功!")

print("\n=== 5. 删除文章 (DELETE) ===")
response = requests.delete(update_url)
print(f"状态码: {response.status_code}")
if response.status_code == 200:
    print("删除成功!")

print("\n=== 6. 获取文章元数据 (HEAD) ===")
response = requests.head(f"{base_url}/1")
print(f"状态码: {response.status_code}")
print(f"响应头: {dict(response.headers)}")

print("\n=== 7. 查看支持的HTTP方法 (OPTIONS) ===")
response = requests.options(base_url)
print(f"状态码: {response.status_code}")
print(f"允许的HTTP方法: {response.headers.get('allow')}")

设置请求头

可以通过headers参数自定义请求头,这对于API认证、设置内容类型等场景非常重要。

基本用法:
import requests

url = "https://httpbin.org/headers"

# 自定义请求头
headers = {
    'User-Agent': 'MyApp/1.0',
    'Accept': 'application/json',
    'Authorization': 'Bearer your-token-here',
    'X-Custom-Header': 'CustomValue'
}

response = requests.get(url, headers=headers)

if response.status_code == 200:
    data = response.json()
    print("服务器接收到的请求头:")
    print(data['headers'])

常见请求头示例

请求头 示例值 用途
User-Agent MyApp/1.0 标识客户端应用程序
Authorization Bearer token123 API认证令牌
Content-Type application/json 请求体的媒体类型
Accept application/json 客户端期望的响应类型
Accept-Language zh-CN,zh;q=0.9 客户端接受的语言
Referer https://example.com 来源页面URL
X-API-Key your-api-key API密钥(自定义头)

超时设置

为了防止请求无限制等待,应该总是设置超时时间。

import requests
from requests.exceptions import Timeout

url = "https://httpbin.org/delay/10"  # 这个端点会延迟10秒响应

try:
    # 设置超时时间为3秒
    response = requests.get(url, timeout=3)
    print("请求成功")
except Timeout:
    print("请求超时!服务器在3秒内没有响应")

# 也可以分别设置连接超时和读取超时
try:
    # 连接超时: 2秒, 读取超时: 5秒
    response = requests.get(url, timeout=(2, 5))
    print("请求成功")
except Timeout as e:
    print(f"超时异常: {e}")
重要提示:
  • 总是设置超时 - 生产环境中必须设置超时,防止程序无限等待
  • 合理的超时值 - 根据网络环境和API特性设置合理的超时时间
  • 连接超时 vs 读取超时 - 连接超时是建立连接的最大时间,读取超时是获取响应的最大时间

使用Session对象

Session对象可以跨请求保持某些参数,如cookies、headers等,同时会自动使用连接池,提高性能。

Session的基本用法:
import requests

# 创建Session对象
session = requests.Session()

# 为Session设置默认参数
session.headers.update({
    'User-Agent': 'MyApp/1.0',
    'Accept': 'application/json'
})

# 所有通过这个Session发送的请求都会使用这些默认参数
response1 = session.get('https://httpbin.org/get')
print(f"第一个请求状态码: {response1.status_code}")

# 可以临时覆盖默认参数
response2 = session.get('https://httpbin.org/get',
                       headers={'User-Agent': 'TempAgent'})
print(f"第二个请求状态码: {response2.status_code}")

# Session会自动处理cookies
response3 = session.post('https://httpbin.org/cookies/set/sessioncookie/123456789')
response4 = session.get('https://httpbin.org/cookies')
print(f"Cookies: {response4.json()}")

# 关闭Session(虽然不是必须的,但是好习惯)
session.close()
使用Session的优势:
  • 持久化参数 - 跨请求保持headers、cookies等参数
  • 连接池 - 重用TCP连接,提高性能
  • cookie持久化 - 自动处理cookie,模拟浏览器行为
  • 默认设置 - 为所有请求设置统一的默认参数

Session与普通请求的性能对比

import requests
import time

def test_without_session():
    """不使用Session,每次创建新连接"""
    start = time.time()

    for i in range(10):
        # 每次请求都创建新连接
        response = requests.get('https://httpbin.org/get')

    return time.time() - start

def test_with_session():
    """使用Session,重用连接"""
    start = time.time()

    with requests.Session() as session:
        for i in range(10):
            # 重用Session中的连接
            response = session.get('https://httpbin.org/get')

    return time.time() - start

# 运行测试
time_without_session = test_without_session()
time_with_session = test_with_session()

print(f"不使用Session: {time_without_session:.2f}秒")
print(f"使用Session: {time_with_session:.2f}秒")
print(f"性能提升: {(time_without_session - time_with_session)/time_without_session*100:.1f}%")

总结

本章详细介绍了如何使用Requests库发送各种HTTP请求:

  1. GET请求 - 使用requests.get()获取数据,通过params参数传递查询参数
  2. POST请求 - 使用requests.post()提交数据,支持表单、JSON和文件上传
  3. 其他请求方法 - PUT、PATCH、DELETE、HEAD、OPTIONS等都有对应的函数
  4. 请求头设置 - 通过headers参数自定义请求头
  5. 超时设置 - 使用timeout参数防止请求无限等待
  6. Session对象 - 使用Session跨请求保持参数,重用连接提高性能

在实际开发中,建议总是设置超时时间,对于需要发送多个请求到同一服务器的场景,使用Session对象可以提高性能。