如何从CSV文件中读取字节对象?

15

我使用了tweepy和Python的csv.writer()将推文的文本存储在CSV文件中,但是在存储之前,我必须对文本进行utf-8编码,否则tweepy会抛出奇怪的错误。

现在,文本数据被存储如下:

"b'Lorem Ipsum\xc2\xa0Assignment '"

我试过使用这段代码进行解码(在其他列中还有更多数据,文本在第三列):

with open('data.csv','rt',encoding='utf-8') as f:
    reader = csv.reader(f,delimiter=',')
    for row in reader:
        print(row[3])

但是,它不会解码文本。我无法使用.decode('utf-8'),因为csv读取器将数据读取为字符串,即row[3]的类型为'str',而我似乎无法将其转换为bytes,这样数据就会再次编码!

如何解码文本数据?

编辑:这是来自csv文件的示例行:

67783591545656656999,3415844,1450443669.0,b'Virginia School District Closes After Backlash Over Arabic Assignment: The Augusta County school district in\xe2\x80\xa6  | @abcde',52,18

注意:如果问题出在编码过程中,请注意我无法负担再次下载整个数据。


请提供您的文件中至少一行完整的代码,就像在文本编辑器中打开该文件时所显示的那样。如果没有您的代码和数据,我们无法重现您的问题。 - BoarGules
很抱歉,我已经添加了一个例子。请将该行代码保存到一个名为.csv的文件中。 - gitmorty
那么这个csv文件里面实际上有字符串,它们在表示时带有b前缀,比如b'Virginia...' - martineau
3
生成那个 CSV 文件的程序有问题,需要修复。 - tripleee
3个回答

15

最简单的方法如下所示。试试看吧。

import csv
from io import StringIO

byte_content = b"iam byte content"
content = byte_content.decode()
file = StringIO(content)
csv_data = csv.reader(file, delimiter=",")

7
如果您的输入文件确实包含带有Python语法b前缀的字符串,一种解决方法(即使这不是csv数据的有效格式)是使用Python的ast.literal_eval()函数,如@Ry 建议的方式 - 尽管我会以稍微不同的方式使用它,如下所示。
这将提供一种安全的方法来解析文件中带有b前缀的字符串,指示它们是字节字符串。其余部分将保持不变。
请注意,这不需要将整个CSV文件读入内存中。
import ast
import csv


def _parse_bytes(field):
    """Convert string represented in Python byte-string literal b'' syntax into
    a decoded character string - otherwise return it unchanged.
    """
    result = field
    try:
        result = ast.literal_eval(field)
    finally:
        return result.decode() if isinstance(result, bytes) else result


def my_csv_reader(filename, /, **kwargs):
    with open(filename, 'r', newline='') as file:
        for row in csv.reader(file, **kwargs):
            yield [_parse_bytes(field) for field in row]


reader = my_csv_reader('bytes_data.csv', delimiter=',')
for row in reader:
    print(row)

谢谢。这确实解决了上面的问题,但我不太舒服使用eval()。它甚至在我的文件上失败了,因为它有标题字符串。 - gitmorty
gitmorty: 我认为@Ryan使用ast.literal_eval()而不是eval()的想法很好,并将基本思想融入了我的答案中 - 我认为这解决了您在评论中提到的两个问题。 - martineau

2
你可以使用 ast.literal_eval 来安全地将不正确的字段转换回字节:
import ast


def _parse_bytes(bytes_repr):
    result = ast.literal_eval(bytes_repr)

    if not isinstance(result, bytes):
        raise ValueError("Malformed bytes repr")

    return result

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接