56·模块十二:网络编程进阶

HTTP 请求与 requests 库

httprequestsweb

第 56 课:HTTP 请求与 requests 库

模块十二:网络编程 | 难度:intermediate | 标签:http, requests, web


学习目标

  1. 理解HTTP协议基础:了解GET、POST、PUT、DELETE等基本请求方法及其用途。
  2. 掌握requests库的使用:学会使用requests库发送各种HTTP请求,并获取响应。
  3. 处理请求参数与响应数据:能够向URL添加查询参数,设置请求头,并正确解析JSON、文本等格式的响应数据。
  4. 了解常见的HTTP状态码:理解200、404、500等状态码的含义,用于调试和判断请求结果。
  5. 学会基本的错误处理:能够在代码中捕获网络请求可能发生的异常(如超时、连接错误)。

核心概念

什么是HTTP?

想象一下,你在浏览器地址栏输入一个网址(如https://api.github.com)并按下回车,浏览器就会向存放这个网站的服务器发送一个 HTTP请求。服务器处理完请求后,会将一个 HTTP响应 发送回你的浏览器,浏览器再将响应内容(如HTML页面、图片、JSON数据)渲染出来。

HTTP(超文本传输协议)就是浏览器(或你的Python程序)与服务器之间沟通的"语言"。它基于请求-响应模型,主要包含两种核心角色:

  • 客户端:发起请求的一方(如你的浏览器或Python脚本)。
  • 服务器:接收请求并返回响应的一方。

为什么选择 requests 库?

Python内置了一个名为 urllib 的库可以用来发送HTTP请求,但其API相对繁琐。requests 库由社区开发者Kenneth Reitz编写,它的理念是"为人类而生",提供了极其简洁、优雅且功能强大的API,极大地简化了HTTP请求的编写过程,是目前Python生态中处理HTTP请求的事实标准

一个简单的对比:

# 使用内置的urllib(相对复杂)
import urllib.request
response = urllib.request.urlopen('https://api.github.com')
data = response.read().decode('utf-8')

# 使用requests库(非常直观)
import requests
response = requests.get('https://api.github.com')
data = response.text

代码示例

示例1:发送一个基本的GET请求

GET请求通常用于从服务器获取数据

import requests
import json

# 1. 发送一个简单的GET请求
response = requests.get('https://httpbin.org/get')

# 2. 查看响应状态码 (200 表示成功)
print(f"状态码: {response.status_code}")

# 3. 查看响应头
print(f"Content-Type: {response.headers['Content-Type']}")

# 4. 获取响应内容
# response.text 返回解码后的字符串
print("响应文本(前100字符):", response.text[:100])

# 如果响应是JSON格式,可以使用.json()方法直接解析为字典
data = response.json()
print("\n解析后的JSON数据:")
print(json.dumps(data, indent=2, ensure_ascii=False)) # 美化打印

示例2:发送带参数的请求

查询参数是附加在URL后面,用于向服务器传递额外信息的键值对。

import requests

# 模拟在搜索引擎中搜索"Python requests"
params = {
    'q': 'Python requests',
    'page': 1,
    'lang': 'en'
}

# requests会自动将参数编码并添加到URL后面
# 实际请求的URL会是: https://httpbin.org/get?q=Python+requests&page=1&lang=en
response = requests.get('https://httpbin.org/get', params=params)

# 查看实际请求的URL
print("实际请求的URL:", response.url)
print("状态码:", response.status_code)

示例3:发送POST请求

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

import requests

# 1. 发送一个表单格式的POST请求 (Content-Type: application/x-www-form-urlencoded)
form_data = {
    'username': 'testuser',
    'password': 's3cr3t'
}
response1 = requests.post('https://httpbin.org/post', data=form_data)
print("表单POST响应:", response1.status_code)

# 2. 发送一个JSON格式的POST请求 (更常用)
json_data = {
    'name': 'Alice',
    'age': 30,
    'hobbies': ['reading', 'coding']
}
# 使用 `json` 参数,requests会自动设置正确的Content-Type头并序列化数据
response2 = requests.post('https://httpbin.org/post', json=json_data)
print("JSON POST响应:", response2.status_code)
print("服务器收到的JSON:", response2.json()['json']) # httpbin会回显它收到的数据

示例4:设置自定义请求头

有时需要设置User-Agent(标识你的程序身份)或Authorization(携带认证令牌)等自定义请求头。

import requests

headers = {
    'User-Agent': 'My Python Learning Bot 1.0',
    'Accept': 'application/json',
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN' # 模拟认证令牌
}

response = requests.get('https://httpbin.org/headers', headers=headers)
print("服务器收到的请求头:")
print(json.dumps(response.json(), indent=2))

示例5:处理其他HTTP方法与异常

import requests
from requests.exceptions import HTTPError, Timeout, ConnectionError

# 常用方法:PUT (更新), DELETE (删除), PATCH (部分更新)
# response = requests.put('https://httpbin.org/put', data={'key': 'value'})
# response = requests.delete('https://httpbin.org/delete')

# 错误处理示例
try:
    # 设置超时时间(秒),防止程序长时间卡住
    response = requests.get('https://httpbin.org/delay/3', timeout=2)
    response.raise_for_status() # 如果状态码不是2xx,抛出HTTPError异常
    print("请求成功!")
except Timeout:
    print("错误:请求超时。服务器在指定时间内未响应。")
except ConnectionError:
    print("错误:网络连接问题。请检查你的网络。")
except HTTPError as e:
    print(f"错误:HTTP错误 {e.response.status_code}")
except requests.exceptions.RequestException as e:
    # 捕获所有requests可能抛出的异常的基类
    print(f"发生未知请求错误: {e}")

实践练习

练习1:获取并展示GitHub用户信息

要求

  1. 使用requests库向 https://api.github.com/users/{username} 发送GET请求(将{username}替换为一个真实的GitHub用户名,如torvalds)。
  2. 解析返回的JSON数据。
  3. 打印出该用户的namebiopublic_repos数量。
  4. 处理可能出现的用户不存在(404状态码)或网络错误。

预期输出(示例,具体数据随用户名变化):

用户名: torvalds
姓名: Linus Torvalds
简介: Software engineer, creator of Linux and Git.
公开仓库数: 8

练习2:模拟登录(POST请求)

要求

  1. 使用requests库向 https://httpbin.org/post 发送一个POST请求。
  2. 请求体为一个JSON对象,包含"username""password"两个字段(值自定义)。
  3. 打印出服务器返回的状态码,以及服务器在formjson字段中回显的你发送的用户名。

预期输出(示例):

状态码: 200
服务器回显的用户名 (在json中): testuser

练习3:综合练习 - 自定义请求与数据提取

要求

  1. https://httpbin.org/headers 发送一个GET请求。
  2. 自定义请求头,添加一个键为X-My-Custom-Header,值为你自己名字的头。
  3. 解析响应JSON,打印出服务器认为你发送的所有请求头
  4. 特别地,打印出你自定义的头是否被服务器正确接收。

预期输出(示例):

服务器收到的所有请求头:
{
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Host": "httpbin.org",
    "User-Agent": "python-requests/2.31.0",
    "X-Amzn-Trace-Id": "Root=1-6518f1c3-...",
    "X-My-Custom-Header": "张三"  // 你的自定义头
  }
}
我的自定义头 'X-My-Custom-Header' 被成功接收!

