get file from s3 python
Guarde Dataframe en csv directamente en s3 Python (7)
Tengo un DataFrame de pandas que quiero subir a un nuevo archivo CSV.
El problema es que no quiero guardar el archivo localmente antes de transferirlo a s3.
¿Hay algún método como to_csv para escribir el marco de datos en s3 directamente?
Estoy usando boto3.
Esto es lo que tengo hasta ahora:
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
Esta es una respuesta más actualizada:
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)
El problema con StringIO es que va a acabar con tu memoria. Con este método, está transmitiendo el archivo a s3, en lugar de convertirlo en cadena, luego escribiéndolo en s3. Mantener el marco de datos de pandas y su copia de cadena en la memoria parece muy ineficiente.
Si está trabajando en un instante ec2, puede asignarle un rol de IAM para que pueda escribirlo en s3, por lo que no necesita pasar las credenciales directamente.
Sin embargo, también puede conectarse a un depósito pasando credenciales a la función
S3FileSystem()
.
Ver documentación:
https://s3fs.readthedocs.io/en/latest/
Leí un csv con dos columnas del cubo s3, y el contenido del archivo csv lo puse en el marco de datos de pandas.
Ejemplo:
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
prueba.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 __name__ == ''__main__'':
test = test()
test.process()
Me gusta s3fs que te permite usar s3 (casi) como un sistema de archivos local.
Puedes hacerlo:
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
solo
wb
modos
rb
y
wb
para abrir el archivo, es por eso que hice esto de
bytes_to_write
.
Puede usar directamente la ruta S3. Estoy usando 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
Manejo de archivos S3
pandas ahora usa s3fs para manejar conexiones S3. Esto no debería romper ningún código. Sin embargo, dado que s3fs no es una dependencia requerida, deberá instalarlo por separado, como boto en versiones anteriores de pandas. GH11915 .
Puedes usar:
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())
Si pasa
None
como el primer argumento para
to_csv()
los datos se devolverán como una cadena.
A partir de ahí, es un paso fácil subir eso a S3 de una vez.
También debería ser posible pasar un objeto
StringIO
a
to_csv()
, pero usar una cadena será más fácil.
import boto3
s3_client = boto3.client(''s3'',aws_access_key_id="AccessKey",aws_secret_access_key="Secretkey")
head_response = s3_client.head_object(Bucket=''YourBucket'',Key=''YourPath'')
if head_response[''HTTPStatusCode''] == 200:
Your operation if file exsits