杰瑞科技汇

Python requests如何处理文件上传与下载?

准备工作:安装 requests

如果你的 Python 环境中还没有安装 requests,可以通过 pip 进行安装:

Python requests如何处理文件上传与下载?-图1
(图片来源网络,侵删)
pip install requests

从服务器下载文件

这是最常见的用例之一,这里的“文件”可以是任何可以被服务器作为响应返回的内容,比如图片、PDF、CSV 文件、压缩包等。

核心方法:requests.get()

下载文件的关键在于正确处理响应对象 Responsecontent 属性。

  • response.content: 返回的是二进制数据bytes),这是下载图片、视频、PDF 等二进制文件时必须使用的属性。
  • response.text: 返回的是字符串str),它已经经过了编码解码,适用于下载 HTML、TXT、JSON 等文本文件。

示例1:下载并保存一张图片(二进制文件)

假设我们要下载一张示例图片并保存到本地。

import requests
# 目标文件的 URL
url = "https://www.python.org/static/community_logos/python-logo-master-v3-TM.png"
# 1. 发送 GET 请求
try:
    response = requests.get(url, stream=True) # stream=True 对于大文件非常重要
    # 2. 检查请求是否成功 (状态码 200)
    response.raise_for_status()  # 如果请求失败 (404, 500), 会抛出异常
    # 3. 获取文件名(从 URL 中提取)
    filename = url.split("/")[-1]
    # 4. 以二进制写入模式 ('wb') 保存文件
    with open(filename, 'wb') as f:
        # response.iter_content(chunk_size=8192) 可以分块读取内容,节省内存
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)
    print(f"文件 '{filename}' 下载成功!")
except requests.exceptions.RequestException as e:
    print(f"下载失败: {e}")

代码解析:

Python requests如何处理文件上传与下载?-图2
(图片来源网络,侵删)
  1. stream=True: 这是一个非常重要的参数,尤其是在下载大文件时,它告诉 requests 不要立即下载整个响应体到内存,而是允许我们以流的方式逐步读取数据,这样可以避免内存耗尽。
  2. response.raise_for_status(): 这是一个好习惯,HTTP 请求返回了错误的状态码(如 404 Not Found, 500 Server Error),它会抛出一个 HTTPError 异常,帮助我们快速定位问题。
  3. response.iter_content(chunk_size=8192): 这是流式读取的核心,它会返回一个迭代器,每次生成一块数据(这里设置为 8KB),我们在一个循环中逐块写入文件,非常高效。
  4. with open(..., 'wb') as f: 使用 with 语句可以确保文件在操作完成后被自动关闭。'wb' 表示以二进制写入模式打开文件。

示例2:下载并保存一个文本文件(如 CSV)

对于文本文件,我们可以使用 response.text

import requests
url = "https://raw.githubusercontent.com/datasets/covid-19/main/data/time-series-19-covid-combined.csv"
try:
    response = requests.get(url)
    response.raise_for_status()  # 检查请求是否成功
    # 获取文件名
    filename = url.split("/")[-1]
    # 以文本写入模式 ('w') 保存文件
    # 需要指定编码,通常是 utf-8
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(response.text)
    print(f"文件 '{filename}' 下载成功!")
except requests.exceptions.RequestException as e:
    print(f"下载失败: {e}")

上传文件到服务器

上传文件通常使用 POSTPUT 请求。requests 让这个过程变得非常简单。

核心方法:requests.post()

你需要准备一个字典,files 参数是关键。files 参数的值是一个字典,键是服务器端期望的表单字段名,值是一个文件元组。

文件元组的格式为:(文件名, 文件对象, content_type)

Python requests如何处理文件上传与下载?-图3
(图片来源网络,侵删)
  • 文件名: 字符串,上传到服务器时显示的文件名。
  • 文件对象: 一个文件对象(通过 open() 以二进制读取模式 'rb' 打开)。
  • content_type (可选): 文件的 MIME 类型,如 image/jpeg

示例:上传本地文件到服务器

假设有一个本地文件 my_report.pdf,我们要将它上传到一个支持文件上传的 API。

