Сбор данных в таблицу: CSV и JSON
Финальная цель скрейпинга — превратить хаос HTML в аккуратную таблицу.
Извлечённые данные складывают в список словарей, а затем сохраняют в CSV или JSON. Каждая строка — одна сущность (товар, вакансия), каждый ключ — одно поле.
Парсинг отдельных элементов — это половина дела. Скрейпер должен собрать их в структуру: пройти по всем карточкам, из каждой вытащить набор полей и сложить в список словарей. Такой список легко записать в файл или загрузить в pandas. Разберём типовой паттерн «цикл по карточкам».
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
rows = []
for card in soup.select('div.product'):
title_el = card.select_one('.title')
price_el = card.select_one('.price')
rows.append({
'title': title_el.text.strip() if title_el else None,
'price': price_el.text.strip() if price_el else None,
'url': card.find('a').get('href'),
})Сохранение в CSV и JSON
Для сохранения хватает стандартных модулей csv и json — никаких внешних зависимостей.
import csv, json
with open('products.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=['title', 'price', 'url'])
writer.writeheader()
writer.writerows(rows)
with open('products.json', 'w', encoding='utf-8') as f:
json.dump(rows, f, ensure_ascii=False, indent=2)Как работает под капотом
Паттерн «список словарей» — это, по сути, таблица в памяти: список = строки, ключи словаря = столбцы. csv.DictWriter по списку имён полей формирует заголовок и сериализует каждую строку. json.dump с ensure_ascii=False сохраняет кириллицу читаемой, а не в виде \uXXXX. Очистка .strip() убирает лишние пробелы и переводы строк, которыми обычно «загрязнён» текст из HTML. Покажем чистку и сборку строки таблицы прямо в браузере:
Попробуй сам ▶
raw_cards = [
(' Ноутбук Pro\n', '79 990 ₽'),
('Мышь Lite ', ' 1290 руб '),
]
import re
rows = []
for title, price in raw_cards:
clean_title = title.strip()
# оставить только цифры в цене
digits = re.sub(r'[^0-9]', '', price)
rows.append({'title': clean_title, 'price': int(digits)})
for r in rows:
print(r)
print('Самый дорогой:', max(rows, key=lambda x: x['price'])['title'])От разрозненных полей к чистому датасету
Сбор данных редко заканчивается на «вытащил текст». Реальный датасет требует согласованности: цена везде число, а не строка «79 990 ₽»; дата в одном формате (лучше ISO ГГГГ-ММ-ДД); отсутствующие поля помечены явным None, а не пустой строкой. Эту работу удобно вынести в отдельную функцию-нормализатор, через которую прогоняется каждая собранная запись. Тогда логика извлечения и логика очистки не перемешиваются, и код проще править.
Полезная привычка — сохранять сырой HTML страниц на диск во время разработки. Парсер почти всегда приходится дорабатывать: нашёлся товар без цены, появилась акционная плашка, изменилась вёрстка одной категории. Если каждый перезапуск парсера снова бьёт по живому сайту, ты создаёшь лишнюю нагрузку и рискуешь быть заблокированным за частоту. Скачав страницы один раз и отлаживая разбор локально, ты и работаешь быстрее, и ведёшь себя вежливо по отношению к источнику. Для масштабных проектов ту же идею реализует HTTP-кэш Scrapy.
Частые ошибки
- Не чистить текст. «\n 79 990 ₽ » превратится в мусор без
.strip()и нормализации. - Падать на отсутствующем поле. Не у всех карточек есть все поля — используй защиту
if el else None. - Сохранять кириллицу как
\uXXXX. Указывайensure_ascii=Falseиencoding='utf-8'.
Best practices
- Складывай данные в единообразные словари с фиксированным набором ключей.
- Нормализуй значения сразу:
strip(), приведение цены к числу, дат к ISO-формату. - Сохраняй сырой HTML на диск при отладке — чтобы не перезапрашивать сайт ради переразбора.
Для табличных данных удобно сразу думать в терминах будущего анализа. Список словарей легко превращается в pandas.DataFrame одной строкой, а оттуда — в Excel, базу или график. Поэтому ещё на этапе сбора стоит давать полям понятные, единообразные имена и приводить значения к правильным типам. Чем чище данные на выходе скрейпера, тем меньше мучений на этапе анализа — а ведь именно ради анализа данные обычно и собирают.
Итог: цель — список словарей, превращённый в CSV/JSON стандартными модулями. Главное на этом этапе — аккуратная чистка и нормализация значений, иначе таблица будет грязной.