如何在不写入磁盘的情况下将AWS S3上的文本文件导入熊猫


91

我有一个保存在S3上的文本文件,它是一个制表符分隔的表。我想将其加载到熊猫中,但由于我在heroku服务器上运行,因此无法先保存它。这是我到目前为止所拥有的。

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)

错误是

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

如何将响应主体转换为大熊猫可以接受的格式?

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

更新-使用以下工作

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

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

试试这样:io.BytesIO(file)或者io.StringIO(file),而不是fileread_csv()通话
MaxU

您可以io.StringIO此答案中使用
IanS

这些建议均无效。您可以在我的帖子编辑中看到错误。
alpalalpal

1
更新部分为我工作。谢谢。
Wim Berchmans,2013年

Answers:


110

pandas使用botoread_csv,所以你应该能够:

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

如果你需要boto3,因为你是python3.4+,你可以

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

由于版本0.20.1 pandas使用s3fs,请参见下面的答案。


有没有一种方法可以使用URL而不向所有人公开?该文件需要保密。
alpalalpal

boto3文档展示了如何配置身份验证,以便您也可以访问私有文件:boto3.readthedocs.io/en/latest/guide/quickstart.html
Stefan

1
它抛出NoCredentialsError。如何设置s3凭据tl?我是新来的Python和博托
苏尼尔饶

15
我发现我必须在boto3的最后一个示例中执行以下操作: df = pd.read_csv(io.BytesIO(obj['Body'].read()), encoding='utf8')
user394430 '17

这个答案已经过时了。请参阅Wesams答案
Gerrit

80

现在,熊猫可以处理S3 URL。您可以简单地执行以下操作:

import pandas as pd
import s3fs

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

s3fs如果没有,则需要安装pip install s3fs

认证方式

如果您的S3存储桶是私有的并且需要身份验证,则有两种选择:

1-将访问凭据添加到您的~/.aws/credentials配置文件

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

要么

2-使用适当的值设置以下环境变量

  • aws_access_key_id
  • aws_secret_access_key
  • aws_session_token

美丽。在python3中工作。
凯勒·布朗

认证怎么样..?
詹姆斯·维尔茨巴

1
@JamesWierzba,我在上面的答案中添加了有关身份验证的更多详细信息。
Wesam,

3
处理多个aws配置文件时,如何选择应使用哪个配置文件?s3fs具有profile_name选项,但是我不确定它如何与熊猫一起使用。
Ivo Merchiers

1
@IanS并非如此,目前,我首先使用s3fs打开文件对象(使用指定的配置文件),然后使用pandas进行读取,就像它们在这里一样github.com/pandas-dev/pandas/issues/16692
Ivo Merchiers

15

现在,最新的熊猫都支持此功能。看到

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

例如。,

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

4
请记住,“也可以处理S3 URL,但需要安装S3Fs库”
Julio Villane

身份验证怎么样
James Wierzba

带有auth的URL可能很困难,除非将该URL公开给公众,不确定简单/基本的HTTP auth是否会起作用,
Raveen Beemsingh

9

使用s3fs可以完成以下操作:

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
我认为使用df = pd.read_csv('s3://mybucket/path/to/object/foo.pkl')
s3fs

1
@louis_guitton这似乎与PD-read_csv工作,但不能与read_pickle

1

由于文件可能太大,因此将它们完全加载到数据帧中是不明智的。因此,逐行读取并将其保存在数据框中。是的,我们还可以在read_csv中提供块大小,但随后我们必须保持读取的行数。

因此,我想到了这个工程:

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

工作完成后,我还将删除df。 del df


1

对于文本文件,您可以将以下代码与管道分隔文件一起使用,例如:

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

一种选择是通过将csv转换为json df.to_dict(),然后将其存储为字符串。请注意,这仅在不需要CSV的情况下才有意义,而您只是想将数据帧快速放入S3存储桶中并再次检索它。

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

这会将df转换为dict字符串,然后在S3中将其另存为json。您以后可以以相同的json格式读取它:

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

其他解决方案也不错,但这要简单一些。Yaml不一定是必需的,但是您需要一些解析json字符串的东西。如果S3文件不一定需要是CSV,则可以快速解决。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.