Skip to content

第 2 章 · GET 请求与响应处理

本章目标:掌握 GET 请求的完整用法,理解响应对象的所有核心属性,学会从 API 返回中提取所需数据。

2.1 GET 请求基础

GET 是最常用的 HTTP 方法,用于从服务器获取资源。requests 和 httpx 的 GET API 几乎一致:

python
import requests

# 最简单的 GET 请求
response = requests.get('https://httpbin.org/get')

# 使用 httpx 实现相同功能
import httpx
response = httpx.get('https://httpbin.org/get')

GET 请求可以携带 URL 参数(查询字符串),用于过滤或分页:

python
import requests

# 方法一:直接在 URL 中拼接(不推荐,容易出错)
resp = requests.get('https://api.github.com/search/repositories?q=python&sort=stars')

# 方法二:使用 params 参数(推荐)
params = {'q': 'python', 'sort': 'stars'}
resp = requests.get('https://api.github.com/search/repositories', params=params)

# 查看实际请求的 URL
print(resp.url)
# 输出: https://api.github.com/search/repositories?q=python&sort=stars

params 参数接受字典,requests 会自动编码为 URL 查询字符串。值为 None 的键会被跳过。

2.2 响应对象核心属性

每次请求都返回一个响应对象(requests.Responsehttpx.Response),包含丰富的信息:

python
import requests

resp = requests.get('https://httpbin.org/get')

# 状态码:HTTP 响应状态
print(resp.status_code)  # 200

# 文本内容:自动解码的字符串
print(resp.text[:200])

# 二进制内容:原始字节(适用于图片、文件等)
content = resp.content

# 响应的 URL(可能被重定向)
print(resp.url)

# 请求头
print(resp.headers['Content-Type'])

# 原始响应头(支持大小写不敏感访问)
print(resp.headers.get('content-type'))

响应编码自动检测:requests 会根据 HTTP 头部的 Content-Type 和 charset 自动猜测编码:

python
resp = requests.get('https://example.com/page')

# 查看自动检测的编码
print(resp.encoding)  # 如 'utf-8'

# 手动设置编码(如果自动检测错误)
resp.encoding = 'gbk'
print(resp.text)

2.3 JSON 响应处理

现代 API 绝大多数返回 JSON 格式数据。requests 提供便捷的 .json() 方法:

python
import requests

# GitHub API 返回 JSON
resp = requests.get('https://api.github.com/user')

# 解析为 Python 字典
data = resp.json()
print(data['login'])
print(data['public_repos'])

# 处理嵌套结构
for repo in data.get('repos', [])[:3]:
    print(f"- {repo['name']}: {repo['description']}")

# 检查 Content-Type(可选的安全习惯)
if resp.headers.get('Content-Type') == 'application/json':
    data = resp.json()

注意:如果响应不是有效 JSON,.json() 会抛出 requests.exceptions.JSONDecodeError。生产代码应该加异常处理:

python
try:
    data = resp.json()
except requests.exceptions.JSONDecodeError:
    print('响应不是 JSON 格式,使用 text 属性')
    print(resp.text)

2.4 复杂查询与 URL 模板

当需要构建复杂的查询时,可以组合多个参数:

python
import requests

# GitHub API 分页查询
page = 1
per_page = 10
params = {
    'q': 'machine+learning',
    'sort': 'stars',
    'order': 'desc',
    'page': page,
    'per_page': per_page
}

resp = requests.get('https://api.github.com/search/repositories', params=params)
data = resp.json()

# GitHub API 返回分页信息
print(f"Total: {data['total_count']}")
for item in data['items']:
    print(f"- {item['full_name']}: {item['stargazers_count']} stars")

对于 RESTful API,经常需要动态构建 URL:

python
import requests

# 使用 f-string 构建 URL(注意编码)
username = 'octocat'
resp = requests.get(f'https://api.github.com/users/{username}')

# 或者使用 requests 提供的 URL 构建工具
from urllib.parse import urljoin
base_url = 'https://api.github.com'
user_url = urljoin(base_url, f'users/{username}')
resp = requests.get(user_url)

2.5 本章小结

  • GET 请求通过 requests.get(url) 发起,httpx 语法相同;
  • 响应对象包含 status_codetextcontentheaders 等核心属性;
  • JSON 响应用 .json() 方法解析,注意处理解码异常;
  • params 参数自动编码为查询字符串,None 值的键会被跳过。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. requests.get() 的 params 参数主要作用是什么?

2. 响应对象 resp.text 和 resp.content 的区别是?

3. 调用 resp.json() 时发生 JSONDecodeError,可能的原因是?

4. 以下哪个属性可以查看实际发出的请求 URL(含查询字符串)?

🛠️ 动手实践

  1. 用 requests 获取 https://httpbin.org/get 的响应,打印状态码和所有响应头。
  2. 访问 GitHub API(https://api.github.com)获取用户信息,解析并打印用户名和公开仓库数。
  3. 使用 params 参数查询 https://httpbin.org/get?name=test&age=25,验证 URL 是否正确编码。