Cách nhập tệp văn bản trên AWS S3 vào gấu trúc mà không cần ghi vào đĩa


91

Tôi có một tệp văn bản được lưu trên S3 là một bảng được phân cách bằng tab. Tôi muốn tải nó vào gấu trúc nhưng không thể lưu nó trước vì tôi đang chạy trên máy chủ heroku. Đây là những gì tôi có cho đến nay.

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ỗi là

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

Làm cách nào để chuyển đổi nội dung phản hồi thành định dạng mà gấu trúc sẽ chấp nhận?

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

CẬP NHẬT - Sử dụng điều sau đây đã hiệu quả

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

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

hãy thử theo cách này: io.BytesIO(file)hoặc io.StringIO(file)thay vì filetrong read_csv()cuộc gọi
MaxU

Bạn có thể sử dụng io.StringIOnhư trong câu trả lời này .
IanS

Cả hai đề xuất này đều không hoạt động. Bạn có thể thấy các lỗi trong bài chỉnh sửa của tôi.
alpalalpal

1
Phần CẬP NHẬT đã làm việc cho tôi. Cảm ơn.
Wim Berchmans

Câu trả lời:


110

pandassử dụng botocho read_csv, vì vậy bạn sẽ có thể:

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

Nếu bạn cần boto3vì bạn đang ở trên python3.4+, bạn có thể

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()))

phiên bản 0.20.1 pandas sử dụng s3fs, hãy xem câu trả lời bên dưới.


Có cách nào để sử dụng URL mà không công khai với mọi người không? Tệp cần giữ ở chế độ riêng tư.
alpalalpal

Các boto3tài liệu cho thấy làm thế nào để xác thực cấu hình để bạn có thể truy cập các tập tin cũng như: boto3.readthedocs.io/en/latest/guide/quickstart.html
Stefan

1
Nó đang ném NoCredentialsError. Làm cách nào để đặt thông tin đăng nhập s3? Tôi mới làm quen với python và boto
Sunil Rao

15
Tôi thấy rằng tôi đã phải làm những điều sau đây trên ví dụ cuối cùng với boto3: df = pd.read_csv(io.BytesIO(obj['Body'].read()), encoding='utf8')
user394430

Câu trả lời này đã lỗi thời . Hãy xem câu trả lời của Wesams .
gerrit

80

Bây giờ gấu trúc có thể xử lý các URL S3 . Bạn chỉ có thể làm:

import pandas as pd
import s3fs

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

Bạn cần cài đặts3fs nếu chưa có. pip install s3fs

Xác thực

Nếu nhóm S3 của bạn là riêng tư và yêu cầu xác thực, bạn có hai tùy chọn:

1- Thêm thông tin đăng nhập vào tệp cấu hình của bạn~/.aws/credentials

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

Hoặc là

2- Đặt các biến môi trường sau với giá trị thích hợp của chúng:

  • aws_access_key_id
  • aws_secret_access_key
  • aws_session_token

Xinh đẹp. Hoạt động trong python3.
Kyler Brown

làm thế nào về xác thực ..?
James Wierzba

1
@JamesWierzba, tôi đã bổ sung thêm chi tiết về xác thực cho câu trả lời của mình ở trên.
Wesam

3
Khi xử lý nhiều cấu hình aws, làm thế nào bạn có thể chọn cấu hình nào nên được sử dụng? s3fs có tùy chọn profile_name, nhưng tôi không chắc cách đó hoạt động với gấu trúc.
Ivo Merchiers

1
@IanS Không hẳn, hiện tại, trước tiên tôi mở đối tượng tệp bằng s3fs (sử dụng cấu hình được chỉ định) và sau đó tôi đọc nó với gấu trúc, giống như chúng làm ở đây github.com/pandas-dev/pandas/issues/16692
Ivo Merchiers

15

Điều này hiện đã được hỗ trợ trong gấu trúc mới nhất. Xem

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

ví dụ.,

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

4
Hãy nhớ 'URL S3 cũng được xử lý nhưng yêu cầu cài đặt thư viện S3Fs'
Julio Villane,

xác thực thì sao
James Wierzba

url với auth có thể khó khăn trừ khi, url được tiếp xúc như công cộng, không chắc chắn nếu đơn giản / cơ bản http auth sẽ làm việc,
Raveen Beemsingh

9

Với s3fs, nó có thể được thực hiện như sau:

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)

2
Tôi nghĩ rằng với s3fs bạn thậm chí có thể viếtdf = pd.read_csv('s3://mybucket/path/to/object/foo.pkl')
louis_guitton

1
@louis_guitton điều này dường như hoạt động với pd-read_csv nhưng không hoạt động với read_pickle
Sip

1

Vì các tệp có thể quá lớn, không nên tải chúng trong khung dữ liệu. Do đó, đọc từng dòng một và lưu nó vào khung dữ liệu. Có, chúng tôi cũng có thể cung cấp kích thước phân đoạn trong read_csv nhưng sau đó chúng tôi phải duy trì số hàng đã đọc.

Do đó, tôi đã nghĩ ra kỹ thuật này:

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=",")

Tôi cũng xóa df sau khi hoàn thành công việc. del df


1

Đối với tệp văn bản, bạn có thể sử dụng mã bên dưới với tệp được phân cách bằng dấu sổ đứng, ví dụ: -

import pandas as pd
import io
import boto3
s3_client = boto3.client('s3', use_ssl=False)
bucket = #
prefix = #
obj = s3_client.get_object(Bucket=bucket, Key=prefix+ filename)
df = pd.read_fwf((io.BytesIO(obj['Body'].read())) , encoding= 'unicode_escape', delimiter='|', error_bad_lines=False,header=None, dtype=str)

0

Một tùy chọn là chuyển đổi csv sang json qua df.to_dict()và sau đó lưu trữ nó dưới dạng chuỗi. Lưu ý rằng điều này chỉ có liên quan nếu CSV không phải là một yêu cầu nhưng bạn chỉ muốn nhanh chóng đặt khung dữ liệu vào một nhóm S3 và truy xuất lại nó.

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()))

Điều này sẽ chuyển đổi df thành một chuỗi dict, và sau đó lưu nó dưới dạng json trong S3. Sau đó, bạn có thể đọc nó ở cùng một định dạng json:

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

Các giải pháp khác cũng tốt, nhưng điều này đơn giản hơn một chút. Có thể không nhất thiết phải bắt buộc phải có Yaml nhưng bạn cần thứ gì đó để phân tích cú pháp chuỗi json. Nếu tệp S3 không nhất thiết phải là CSV thì đây có thể là một cách khắc phục nhanh chóng.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.