Python Pandas - 读取 CSV 或 Excel 文件

4

我允许用户上传CSV或Excel文件。我使用pandas读取文件并创建数据框。由于我无法预测用户将上传哪种文件类型,因此我在try / except块中包装了pd.read_csv()和pd.read_excel()。

if form.validate_on_submit():
    input_filename = secure_filename(form.file.data.filename)
    try:
        df = pd.read_csv(form.file.data, header=0, skip_blank_lines=True, skipinitialspace=True, encoding='latin-1')
    except:
        df = pd.read_excel(form.file.data, header=0, skip_blank_lines=True, skipinitialspace=True, encoding='latin-1')

如果在try/except块中首先使用pd.read_csv(),并且我上传了一个.csv文件,它可以正常工作。但是如果我尝试上传一个.xlsx文件,则会出现以下错误:

TypeError: expected str, bytes or os.PathLike object, not NoneType

如果pd.read_excel()在try/except块中首先执行,并且我上传一个.xlsx文件,它就可以工作。如果我尝试上传一个.csv文件,我会得到以下错误:

pandas.io.common.EmptyDataError: No columns to parse from file

之前,我使用mimetype将文件路由到正确的pandas函数,但我希望有一个更干净(并且全面)的解决方案,不涉及多个if/elif语句。这是我的代码:

if form.file.data.mimetype == 'text/csv':
    df = pd.read_csv(form.file.data, header=0, skip_blank_lines=True, skipinitialspace=True, encoding='latin-1')
elif form.file.data.mimetype == 'application/octet-stream':
    df = pd.read_excel(form.file.data, header=0, skip_blank_lines=True, skipinitialspace=True, encoding='latin-1')
elif form.file.data.mimetype == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
    df = pd.read_excel(form.file.data, header=0, skip_blank_lines=True, skipinitialspace=True, encoding='latin-1')
else:
    flash('Error Uploading File. Invalid file type. Please use xls, xlsx or csv.', 'danger')
    return render_template('upload.html', current_user=current_user, form=form)

我正在使用Flask、WTForms和Python 3。谢谢。


我对wtforms不够熟悉,所以...form.file.data是什么?如果它是类似文件的对象,是否有一种方法可以将其定位回0位置?如果没有,您可能需要将其读入类似于io.StringIO缓冲区的东西中,该缓冲区可以被倒带。然后,在第一种类型尝试失败之前,将其定位到0。 - tdelaney
您可能还需要找出csv文件的编码方式。这就是使用之前所述的http头的优势。 - tdelaney
1个回答

0

您正在使用对于read_csv有用但不支持read_excel的关键字参数调用read_excel。您可以尝试以下方法:

if form.validate_on_submit():
    input_filename = secure_filename(form.file.data.filename)
    data = form.file.data
    try:
        df = pd.read_csv(data, header=0, skip_blank_lines=True, 
                         skipinitialspace=True, encoding='latin-1')
    except:
        df = pd.read_excel(data, header=0)

除了删除 read_excel 的额外参数之外,我还将从 form.file.data 中提取数据的过程提前了;这是为了避免可能会与 try/except 块不兼容的懒加载行为。

通常在 web 请求中调试中等复杂的 I/O 函数是困难的。当这类操作不能正常工作时,最好的方法是将问题分成两部分:1/ 从 web 请求获取数据并将其写入文件。然后分别进行第2步/,即从生成的文件中尝试 I/O(在本例中为 Pandas 数据帧加载)。交互式地执行此操作或在单独的程序中执行此操作将为您提供更多的调试机会和清晰度。Jupyter Notebook 非常适合进行此类探索性测试,不过大多数 IDE 或甚至裸的 Python REPL 也可以胜任。当第 2 步/ 很明显工作正常时,您可以将其补回 Flask / web 应用程序代码中。


谢谢你的回答。我尝试了你的代码,但是当文件格式与except语句中的pandas读取函数对应时,仍然似乎存在问题。看起来当在try语句中尝试将数据读入数据帧后引发异常时,form.file.data变为None。这可能是懒加载问题吗? - KingOfLeon
可能会。有些数据源是“可枯竭的”。例如生成器和文件,在某种程度上(尽管它们有一个寻求方法,让您返回到开头)。建议在try/except之前将数据写入文件。检查一下。是否有一种条件化的方式可以基于数据来选择使用哪个pd读取方法?“先做再说”并不总是最好的,如果数据读取不是幂等的话。 - Jonathan Eunice
1
我决定使用filename.endswith('.csv')作为将文件路由到正确的pd读取方法的方式。感谢您的帮助! - KingOfLeon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接