Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Практический парсинг
practical_parsing

Практический парсинг

Парсинг логов, HTML, JSON, CSV, извлечение структурированных данных

Практический парсинг

Регулярные выражения мощны для извлечения структурированных данных из текста: логи, HTML, JSON, CSV. В этой теме изучим практические приёмы парсинга.

#Парсинг логов

#Формат Apache/Nginx

import re log_line = '192.168.1.1 - - [09/Mar/2024:14:30:15 +0000] "GET /index.html HTTP/1.1" 200 1234' # Извлечение IP, даты, метода, пути, статуса, размера pattern = r''' ^(?P<ip>\d+\.\d+\.\d+\.\d+) # IP адрес \s+-\s+-\s+ # идентификаторы \[(?P<timestamp>[^\]]+)\] # timestamp \s+"(?P<method>\w+)\s+ # метод (?P<path>\S+)\s+ # путь (?P<protocol>[^"]+)" # протокол \s+(?P<status>\d+) # статус \s+(?P<size>\d+) # размер ''' match = re.search(pattern, log_line, re.VERBOSE) if match: data = match.groupdict() # {'ip': '192.168.1.1', 'timestamp': '09/Mar/2024:14:30:15 +0000', # 'method': 'GET', 'path': '/index.html', 'protocol': 'HTTP/1.1', # 'status': '200', 'size': '1234'}

#Парсинг множества строк

log_text = """ 192.168.1.1 - - [09/Mar/2024:14:30:15 +0000] "GET /index.html HTTP/1.1" 200 1234 192.168.1.2 - - [09/Mar/2024:14:30:16 +0000] "POST /api/data HTTP/1.1" 201 567 192.168.1.1 - - [09/Mar/2024:14:30:17 +0000] "GET /style.css HTTP/1.1" 200 890 """ pattern = r'^(?P<ip>\d+\.\d+\.\d+\.\d+).*"(?P<method>\w+)\s+(?P<path>\S+).*"\s+(?P<status>\d+)' requests = [] for match in re.finditer(pattern, log_text, re.MULTILINE): requests.append(match.groupdict()) # requests = [ # {'ip': '192.168.1.1', 'method': 'GET', 'path': '/index.html', 'status': '200'}, # {'ip': '192.168.1.2', 'method': 'POST', 'path': '/api/data', 'status': '201'}, # {'ip': '192.168.1.1', 'method': 'GET', 'path': '/style.css', 'status': '200'} # ]

#Фильтрация по статусу

# Найти все 4xx и 5xx ошибки errors = [r for r in requests if int(r['status']) >= 400] # Найти все POST запросы posts = [r for r in requests if r['method'] == 'POST']

#Парсинг HTML (простые случаи)

Предупреждение: Для сложного HTML используйте BeautifulSoup. Regex подходит только для простых, предсказуемых структур.

#Извлечение ссылок

html = ''' <a href="https://example.com">Example</a> <a href="/page1">Page 1</a> <a href='page2.html'>Page 2</a> ''' # Извлечение URL из ссылок pattern = r'<a\s+href=["\']([^"\']+)["\']' urls = re.findall(pattern, html) # ['https://example.com', '/page1', 'page2.html'] # Извлечение текста ссылки pattern = r'<a\s+href=["\'][^"\']+["\']>([^<]+)</a>' texts = re.findall(pattern, html) # ['Example', 'Page 1', 'Page 2']

#Извлечение данных из тегов

html = ''' <div class="price">199.99</div> <div class="price">299.50</div> <span class="name">Product 1</span> ''' # Цены prices = re.findall(r'<div\s+class="price">([\d.]+)</div>', html) # ['199.99', '299.50'] # Названия names = re.findall(r'<span\s+class="name">([^<]+)</span>', html) # ['Product 1']

#Извлечение данных из JSON-like структур в HTML

html = '<div data-product=\'{"id": 123, "name": "Product"}\'></div>' # Извлечение JSON pattern = r'data-product=\'({[^}]+})\'' match = re.search(pattern, html) if match: import json data = json.loads(match.group(1)) # {'id': 123, 'name': 'Product'}

#Парсинг JSON (для простых случаев)

Предупреждение: Для JSON используйте модуль json. Regex только для извлечения частей.

#Извлечение значения по ключу

json_text = '{"name": "John", "age": 30, "city": "Moscow"}' # Извлечение значения по ключу pattern = r'"name":\s*"([^"]+)"' match = re.search(pattern, json_text) if match: name = match.group(1) # 'John' # Для числовых значений pattern = r'"age":\s*(\d+)' match = re.search(pattern, json_text) if match: age = int(match.group(1)) # 30

#Вложенные структуры

json_text = ''' { "user": { "name": "John", "contacts": { "email": "john@example.com", "phone": "+79991234567" } } } ''' # Извлечение email pattern = r'"email":\s*"([^"]+)"' match = re.search(pattern, json_text) email = match.group(1) # 'john@example.com'

#Парсинг CSV

#Простой CSV