常见错误

  1. 忘记检查状态码:只获取response而不检查response.status_code或调用response.raise_for_status(),可能对失败的请求进行后续操作,导致程序出错。

    # 错误示范
    response = requests.get(url)
    data = response.json() # 如果请求失败(如404),这行会抛出异常
    
    # 正确做法
    response = requests.get(url)
    response.raise_for_status() # 如果状态码不是2xx,则抛出异常
    # 或者手动检查
    if response.status_code == 200:
        data = response.json()
    else:
        print(f"请求失败,状态码:{response.status_code}")
    
  2. 混淆 datajson 参数:发送POST请求时,data参数用于发送表单数据,json参数用于发送JSON数据。用错会导致服务器解析失败。

    # 发送JSON数据,应使用json参数
    requests.post(url, json={'key': 'value'}) # 正确
    requests.post(url, data={'key': 'value'}) # 错误,这会发送表单数据
    
  3. 未处理编码问题:使用response.text获取文本时,requests会根据响应头猜测编码。对于非UTF-8编码的页面,可能出现乱码。可以使用response.encoding属性查看和设置。

    # 指定编码
    response.encoding = 'gbk' # 如果已知页面是GBK编码
    print(response.text)
    # 或者直接使用二进制内容,自行解码
    print(response.content.decode('utf-8'))
    
  4. 未设置超时:如果不设置timeout参数,网络请求可能会无限期地等待,导致程序卡死。

    # 总是设置一个合理的超时时间
    response = requests.get(url, timeout=5) # 5秒超时
    
  5. 硬编码敏感信息:将API密钥、密码等敏感信息直接写在代码中(如示例4的Authorization头)。应使用环境变量或配置文件来管理。

小结

  • HTTP基础:我们通过requests库,用Python代码实现了与浏览器类似的功能——向服务器发送请求(GET/POST等)并接收响应。这是爬虫、调用API、自动化脚本的基础。
  • requests库优势:它隐藏了底层复杂性,提供了requests.get(), .post(), .json(), .status_code等直观的方法和属性,让你专注于业务逻辑。
  • 关键操作
    • 获取数据requests.get(url, params=...)
    • 提交数据requests.post(url, data=..., json=...)
    • 设置头部requests.get(url, headers=...)
    • 处理响应response.status_code, .headers, .text, .json()
  • 重要习惯:始终检查状态码、处理可能的异常、设置超时、安全地管理敏感信息。
  • 下一步:学会发送请求是第一步,下一课我们将学习如何使用requests库调用符合RESTful设计规范的API,并解析更复杂的JSON数据。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「RESTful API 使用与数据解析」 以巩固所学知识。