web-dev-qa-db-fra.com

Comment importer un fichier texte sur AWS S3 dans pandas sans écrire sur le disque

J'ai un fichier texte enregistré sur S3 qui est une table délimitée par des tabulations. Je veux le charger dans pandas mais je ne peux pas le sauvegarder au préalable parce que je suis sur un serveur heroku. Voici ce que j'ai à ce jour.

import io
import boto3
import os
import pandas as pd

os.environ["AWS_ACCESS_KEY_ID"] = "xxxxxxxx"
os.environ["AWS_SECRET_ACCESS_KEY"] = "xxxxxxxx"

s3_client = boto3.client('s3')
response = s3_client.get_object(Bucket="my_bucket",Key="filename.txt")
file = response["Body"]


pd.read_csv(file, header=14, delimiter="\t", low_memory=False)

l'erreur est

OSError: Expected file path name or file-like object, got <class 'bytes'> type

Comment convertir le corps de la réponse dans un format pandas acceptera?)

pd.read_csv(io.StringIO(file), header=14, delimiter="\t", low_memory=False)

returns

TypeError: initial_value must be str or None, not StreamingBody

pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)

returns

TypeError: 'StreamingBody' does not support the buffer interface

UPDATE - Utilisation de ce qui suit a fonctionné

file = response["Body"].read()

et

pd.read_csv(io.BytesIO(file), header=14, delimiter="\t", low_memory=False)
59
alpalalpal

pandas utilise boto pour read_csv, vous devriez donc pouvoir:

import boto
data = pd.read_csv('s3://bucket....csv')

Si tu as besoin boto3 parce que vous êtes sur python3.4+, vous pouvez

import boto3
import io
s3 = boto3.client('s3')
obj = s3.get_object(Bucket='bucket', Key='key')
df = pd.read_csv(io.BytesIO(obj['Body'].read()))
61
Stefan

Maintenant les pandas peuvent gérer les URL S . Vous pouvez simplement faire:

import pandas as pd
import s3fs

df = pd.read_csv('s3://bucket-name/file.csv')

Vous devez installer s3fs si vous ne l'avez pas. pip install s3fs

Authentification

Si votre compartiment S3 est privé et nécessite une authentification, vous avez deux options:

1- Ajouter des identifiants d'accès à votre ~/.aws/credentials fichier de configuration

[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

Ou

2- Définissez les variables d’environnement avec leurs valeurs appropriées:

  • aws_access_key_id
  • aws_secret_access_key
  • aws_session_token
40
Wesam

Ceci est maintenant pris en charge dans les derniers pandas. Voir

http://pandas.pydata.org/pandas-docs/stable/io.html#reading-remote-files

par exemple.,

df = pd.read_csv('s3://pandas-test/tips.csv')
12
Raveen Beemsingh

Avec s3fs cela peut être fait comme suit:

import s3fs
import pandas as pd
fs = s3fs.S3FileSystem(anon=False)

# CSV
with fs.open('mybucket/path/to/object/foo.pkl') as f:
    df = pd.read_csv(f)

# Pickle
with fs.open('mybucket/path/to/object/foo.pkl') as f:
    df = pd.read_pickle(f)
6
Dror

Les fichiers pouvant être trop volumineux, il n’est pas judicieux de les charger dans le cadre de données. Par conséquent, lisez ligne par ligne et enregistrez-le dans le dataframe. Oui, nous pouvons également fournir la taille de bloc dans read_csv, mais nous devons ensuite conserver le nombre de lignes lues.

Par conséquent, je suis venu avec cette ingénierie:

def create_file_object_for_streaming(self):
        print("creating file object for streaming")
        self.file_object = self.bucket.Object(key=self.package_s3_key)
        print("File object is: " + str(self.file_object))
        print("Object file created.")
        return self.file_object

for row in codecs.getreader(self.encoding)(self.response[u'Body']).readlines():
            row_string = StringIO(row)
            df = pd.read_csv(row_string, sep=",")

Je supprime également le df une fois le travail terminé. del df

1
aviral sanjay

Une option consiste à convertir le fichier csv en fichier json via df.to_dict(), puis à le stocker en tant que chaîne. Notez que cela n’est pertinent que si le fichier CSV n’est pas une exigence mais que vous souhaitez simplement placer rapidement le cadre de données dans un compartiment S3 et le récupérer à nouveau.

from boto.s3.connection import S3Connection
import pandas as pd
import yaml

conn = S3Connection()
mybucket = conn.get_bucket('mybucketName')
myKey = mybucket.get_key("myKeyName")

myKey.set_contents_from_string(str(df.to_dict()))

Cela convertira le df en une chaîne de dict, puis sauvegardera cela comme json dans S3. Vous pourrez le lire plus tard dans le même format JSON:

df = pd.DataFrame(yaml.load(myKey.get_contents_as_string()))

Les autres solutions sont également bonnes, mais ceci est un peu plus simple. Yaml n'est peut-être pas nécessaire, mais vous avez besoin de quelque chose pour analyser la chaîne json. Si le fichier S3 ne doit pas nécessairement nécessité être un fichier CSV, cela peut constituer une solution rapide.

0
billmanH