csv_text = """name,age,city John,30,Moscow Jane,25,Paris Bob,35,London""" # Разбиение на строки lines = csv_text.strip().split('\n') # Парсинг каждой строки pattern = r'^([^,]+),([^,]+),([^,]+)$' for line in lines[1:]: # Пропуск заголовка match = re.match(pattern, line) if match: name, age, city = match.groups()

#CSV с кавычками

csv_text = '''name,description,price "Product 1","Description with, comma",199.99 "Product 2","Simple description",299.50''' # Извлечение полей с кавычками pattern = r'"([^"]+)"|"([^"]+)"|([^,]+)' # Лучше использовать csv модуль для надёжности

#Извлечение структурированных данных

#Номера заказов

text = 'Заказы: #12345, #67890, #11111' # Все номера заказов orders = re.findall(r'#(\d+)', text) # ['12345', '67890', '11111']

#Цены

text = 'Цены: 199.99 руб., 299.50 руб., 1000 руб.' # Все цены prices = re.findall(r'(\d+(?:\.\d+)?)\s*руб', text) # ['199.99', '299.50', '1000']

#Даты в разных форматах

text = 'Даты: 2024-03-09, 09.03.2024, 03/09/2024' # YYYY-MM-DD dates1 = re.findall(r'\d{4}-\d{2}-\d{2}', text) # ['2024-03-09'] # DD.MM.YYYY dates2 = re.findall(r'\d{2}\.\d{2}\.\d{4}', text) # ['09.03.2024'] # MM/DD/YYYY dates3 = re.findall(r'\d{2}/\d{2}/\d{4}', text) # ['03/09/2024']

#Практические примеры

#1. Парсинг email из текста

text = """ Контакты: support@example.com sales@test.org admin@company.co.uk """ pattern = r'[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}' emails = re.findall(pattern, text) # ['support@example.com', 'sales@test.org', 'admin@company.co.uk']

#2. Извлечение хэштегов

text = '#Python #regex #programming и #100days' # Все хэштеги hashtags = re.findall(r'#(\w+)', text) # ['Python', 'regex', 'programming', '100days']

#3. Парсинг упоминаний

text = '@john привет! @jane как дела?' # Все упоминания mentions = re.findall(r'@(\w+)', text) # ['john', 'jane']

#4. Извлечение размеров файлов

text = 'Файлы: document.pdf (1.5 MB), image.jpg (2.3 KB), video.mp4 (1.2 GB)' # Все размеры с единицами sizes = re.findall(r'\(([\d.]+)\s*(KB|MB|GB)\)', text) # [('1.5', 'MB'), ('2.3', 'KB'), ('1.2', 'GB')]

#5. Парсинг комментариев кода

code = """ # Это комментарий def hello(): # Ещё комментарий pass """ # Все комментарии comments = re.findall(r'#\s*(.+)$', code, re.MULTILINE) # ['Это комментарий', 'Ещё комментарий']

#6. Извлечение данных из Markdown

markdown = """ # Заголовок 1 ## Заголовок 2 [Ссылка](https://example.com) ![Изображение](image.png) """ # Заголовки первого уровня h1 = re.findall(r'^#\s+(.+)$', markdown, re.MULTILINE) # ['Заголовок 1'] # Заголовки второго уровня h2 = re.findall(r'^##\s+(.+)$', markdown, re.MULTILINE) # ['Заголовок 2'] # Ссылки links = re.findall(r'\[([^\]]+)\]\(([^)]+)\)', markdown) # [('Ссылка', 'https://example.com')]

#Обработка больших файлов

#Чтение по строкам

def parse_log_file(filename): pattern = re.compile(r'^(?P<ip>\d+\.\d+\.\d+\.\d+).*"(?P<method>\w+)') with open(filename, 'r') as f: for line in f: match = pattern.match(line) if match: yield match.groupdict() # Использование for request in parse_log_file('access.log'): process(request)

#Использование finditer для памяти

# Вместо findall, который создаёт весь список в памяти text = large_text # Очень большой текст # Плохо: создаёт список всех совпадений matches = re.findall(r'\d+', text) # Хорошо: итератор for match in re.finditer(r'\d+', text): process(match.group())

#Распространённые ошибки

#1. Жадный захват в HTML

html = '<div>content1</div><div>content2</div>' # Ошибка: жадный захват re.findall(r'<div>.*</div>', html) # ['<div>content1</div><div>content2</div>'] # Правильно: нежадный захват re.findall(r'<div>.*?</div>', html) # ['<div>content1</div>', '<div>content2</div>']

#2. Парсинг вложенного HTML

html = '<div><span>nested</span></div>' # Ошибка: regex не может парсить вложенные структуры re.findall(r'<div>.*</div>', html) #соответствует весь HTML # Правильно: использовать BeautifulSoup from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'html.parser') div = soup.find('div')

#3. Забытые группы в findall

text = '1-2 3-4' # Ошибка: ожидали полные совпадения re.findall(r'(\d+)-(\d+)', text) # [('1', '2'), ('3', '4')] # Правильно: non-capturing группы re.findall(r'(?:\d+)-(?:\d+)', text) # ['1-2', '3-4']

Далее: Продвинутые техники