如何将Python requests库的响应转换为“类文件对象”

8 投票
1 回答
1870 浏览
提问于 2025-04-18 13:39

我正在用Python的requests库访问一个网络服务,结果返回了一个(非常大的)CSV文件,我想把它直接导入到数据库中。我的代码大致是这样的:

response = requests.get(url, auth=auth, stream=True)
if response.status_code == 200:
    stream_csv_into_database(response)

当我使用MongoDB数据库时,加载过程非常顺利,使用DictReader就可以了:

def stream_csv_into_database(response):
    .
    .
    .
    for record in csv.DictReader(response.iter_lines(), delimiter='\t'):
        product_count += 1
        product = {k:v for (k,v) in record.iteritems() if v}
        product['_id'] = product_count
        collection.insert(product)

不过,我现在要从MongoDB切换到亚马逊的RedShift数据库,我已经可以通过psycopg2正常访问它。我可以顺利打开连接并进行简单查询,但我想做的是利用从网络服务获取的流式响应,使用psycopg2的copy_expert来加载RedShift表。以下是我目前尝试的代码:

def stream_csv_into_database(response, campaign, config):
    print 'Loading product feed for {0}'.format(campaign)
    conn = new_redshift_connection(config) # My own helper, works fine.
    table = 'products.' + campaign
    cur = conn.cursor()
    reader = response.iter_lines()
    # Error on following line:
    cur.copy_expert("COPY {0} FROM STDIN WITH CSV HEADER DELIMITER '\t'".format(table), reader)
    conn.commit()
    cur.close()
    conn.close()

我遇到的错误是:

文件必须是可读的类文件对象才能进行COPY FROM;可写的类文件对象才能进行COPY TO。

我明白这个错误的意思;实际上,我从psycopg2的文档中看到,copy_expert调用了copy_from,它的功能是:

从类文件对象中读取数据并将其附加到数据库表中(COPY table FROM file语法)。源文件必须具有read()和readline()方法。

我的问题是,我找不到方法让response对象变成一个类文件对象!我尝试了.data.iter_lines都没有成功。我当然不想从网络服务下载整个几GB的文件,然后再上传到RedShift。一定有办法让流式响应作为一个类文件对象,这样psycopg2就可以将数据复制到RedShift中。有没有人知道我缺少了什么?

1 个回答

6

你可以使用 response.raw 文件对象,但要注意,如果内容经过了编码(比如 GZIP 或 Deflate 压缩),这些编码会依然存在,除非你在调用 .read() 时把 decode_content 这个选项设置为 True,而 psycopg2 是不会这样做的。

你可以在 raw 文件对象上设置这个选项,以便在读取时默认进行解压:

response.raw.decode_content = True

然后可以使用 response.raw 文件对象来配合 csv.DictReader()

撰写回答