Обработка и разбор файлов CSV, логов и специфических форматов в Python
Основные подходы к разбору файлов в Python
Наиболее эффективный способ парсинга CSV: использование модуля csv
Модуль csv встроен в Python и корректно обрабатывает кавычки, экранирование, разные разделители. Для файлов с заголовками удобен класс DictReader.
import csv
with open('data.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
print(row['name'], row['age'])ввод программ на python (ввод данных в программе python)
Вывод (для примера data.csv: name,age\nAlice,30\nBob,25):
Alice 30 Bob 25
Python file io (ввод-вывод файлов в python)
Если разделитель иной (например, точка с запятой), укажите параметр delimiter=';'. Для файлов без заголовков используйте csv.reader.
Типичные проблемы:
- Неверная кодировка - укажите encoding (utf-8, cp1251).
- Пустые строки в конце файла - reader их пропускает, но проверяйте.
- Строки с разным количеством полей - DictReader выдаст ошибку. Решение: csv.reader и ручная проверка.
Как разобрать CSV вручную без модуля csv?
with open('data.csv', 'r') as f:
for line in f:
parts = line.strip().split(',')
print(parts)
Python temp files (временные файлы в python)
Проблема: разделитель внутри кавычек (например, "Smith, John") будет разбит некорректно. Модуль csv решает это автоматически.
Как разобрать файл лога Apache (Common Log Format)?
import re
pattern = r'^(\S+) \S+ \S+ \[([^\]]+)\] "(\S+) (\S+) \S+" (\d+) (\d+)'
with open('access.log', 'r') as f:
for line in f:
match = re.match(pattern, line)
if match:
ip, date, method, url, status, size = match.groups()
print(ip, url)Python index files (индексация файлов в python)
Этот подход гибок для любых логов. Ошибки: несоответствие формату строки - проверяйте None.
Как обработать custom файл с нестандартным разделителем и комментариями?
# Пример файла data.custom:
# name|age|city
Alice|30|New York
Bob|25|Los Angeles
with open('data.custom', 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
parts = line.split('|')
print(parts)
Проблемы: экранирование разделителя внутри поля не предусмотрено. Для сложных custom форматов используйте регулярные выражения или напишите свой парсер на основе конечного автомата.
Общие проблемы при парсинге любых файлов:
- Большие файлы: читайте построчно, не загружайте в память целиком.
- Битые строки: добавьте try-except и логирование.
- Разные кодировки: используйте chardet для автоматического определения.
Построчный парсинг CSV с генератором и обработкой ошибок
import csv
def parse_csv(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
yield int(row['age']), row['name']
except (ValueError, KeyError) as e:
print(f'Ошибка в строке {reader.line_num}: {e}')
for age, name in parse_csv('data.csv'):
print(f'{name}: {age}')
Alice: 30 Bob: 25
Разбор Combined Log Format (Apache) с извлечением User-Agent
import re
# Combined Log Format: IP rfc931 authuser [date] "method resource protocol" status size "referer" "user-agent"
pattern = r'^(\S+) \S+ \S+ \[([^\]]+)\] "(\S+) (\S+) \S+" (\d+) (\d+) "([^"]*)" "([^"]*)"'
with open('access.log', 'r') as f:
for line in f:
m = re.match(pattern, line)
if m:
ip, date, method, url, status, size, referer, ua = m.groups()
print(f'IP: {ip}, URL: {url}, UA: {ua[:50]}')
IP: 192.168.1.1, URL: /index.html, UA: Mozilla/5.0...
Парсинг файла с фиксированной шириной столбцов (Fixed Width)
# Пример: строки вида "ALICE 30 NEW YORK" (10 символов имя, 5 возраст, 20 город)
widths = [10, 5, 20]
fields = ['name', 'age', 'city']
with open('fixed.txt', 'r') as f:
for line in f:
start = 0
row = {}
for i, w in enumerate(widths):
raw = line[start:start+w].strip()
row[fields[i]] = raw
start += w
print(row)
{'name': 'ALICE', 'age': '30', 'city': 'NEW YORK'}
Проблемы: строки разной длины, лишние пробелы. Решение: обрезать line.rstrip('\n') и проверять длину.
Использование csv.Sniffer для автоматического определения диалекта
import csv
with open('unknown.csv', 'r') as f:
sample = f.read(1024)
dialect = csv.Sniffer().sniff(sample)
f.seek(0)
reader = csv.reader(f, dialect=dialect)
for row in reader:
print(row)
Sniffer анализирует разделитель, кавычки, символ конца строки. Работает не всегда корректно на маленьких выборках.
Парсинг многострочных полей в CSV (с переносом строки внутри кавычек)
# Модуль csv поддерживает многострочные поля по умолчанию
import csv
with open('multiline.csv', 'r') as f:
reader = csv.reader(f)
for row in reader:
# row может содержать строку с \n
print(row)
Пример multiline.csv:
"Alice","Hello world",30 "Bob","Single line",25
Первая запись вернет ['Alice', 'Hello\nworld', '30']. Важно: файл должен быть открыт с newline='' (по умолчанию), иначе будет нарушено экранирование.