Python UNICODE csv阅读器GZIPPED文件

时间:2017-07-18 08:32:19

标签: python python-2.7 csv unicode gzip

我已阅读与unicode阅读相关的每个帖子,但我似乎无法让它工作。

我试图读取一个恰好在其上有utf-8 BOM签名的csv,也是utf-8。

所以,在打开文件后,用unicodecsv库读取它,我尝试了不同的东西。

def _extract_gz(self):  # fd
    logging.info("Gz detected")
    self.fp = gzip.open(self.path)
    return unicodecsv.reader(self.path.read().decode('utf-8-sig').splitlines(), encoding='utf-8')

仍然在第226行失败.UnicodeEncodeError:'ascii'编解码器无法编码位置226中的字符u'\ xf1':序数不在范围内(128)

也试过这种方法,但也失败了。

def _extract_gz(self):  # fd
    logging.info("Gz detected")
    self.fp = gzip.open(self.path)
    self.f = self.unicode_csv_reader()
    return self.f

def unicode_csv_reader(self):
    csv_reader = csv.reader(self.fp.read().decode('utf-8-sig').splitlines())
    for row in csv_reader:
        yield [cell.encode('utf-8', 'replace') for cell in row]

我做错了什么?

谢谢大家。

版本是 Python 2.7.12

1 个答案:

答案 0 :(得分:1)

内置的csv模块不支持Unicode(假设是Python 2.x),但是有一个替换unicodecsv模块可以做(并且你已经尝试过了,不成功),它应该是相当简单的:

import gzip
import unicodecsv as csv

def read_csv(filename, has_bom=True, **kwargs):
    with gzip.open(filename, "r") as f:
        if has_bom:
            f.seek(3)  # skip the BOM
        reader = csv.reader(f, **kwargs)
        for row in reader:
            yield row

for row in read_csv("path/to/your.csv.gz", delimiter=";"):  # encoding needed for BOM
    print(row)  # or do whatever you want with it

应该做的伎俩。

更新 - 以上代码适用于您上传的文件,并且不会引发任何错误(因为您的文件是由我添加的半列分隔的),但是unicodecsv模块中的错误 - 在解析带有BOM的文件时,它不会删除第一列名称周围的引号,因此我更新了代码以反映该内容。

在上传的文件中运行时,您会得到以下输出(YMMV,取决于您的控制台如何打印unicode):

[u'Name', u'Ref', u'POS', u'POS', u'Status', u'City', u'']
[u'Hotel Flamero', u'3365', u'ES', u'0.27', u'No Change', u'Matalascañas', u'']

(最后一个空条目是由于您的CSV将最后一个条目设为空)

UPDATE#2 - 手头没有MySQL实例,但您可以使用内存中的SQLite DB检查它是否正常解析:

import sqlite3
db = sqlite3.connect(":memory:")  # create an in-memory DB
c = db.cursor()
c.execute("CREATE TABLE test (Name TEXT, Ref TEXT, POS TEXT, Status TEXT, City TEXT)")

header = None
for row in read_csv("path/to/your.csv.gz", delimiter=";"):
    del row[-1]  # remove the last element as it's always empty
    if header is None:  # get the header first
        header = row
        continue
    query = u"INSERT INTO test ({}) VALUES ({})".format(
        u", ".join(header),
        u", ".join(u"'{}'".format(column) for column in row)  # quote each column entry
    )
    c.execute(query)

# now lets read our data from the DB
c.execute("SELECT * FROM test")
for row in c.fetchall():
    print(row)

幸福地打印出来:

(u'Hotel Flamero', u'3365', u'ES', u'No Change', u'Matalascañas')