2017-02-01 10 views
1

Я пытаюсь перебирать строки в файле csv. Я получаю csv файл string с веб-сайта. Я знаю, как создать csv.reader с использованием with, когда данные хранятся в файле. Я не знаю, как получить строки с использованием csv.reader без сохранения string в файл. Я использую Python 2.7.12.Как использовать строку в качестве входа для чтения csv, не сохраняя ее в файле

Я пытался создать StringIO объект, как это:

from StringIO import StringIO 

csv_data = "some_string\nfor_example" 
with StringIO(csv_data) as input_file: 
    csv_reader = reader(csv_data, delimiter=",", quotechar='"') 

Однако, я получаю эту ошибку:

Traceback (most recent call last): 
    File "scraper.py", line 228, in <module> 
    with StringIO(csv_data) as input_file: 
AttributeError: StringIO instance has no attribute '__exit__' 

Я понимаю, что StringIO класс не имеет __exit__ метод, который вызывается, когда when заканчивает выполнение того, что он делает с этим объектом.

Ответ на вопрос, как это сделать правильно? Я полагаю, что я могу изменить класс StringIO путем подклассификации его и добавления метода __exit__, но я подозреваю, что есть более легкое решение.

Update:

Кроме того, я пробовал различные комбинации, которые пришли мне на ум:

with open(StringIO(csv_data)) as input_file: 

with csv_data as input_file: 

, но, конечно, ни один из тех, кто работал.

+2

Просто используйте 'input_file = StringIO (csv_data)' вместо блока 'with'. Как загрузить CSV-данные из Интернета? Обычно вы загружаете файл-файл при загрузке, который можно использовать напрямую без предварительного хранения всего содержимого в строковой переменной, а затем обертывания этой переменной в 'StringIO'. –

+0

Невозможно воспроизвести в Python 3.5. 'StringIO' можно использовать в' with'. Что такое * точно * ваша версия и код? ('from StringIO import StringIO' is * bad * ...) –

+0

@SvenMarnach Да, я могу сделать это таким образом, но я бы хотел использовать' with'. Я использую 'request.get' для получения данных, а затем создаю' csv_data' из 'response.text'. – Fejs

ответ

3
>>> import csv 
>>> csv_data = "some,string\nfor,example" 
>>> result = csv.reader(csv_data.splitlines()) 
>>> list(result) 
[['some', 'string'], ['for', 'example']] 
+0

Это довольно приятное решение, спасибо. – Fejs

+0

Это не будет работать, если строка имеет переводы строк внутри указанных значений. – swooby

0

Если вы хотите менеджеров контекста, вы можете использовать tempfile вместо:

import tempfile 


with tempfile.NamedTemporaryFile(mode='w') as t: 
    t.write('csv_data') 
    t.seek(0) 
    csv_reader = reader(open(t.name), delimiter=",", quotechar='"') 

Как преимущество, чтобы передать строку splitlines непосредственно для читателя CSV вы можете написать файл любого размера, а затем спокойно читать его в csv reader без проблем с памятью.

Этот файл будет закрыт и удален автоматически

1

Вы должны использовать IO модуль вместо StringIO один, потому что io.BytesIO для байтов строки или io.StringIO для них Unicode и поддерживают интерфейс контекста менеджера и может быть использован в with заявления:

from io import BytesIO 
from csv import reader 
csv_data = "some_string\nfor_example" 
with BytesIO(csv_data) as input_file: 
    csv_reader = reader(input_file, delimiter=",", quotechar='"') 
    for row in csv_reader: 
     print row 
+0

Я получаю следующую ошибку при попытке: «Traceback (последний последний звонок): Файл« scraper.py », строка 227, в с BytesIO (race_csv_data) в качестве входного_файла: TypeError: 'unicode' не имеет интерфейса буфера' – Fejs

+0

@Fejs Это означает, что ваша 'race_csv_data' является строкой unicode, и вы должны использовать' io.StringIO' вместо 'io.BytesIO '(но ваш пример использовал байтовую строку ;-) ...) –