【问题标题】:Reading multiple csv files from S3 bucket with boto3使用 boto3 从 S3 存储桶中读取多个 csv 文件
【发布时间】:2019-03-22 03:40:35
【问题描述】:

我需要在 python 中使用 boto3 从 S3 存储桶中读取多个 csv 文件,最后将这些文件合并到 pandas 中的单个数据框中。

我可以从以下 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 中做到这一点?

【问题讨论】:

    标签: python csv amazon-s3 boto3


    【解决方案1】:

    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)
    

    然后你可以迭代地把这个函数应用到每个前缀上,最后组合结果。

    【讨论】:

    • *** ValueError: DataFrame constructor not properly called! 答案可能已被弃用。 body 是一个字节对象,我必须将其转换为指定的 utf-8 字符串编码,然后转换为 StringIO 对象,如下所示:stackoverflow.com/questions/47379476/…,但这只是将整个字符串设置为具有空值的列名。
    【解决方案2】:

    修改答案 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)
    

    【讨论】:

      【解决方案3】:

      你能这样做吗,使用“过滤器”而不是“全部”:

      for obj in bucket.objects.filter(Prefix='files/splittedfiles/'):
          key = obj.key
          body = obj.get()['Body'].read()
      

      【讨论】:

        猜你喜欢
        • 2016-07-12
        • 1970-01-01
        • 1970-01-01
        • 2022-01-09
        • 2018-11-07
        • 2017-09-29
        • 2021-05-22
        • 1970-01-01
        • 2021-01-31
        相关资源
        最近更新 更多