如何将Python requests库的响应转换为“类文件对象”
我正在用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 个回答
你可以使用 response.raw
文件对象,但要注意,如果内容经过了编码(比如 GZIP 或 Deflate 压缩),这些编码会依然存在,除非你在调用 .read()
时把 decode_content
这个选项设置为 True
,而 psycopg2 是不会这样做的。
你可以在 raw
文件对象上设置这个选项,以便在读取时默认进行解压:
response.raw.decode_content = True
然后可以使用 response.raw
文件对象来配合 csv.DictReader()
。