У меня есть две функции: одна загружает отдельные файлы CSV, а другая загружает zip-архив с несколькими файлами CSV.
Функция download_and_process_csv
корректно работает с response.iter_lines()
, которая, похоже, удаляет символы новой строки.
«Курица, вода, кукурузная мука, соль, декстроза, сахар, фосфат натрия, эриторбат натрия, нитрит натрия. Произведено на предприятии, где присутствуют аллергены, такие как яйца, молоко, соя, пшеница, горчица, глютен, овес, молочные продукты».
Функция download_and_process_zip
, похоже, по какой-то причине включает символы новой строки (\n\n
). Я пробовал newline=''
в io.TextIOWrapper
, но он просто заменяет его на \r\n
.
«Курица, вода, кукурузная мука, соль, декстроза, сахар, фосфат натрия, эриторбат натрия, нитрит натрия. \n\nПроизведено на предприятии, где присутствуют аллергены, такие как яйца, молоко, соя, пшеница, горчица, глютен, овес, молочные продукты».
Есть ли способ изменить download_and_process_zip
так, чтобы символы новой строки были исключены/заменены, или мне придется перебирать все строки и вручную заменять символы?
@request_exceptions
def download_and_process_csv(client, url, model_class):
with closing(client.get(url, stream=True)) as response:
response.raise_for_status()
response.encoding = 'utf-8'
reader = csv.reader(response.iter_lines(decode_unicode=True))
process_copy_from_csv(model_class, reader)
@request_exceptions
def download_and_process_zip(client, url):
with closing(client.get(url, stream=True)) as response:
response.raise_for_status()
with io.BytesIO(response.content) as buffer:
with zipfile.ZipFile(buffer, 'r') as z:
for filename in z.namelist():
base_filename, file_extension = os.path.splitext(filename)
model_class = apps.get_model(base_filename)
if file_extension == '.csv':
with z.open(filename) as csv_file:
reader = csv.reader(io.TextIOWrapper(
csv_file,
encoding='utf-8',
# newline='',
))
process_copy_from_csv(model_class, reader)
Я поигрался с фиктивным сервером, который обслуживает этот CSV-файл:
"foo
bar"
CSV содержит одно поле "foo\nbar"
в одной строке. Я называю новую строку в данных встроенной новой строкой.
Когда я использую метод iter_content для объекта Response:
print("Getting CSV")
resp = requests.get("http://localhost:8999/csv")
x = resp.iter_content(decode_unicode=True)
reader = csv.reader(x)
for row in reader:
print(row)
Я получаю правильный вывод: выводится одна строка с одним полем данных:
Getting CSV
['foo\nbar']
Если я изменю iter_content на iter_lines, я получу неправильный результат:
Getting CSV
['foobar']
Судя по названию, я подозреваю, что iter_lines ищет любую последовательность символов, подобную новой строке, и останавливается на ней, прежде чем передать строку программе чтения csv (без новой строки), и поэтому встроенная новая строка эффективно удаляется. Я не могу говорить о вашем результате, когда новая строка была заменена пробелом... замены не происходит, просто эффективно удаляется.
Этот популярный SO, Использовать запросы Python для загрузки CSV, задает общий вопрос о загрузке CSV с помощью модуля запросов, но каждый ответ, кажется, адаптирован к тому факту, что рассматриваемый CSV не содержит встроенных символов новой строки, и поэтому там много ответов с iter_lines. Я не знаю, когда в запросы была добавлена функция iter_content(), но об этом не упоминается ни в одном ответе.
Что касается замены пробелом, это моя ошибка - на самом деле символы новой строки удаляются. Я не внимательно присмотрелся, так как даже в моем примере перед символами новой строки есть пробел ' \n\n'
возможно, проверьте, что у вас есть в переменных, прежде чем использовать
TextIOWrapper
- возможно, проблема в другом месте. ИЛИ, может быть, вы могли бы читать какbytes
вместоstring