web-dev-qa-db-fra.com

Enregistrez le fichier de données au format csv directement sur s3 Python

J'ai un pandas _ DataFrame que je souhaite télécharger dans un nouveau fichier CSV. Le problème est que je ne veux pas enregistrer le fichier localement avant de le transférer sur s3. Existe-t-il une méthode telle que to_csv pour écrire le dataframe sur s3 directement? J'utilise boto3.
Voici ce que j'ai jusqu'à présent:

import boto3
s3 = boto3.client('s3', aws_access_key_id='key', aws_secret_access_key='secret_key')
read_file = s3.get_object(Bucket, Key)
df = pd.read_csv(read_file['Body'])

# Make alterations to DataFrame

# Then export DataFrame to CSV through direct transfer to s3
67
user2494275

Vous pouvez utiliser:

from io import StringIO # python3; python2: BytesIO 
import boto3

csv_buffer = StringIO()
df.to_csv(csv_buffer)
s3_resource = boto3.resource('s3')
s3_resource.Object(bucket, 'df.csv').put(Body=csv_buffer.getvalue())
81
Stefan

J'aime s3fs qui vous permet d'utiliser (presque) s3 comme un système de fichiers local.

Tu peux le faire:

import s3fs

bytes_to_write = df.to_csv(None).encode()
fs = s3fs.S3FileSystem(key=key, secret=secret)
with fs.open('s3://bucket/path/to/file.csv', 'wb') as f:
    f.write(bytes_to_write)

s3fs ne supporte que rb et wb modes d'ouverture du fichier, c'est pourquoi j'ai fait ce type de bytes_to_write.

43
michcio1234

Ceci est une réponse plus à jour:

import s3fs

s3 = s3fs.S3FileSystem(anon=False)

# Use 'w' for py3, 'wb' for py2
with s3.open('<bucket-name>/<filename>.csv','w') as f:
    df.to_csv(f)

Le problème avec StringIO est qu'il va ronger votre mémoire. Avec cette méthode, vous transmettez en continu le fichier au format s3, plutôt que de le convertir en chaîne, puis de l'écrire au format s3. Tenir le pandas dataframe et sa copie de chaîne en mémoire semble très inefficace.

Si vous travaillez dans un instant ec2, vous pouvez lui attribuer un rôle IAM pour lui permettre de l'écrire sur s3. Ainsi, vous n'avez pas besoin de passer directement les informations d'identification. Toutefois, vous pouvez également vous connecter à un compartiment en transmettant les informations d'identification à la fonction S3FileSystem(). Voir la documentation: https://s3fs.readthedocs.io/en/latest/

26
erncyp

Vous pouvez directement utiliser le chemin S3. J'utilise Pandas 0.24.1

In [1]: import pandas as pd

In [2]: df = pd.DataFrame( [ [1, 1, 1], [2, 2, 2] ], columns=['a', 'b', 'c'])

In [3]: df
Out[3]:
   a  b  c
0  1  1  1
1  2  2  2

In [4]: df.to_csv('s3://experimental/playground/temp_csv/dummy.csv', index=False)

In [5]: pd.__version__
Out[5]: '0.24.1'

In [6]: new_df = pd.read_csv('s3://experimental/playground/temp_csv/dummy.csv')

In [7]: new_df
Out[7]:
   a  b  c
0  1  1  1
1  2  2  2

Note de sortie:

Traitement de fichiers S3

les pandas utilisent maintenant s3fs pour gérer les connexions S3. Cela ne devrait casser aucun code. Cependant, s3fs n'étant pas une dépendance requise, vous devrez l'installer séparément, comme boto dans les versions précédentes de pandas. GH11915 .

14
Amit Kushwaha

Si vous passez None comme premier argument à to_csv() , les données seront renvoyées sous forme de chaîne. À partir de là, il est facile de télécharger cela en une fois sur S3.

Il devrait également être possible de passer un objet StringIO à to_csv(), mais l'utilisation d'une chaîne sera plus facile.

12
mhawke

J'ai lu un CSV avec deux colonnes du seau S3 et le contenu du fichier CSV que j'ai mis dans pandas dataframe.

Exemple:

config.json

{
  "credential": {
    "access_key":"xxxxxx",
    "secret_key":"xxxxxx"
}
,
"s3":{
       "bucket":"mybucket",
       "key":"csv/user.csv"
   }
}

cls_config.json

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import json

class cls_config(object):

    def __init__(self,filename):

        self.filename = filename


    def getConfig(self):

        fileName = os.path.join(os.path.dirname(__file__), self.filename)
        with open(fileName) as f:
        config = json.load(f)
        return config

cls_pandas.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pandas as pd
import io

class cls_pandas(object):

    def __init__(self):
        pass

    def read(self,stream):

        df = pd.read_csv(io.StringIO(stream), sep = ",")
        return df

cls_s3.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import boto3
import json

class cls_s3(object):

    def  __init__(self,access_key,secret_key):

        self.s3 = boto3.client('s3', aws_access_key_id=access_key, aws_secret_access_key=secret_key)

    def getObject(self,bucket,key):

        read_file = self.s3.get_object(Bucket=bucket, Key=key)
        body = read_file['Body'].read().decode('utf-8')
        return body

test.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from cls_config import *
from cls_s3 import *
from cls_pandas import *

class test(object):

    def __init__(self):
        self.conf = cls_config('config.json')

    def process(self):

        conf = self.conf.getConfig()

        bucket = conf['s3']['bucket']
        key = conf['s3']['key']

        access_key = conf['credential']['access_key']
        secret_key = conf['credential']['secret_key']

        s3 = cls_s3(access_key,secret_key)
        ob = s3.getObject(bucket,key)

        pa = cls_pandas()
        df = pa.read(ob)

        print df

if __== '__main__':
    test = test()
    test.process()