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

Posted

技术标签:

【中文标题】如何在不写入磁盘的情况下将 AWS S3 上的文本文件导入 pandas【英文标题】:How to import a text file on AWS S3 into pandas without writing to disk 【发布时间】:2016-10-08 18:55:41 【问题描述】:

我在 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

如何将响应正文转换为 pandas 可以接受的格式?

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)read_csv() 调用中代替 file 你可以像this answer一样使用io.StringIO 这些建议都不起作用。您可以在我的帖子编辑中看到错误。 更新部分对我有用。谢谢。 【参考方案1】:

pandasboto 用于read_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()))

由于version 0.20.1 pandas 使用s3fs,请参阅answer below。

【讨论】:

有没有办法在不向所有人公开的情况下使用 URL?该文件需要保密。 boto3 文档展示了如何配置身份验证以便您也可以访问私有文件:boto3.readthedocs.io/en/latest/guide/quickstart.html 它正在抛出 NoCredentialsError。如何设置 s3 凭据 tl 呢?我是 python 和 boto 的新手 我发现我必须在最后一个示例中使用 boto3 执行以下操作:df = pd.read_csv(io.BytesIO(obj['Body'].read()), encoding='utf8') 这个答案过时了。请参阅Wesams answer。【参考方案2】:

现在pandas can handle S3 URLs。你可以这样做:

import pandas as pd
import s3fs

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

You need to install s3fs 如果你没有的话。 pip install s3fs

认证

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

1- 将访问凭据添加到您的 ~/.aws/credentials config file

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

或者

2- 使用正确的值设置以下environment variables:

aws_access_key_id aws_secret_access_key aws_session_token

【讨论】:

美丽。在 python3 中工作。 身份验证怎么样..? @JamesWierzba ,我在上面的答案中添加了有关身份验证的更多详细信息。 在处理多个 aws 配置文件时,如何选择应该使用哪个配置文件? s3fs 有 profile_name 选项,但我不确定它如何与 pandas 一起使用。 @IanS 不是真的,目前,我先用 s3fs(使用指定的配置文件)打开文件对象,然后用 pandas 读取它,就像他们在这里做的github.com/pandas-dev/pandas/issues/16692【参考方案3】:

最新的 pandas 现已支持此功能。见

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

例如,

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

【讨论】:

记住'S3 URL 也被处理,但需要安装 S3Fs 库' 认证怎么样 带有身份验证的网址可能很困难,除非该网址公开为公开,不确定简单/基本的 http 身份验证是否有效,【参考方案4】:

使用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)

【讨论】:

我认为使用 s3fs 你甚至可以写 df = pd.read_csv('s3://mybucket/path/to/object/foo.pkl') @louis_guitton 这似乎适用于 pd-read_csv 但不适用于 read_pickle【参考方案5】:

对于 python 3.6+,亚马逊现在有一个非常好的库,可以在他们的服务中使用 Pandas,称为awswrangler。

import awswrangler as wr
import boto3


# Boto3 session
session = boto3.session.Session(aws_access_key_id='XXXX', 
                                aws_secret_access_key='XXXX')

# Awswrangler pass forward all pd.read_csv() function args
df = wr.s3.read_csv(path='s3://bucket/path/',
                    boto3_session=session,
                    skiprows=2,
                    sep=';',
                    decimal=',',
                    na_values=['--'])

安装awswrangler:pip install awswrangler

【讨论】:

如果您要使用 AWS/Python/Pandas/Glue/等...AWS Wrangler 是您最好的新朋友。【参考方案6】:

由于文件可能太大,将它们完全加载到数据框中是不明智的。因此,逐行读取并将其保存在数据框中。是的,我们也可以在 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

【讨论】:

【参考方案7】:

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

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)

【讨论】:

【参考方案8】:

一个选项是通过df.to_dict() 将 csv 转换为 json,然后将其存储为字符串。请注意,这仅在不需要 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,这可以是一个快速修复。

【讨论】:

【参考方案9】:
import s3fs
import pandas as pd
s3 = s3fs.S3FileSystem(profile='<profile_name>')
pd.read_csv(s3.open(<s3_path>))

【讨论】:

请在您的代码中添加一些解释。

以上是关于如何在不写入磁盘的情况下将 AWS S3 上的文本文件导入 pandas的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 PHP 将文件写入磁盘的情况下将文件发布到 REST 服务器?

Python 3:如何在不保存在磁盘上的情况下将 pandas 数据帧作为 csv 流上传?

如何在不使用 BIOS 的情况下将数据写入显卡?

如何在不创建 IAM 用户的情况下将文件从 EKS 上传到 S3 存储桶?

如何在不使用密钥的情况下将 GitHub 操作与 AWS 部署连接?

如何在不使用 SDK 的情况下将文件从 Android 上传到 Amazon S3