使用boto3从S3存储桶读取多个csv文件

10

我需要使用Python中的boto3从S3存储桶读取多个CSV文件,并最终将这些文件合并成单个数据框架中的内容。

我能够通过以下Python脚本读取单个文件:

 s3 = boto3.resource('s3')
 bucket = s3.Bucket('test-bucket')
 for obj in bucket.objects.all():
    key = obj.key
    body = obj.get()['Body'].read()

以下是我的路径

 files/splittedfiles/Code-345678
Code-345678中,我有多个csv文件,我需要在pandas中读取并将它们合并为单个数据帧。
另外,我怎样能传递一个选定的Codes列表作为参数,以便只读取这些文件夹。例如:
files/splittedfiles/Code-345678
files/splittedfiles/Code-345679
files/splittedfiles/Code-345680
files/splittedfiles/Code-345681
files/splittedfiles/Code-345682

我需要仅读取以下代码下的文件。

345678,345679,345682

我该如何在Python中实现?

3个回答

13
"boto3" API不支持一次读取多个对象。您可以检索具有指定前缀的所有对象,并使用循环加载返回的每个对象。为此,您可以使用 "filter()" 方法,并将 "Prefix" 参数设置为要加载的对象的前缀。下面我已经对您的代码进行了简单更改,使您可以获得所有具有前缀 "files/splittedfiles/Code-345678" 的对象,您可以通过循环读取这些对象来将每个文件加载到DataFrame中:
s3 = boto3.resource('s3')
bucket = s3.Bucket('test-bucket')
prefix_objs = bucket.objects.filter(Prefix="files/splittedfiles/Code-345678")
for obj in prefix_objs:
    key = obj.key
    body = obj.get()['Body'].read()

如果您有多个前缀需要评估,您可以将上面的内容转换为一个函数,其中前缀是一个参数,然后将结果组合在一起。 函数可能如下所示:

import pandas as pd

def read_prefix_to_df(prefix):
    s3 = boto3.resource('s3')
    bucket = s3.Bucket('test-bucket')
    prefix_objs = bucket.objects.filter(Prefix=prefix)
    prefix_df = []
    for obj in prefix_objs:
        key = obj.key
        body = obj.get()['Body'].read()
        df = pd.DataFrame(body)
        prefix_df.append(df)
    return pd.concat(prefix_df)

然后您可以迭代地将此函数应用于每个前缀,并在最后组合结果。


6
“ValueError: DataFrame constructor not properly called!” 的意思是“DataFrame构造函数调用不正确!”。为了解决这个问题,您需要将 body 转换为指定为utf-8编码的字符串,然后将其转换为StringIO对象。但是,在这种情况下,结果可能会导致整个字符串作为列名,并带有空值。 - Dave Liu

13

修改回答1以解决错误 DataFrame constructor not properly called!

代码:

import boto3
import pandas as pd
import io

s3 = boto3.resource('s3')
bucket = s3.Bucket('bucket_name')
prefix_objs = bucket.objects.filter(Prefix="folder_path/prefix")

prefix_df = []

for obj in prefix_objs:
    key = obj.key
    body = obj.get()['Body'].read()
    temp = pd.read_csv(io.BytesIO(body), encoding='utf8')        
    prefix_df.append(temp)

1
你能这样做吗,使用“filter”而不是“all”:
for obj in bucket.objects.filter(Prefix='files/splittedfiles/'):
    key = obj.key
    body = obj.get()['Body'].read()

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