import requests
# 目标上传 URL (这里使用一个公共的测试 API)
url = "https://httpbin.org/post"
# 本地要上传的文件路径
file_path = "my_report.pdf" # 请确保这个文件存在
# 准备要上传的文件
# 'file' 是服务器端期望的字段名,请根据 API 文档修改
# ('my_report.pdf', open(file_path, 'rb'), 'application/pdf') 中的 'application/pdf' 是可选的
files = {
    'file': (file_path, open(file_path, 'rb'))
}
# 其他表单数据 (可选)
data = {
    'description': '这是我的月度报告'
}
try:
    # 发送 POST 请求,包含文件和其他数据
    response = requests.post(url, files=files, data=data)
    response.raise_for_status()  # 检查请求是否成功
    # 打印服务器返回的响应
    print("上传成功!服务器响应:")
    print(response.json())
except requests.exceptions.RequestException as e:
    print(f"上传失败: {e}")
finally:
    # 确保文件被关闭
    files['file'][1].close()

代码解析:

  1. open(file_path, 'rb'): 我们必须以二进制读取模式 ('rb') 打开本地文件。
  2. files = {'file': ...}: 构建一个字典,键 'file' 是向服务器提交数据时使用的字段名,这个字段名需要根据目标服务器的 API 文档来确定。
  3. data 参数: 如果除了文件本身,还需要提交其他表单数据(如描述、标签等),可以使用 data 参数。
  4. finally 块: 这是一个很好的编程习惯,无论请求成功还是失败,finally 块中的代码都会被执行,确保我们打开的文件被正确关闭,防止资源泄漏。

在内存中处理文件

有时候你并不想将文件保存到磁盘,而是想在内存中直接处理它(解析一个 CSV 文件或对图片进行一些操作)。

这非常简单,直接使用 response.contentresponse.text 即可。

示例:下载 CSV 并直接用 csv 模块解析

import requests
import csv
import io
url = "https://raw.githubusercontent.com/datasets/covid-19/main/data/time-series-19-covid-combined.csv"
try:
    response = requests.get(url)
    response.raise_for_status()
    # response.content 是二进制数据,需要解码成字符串
    # 使用 io.StringIO 将字符串包装成一个类似文件的对象
    csv_file = io.StringIO(response.text.decode('utf-8'))
    # 现在可以直接将 csv_file 传给 csv.reader
    csv_reader = csv.reader(csv_file)
    # 读取并打印前5行(不包括表头)
    header = next(csv_reader)  # 读取表头
    print("表头:", header)
    print("\n前5行数据:")
    for i, row in enumerate(csv_reader):
        if i < 5:
            print(row)
        else:
            break
except requests.exceptions.RequestException as e:
    print(f"下载或解析失败: {e}")

代码解析:

  • response.text: 获取文件内容为字符串。
  • io.StringIO(): 这是一个非常有用的工具,它创建了一个在内存中的文本缓冲区,可以像操作文件一样操作这个字符串(传递给 csv.reader)。
  • 对于二进制文件(如图片),可以使用 io.BytesIO(response.content) 来创建一个内存中的二进制文件对象。

总结与最佳实践

场景 方法 关键点
下载二进制文件 (图片, PDF, 视频) requests.get(url, stream=True)
with open(filename, 'wb') as f:
    for chunk in response.iter_content():
        f.write(chunk)
必须使用 stream=Trueresponse.iter_content(),避免内存问题,写入模式为 'wb'
下载文本文件 (HTML, CSV, TXT) requests.get(url)
with open(filename, 'w', encoding='utf-8') as f:
    f.write(response.text)
使用 response.text,写入模式为 'w',并指定正确的 encoding
上传文件 requests.post(url, files={'key': (filename, file_obj)}) 本地文件需以 'rb' 模式打开。files 字典的键需符合 API 要求。
在内存中处理文件 data = response.content (二进制) 或 data = response.text (文本) 使用 io.StringIOio.BytesIO 将数据包装成文件对象,以便传给其他库(如 csv, PIL)。
通用实践 使用 try...except 处理网络错误。
使用 response.raise_for_status() 检查 HTTP 错误。
使用 with open(...)finally 确保资源被正确释放。
写健壮、可维护的代码。

希望这份详细的指南能帮助你熟练掌握 requests 库的文件操作!

分享:
扫描分享到社交APP
上一篇
下一篇