PyInstaller打包后Python Multipart POST文件上传失效问题求助
Excel文件上传打包后失效的解决方案
问题描述
使用Tkinter选择Excel文件后,通过requests发送POST请求上传文件,在VS Code中直接运行Python脚本时一切正常,但经PyInstaller打包为exe后,请求返回状态码200,却未成功上传文件,怀疑是路径或文件句柄相关问题。
原代码
Tkinter选择文件代码
from tkinter import filedialog self.file = filedialog.askopenfile( mode="r", filetypes=[("Excel files", ".xlsx .xls")] )
POST请求上传代码
import os import json import requests from requests_toolbelt.multipart.encoder import MultipartEncoder field_data = { "data": (None, json.dumps(data), "application/json"), "file": ( os.path.basename(file.name), open(os.path.abspath(file.name), "rb"), "multipart/form-data", ), } m = MultipartEncoder(fields=field_data) headers = {"Content-Type": m.content_type} API_ENDPOINT = "https://uploadfile" session = requests.Session() session.trust_env = False r = session.post(url=API_ENDPOINT, data=m, headers=headers)
解决方案
1. 修正文件打开模式与复用文件对象
原代码中askopenfile使用文本模式"r",上传文件需要二进制模式;同时重复打开文件可能导致打包后出现文件句柄异常,直接复用已打开的文件对象即可:
- 将
askopenfile的mode改为"rb" - POST请求中直接使用已打开的
self.file对象,无需再次调用open
2. 重置文件指针位置
文件打开后如果有过读取操作,指针会停在文件末尾,上传前需要将指针重置到开头:
self.file.seek(0)
3. 优化MIME类型与路径处理
filedialog.askopenfile返回的文件对象的name属性已经是绝对路径,无需额外调用os.path.abspath- 替换
multipart/form-data为更准确的Excel MIME类型(.xlsx用application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,.xls用application/vnd.ms-excel)
修改后的完整代码
Tkinter选择文件部分
from tkinter import filedialog self.file = filedialog.askopenfile( mode="rb", filetypes=[("Excel files", ".xlsx .xls")] )
POST请求上传部分
import os import json import requests from requests_toolbelt.multipart.encoder import MultipartEncoder # 重置文件指针到开头 self.file.seek(0) # 根据文件后缀设置正确的MIME类型 file_ext = os.path.splitext(self.file.name)[1].lower() mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" if file_ext == ".xlsx" else "application/vnd.ms-excel" field_data = { "data": (None, json.dumps(data), "application/json"), "file": ( os.path.basename(self.file.name), self.file, mime_type, ), } m = MultipartEncoder(fields=field_data) headers = {"Content-Type": m.content_type} API_ENDPOINT = "https://uploadfile" session = requests.Session() session.trust_env = False r = session.post(url=API_ENDPOINT, data=m, headers=headers) # 上传完成后关闭文件,释放资源 self.file.close()
额外打包注意事项
打包时需确保PyInstaller包含requests_toolbelt依赖,可通过以下命令打包:
pyinstaller --hidden-import requests_toolbelt.multipart.encoder your_script.py
内容的提问来源于stack exchange,提问作者shfshfdl
相关产品推荐
相关产品推荐

