2016-07-01 22 views
18

Mam pandas DataFrame, który chcę załadować do nowego pliku CVS. Problem polega na tym, że nie chcę zapisywać pliku lokalnie przed przeniesieniem go do s3. Czy istnieje metoda podobna do to_csv do bezpośredniego zapisu ramki danych do s3? Używam boto3.
Oto co mam do tej pory:Zapisz ramkę danych do csv bezpośrednio do s3 Python

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 

Odpowiedz

7

Jeśli zdasz None jako pierwszy argument to_csv() dane zostaną zwrócone w postaci ciągu znaków. Stamtąd łatwo jest przesłać go do S3 za jednym razem.

Powinno być również możliwe przekazanie obiektu StringIO do to_csv(), ale użycie ciągu znaków będzie łatwiejsze.

+0

będzie łatwiejsze, w jaki sposób? Jaki jest prawidłowy sposób to zrobić? –

+0

@EranMoshe: tak czy inaczej zadziała poprawnie, ale oczywiście łatwiej jest przekazać 'None' do' to_csv() 'i użyć zwróconego ciągu, niż utworzyć obiekt' StringIO', a następnie odczytać dane z powrotem. – mhawke

+0

Jako leniwy programista, właśnie to zrobiłem. A miałeś na myśli programistę, który pisze mniej kodu:> –

21

Można użyć:

from io import StringIO 
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()) 
+0

z pliku import StringIO, więc wydaje się, że nie pozwala na edycje zawierające mniej niż 6 znaków. – Satyadev

+0

Jeśli to duży plik, co robi to z pamięcią ...? – citynorman

+0

Jeśli plik jest większy niż dostępna pamięć RAM, akcja zakończy się niepowodzeniem i będzie wyjątek z wyjątkiem wyjątku (nie wiem, który z nich). To powinno być zaakceptowane jako odpowiedź: –

0
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 
14

Lubię s3fs która pozwala używać S3 (prawie) jak lokalny system plików.

Można to zrobić:

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 obsługuje tylko rb i wb tryby otwierania pliku, dlatego zrobiłem ten bytes_to_write rzeczy.

+0

Świetnie! Jak mogę uzyskać adres URL pliku przy użyciu tego samego modułu s3fs? –

+0

@ M.Zaman, nie jestem pewien, o co pytasz. – michcio1234

+0

Szukałem adresu URL, skąd mogę pobrać zapisany plik, tak czy inaczej dostaję go przez S3FileSystem. Dzięki –

0

Czytam plik CSV z dwiema kolumnami z s3, a zawartość pliku CSV umieszczam w ramce danych pandy.

przykład:

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 __name__ == '__main__': 
    test = test() 
    test.process() 
+1

, proszę nie wysyłać rozwiązania, należy również dodać ich wyjaśnienie. – sjaustirni

Powiązane problemy