Парсинг на Python: с чего начать
Парсинг (веб-скрапинг) - это автоматический сбор данных со страниц сайта: цен, названий, ссылок, таблиц. Python для этой задачи подходит лучше большинства языков: за десяток строк кода можно скачать страницу, найти нужные элементы и сохранить результат в CSV. Ниже собран план обучения, минимальный набор библиотек, правила вежливого парсинга и первый парсер, который можно запустить прямо сейчас.

Содержание статьи
Как устроен парсинг сайта
Любой парсер, от учебного скрипта до промышленного краулера, выполняет одни и те же четыре шага:
- Загрузка. Программа отправляет HTTP-запрос и получает HTML-код страницы, тот же самый, что видит браузер в режиме "Просмотр кода".
- Разбор. HTML превращается в дерево элементов, по которому можно искать теги, классы и атрибуты.
- Извлечение. Из найденных элементов берется текст, ссылки, числа, и все это приводится к удобному виду: строки без лишних пробелов, цены в виде
float. - Сохранение. Данные записываются в CSV, JSON, Excel или базу данных.
Если поверх этого добавить обход нескольких страниц, паузы между запросами и обработку ошибок, получится полноценный парсер. Каждый из этих шагов разобран в отдельном уроке цикла.
План обучения по шагам
Парсинг не требует глубокого знания Python, но без базы будет тяжело. Перед стартом стоит уверенно владеть циклами, списками, словарями и функциями. Дальше удобно двигаться в таком порядке:
- Основы HTML: теги, атрибуты
classиid, вложенность элементов. Достаточно умения читать код страницы в инструментах разработчика браузера (клавиша F12). - HTTP-запросы через библиотеку requests: метод GET, коды ответа, заголовки, таймауты.
- Разбор HTML с помощью BeautifulSoup: методы
find,find_all, CSS-селекторы черезselect. - Практика на простой странице: Урок 2. Парсер на Python показывает полный цикл от запроса до CSV.
- Табличные данные: Урок 3. Парсинг таблиц учит разбирать
table, чистить числа и использоватьpandas.read_html. - Много страниц подряд: Урок 4. Пагинация про переход по страницам, сессии, паузы и повторы при ошибках.
- Продвинутые темы: асинхронные запросы, динамические сайты на JavaScript, работа с API.
На каждый из первых шести пунктов уходит от одного вечера до пары дней. Главное правило: после каждого урока писать свой небольшой парсер на новой странице, а не только повторять примеры.
Базовый стек: requests, BeautifulSoup и lxml
Для 80 процентов задач хватает трех библиотек. Установить их можно одной командой:
pip install requests beautifulsoup4 lxml
| Библиотека | Что делает | Когда нужна |
|---|---|---|
| requests | Отправляет HTTP-запросы, возвращает ответ сервера | Всегда, когда нужно скачать страницу |
| beautifulsoup4 | Строит дерево HTML и дает удобный поиск по нему | Разбор страниц, поиск тегов и атрибутов |
| lxml | Быстрый парсер HTML и XML на C, поддерживает XPath | Как движок для BeautifulSoup или напрямую для больших объемов |
| pandas | Таблицы данных, чтение HTML-таблиц, экспорт в Excel | Когда данные табличные или их нужно анализировать |
| httpx | HTTP-клиент с поддержкой async и HTTP/2 | Сотни и тысячи страниц, асинхронный сбор |
BeautifulSoup сам по себе не разбирает HTML, он использует один из движков. Встроенный html.parser работает без установки, но медленнее. Движок lxml в несколько раз быстрее и лучше справляется с битой разметкой, поэтому в реальных проектах указывают именно его: BeautifulSoup(html, "lxml").
Когда этого стека недостаточно
Связка requests + BeautifulSoup видит только тот HTML, который отдал сервер. Если данные подгружаются JavaScript-кодом уже в браузере, в ответе их не будет. Прежде чем подключать тяжелые инструменты вроде Playwright, откройте в браузере вкладку Network и посмотрите, откуда приходят данные. Часто страница сама запрашивает JSON с внутреннего API, и этот JSON проще и надежнее забрать напрямую через requests, чем разбирать HTML.
Этика парсинга и файл robots.txt
Парсер нагружает чужой сервер, поэтому сбор данных должен быть аккуратным. Набор простых правил защищает и сайт, и вас от блокировки:
- Читайте robots.txt. Файл лежит в корне сайта (
/robots.txt) и сообщает, какие разделы роботам посещать нельзя. Это не технический запрет, а договоренность, которую принято соблюдать. - Делайте паузы. Одного запроса в секунду обычно достаточно. Десятки запросов в секунду к небольшому сайту выглядят как атака.
- Представляйтесь. Указывайте осмысленный заголовок
User-Agent, по которому администратор поймет, кто к нему ходит. - Не собирайте лишнего. Персональные данные людей, контент за авторизацией и материалы, запрещенные пользовательским соглашением, лучше не трогать вовсе.
- Ищите API. Если у сайта есть официальный API или выгрузка, используйте ее вместо парсинга HTML.
Проверить robots.txt можно стандартным модулем urllib.robotparser, ничего устанавливать не нужно:
from urllib.robotparser import RobotFileParser
rp = RobotFileParser()
rp.set_url("https://books.toscrape.com/robots.txt")
rp.read()
agent = "MyStudyBot/1.0"
print(rp.can_fetch(agent, "https://books.toscrape.com/catalogue/page-2.html"))
# -> True
print(rp.crawl_delay(agent))
# -> None (задержка не указана, берем свою, например 1 секунду)
Первый минимальный парсер
Для тренировки есть специальные учебные сайты, созданные для парсинга: books.toscrape.com (каталог книг) и quotes.toscrape.com (цитаты). На них можно экспериментировать без риска кому-то навредить. Следующий скрипт скачивает первую страницу каталога книг и печатает название и цену каждой книги:
import requests
from bs4 import BeautifulSoup
URL = "https://books.toscrape.com/"
HEADERS = {"User-Agent": "MyStudyBot/1.0 (learning python)"}
response = requests.get(URL, headers=HEADERS, timeout=10)
response.raise_for_status() # ошибка, если код ответа 4xx или 5xx
response.encoding = "utf-8"
soup = BeautifulSoup(response.text, "lxml")
for card in soup.select("article.product_pod"):
title = card.h3.a["title"] # полное название в атрибуте
price = card.select_one("p.price_color").get_text(strip=True)
print(f"{price:>8} {title}")
Результат выглядит так (первые строки):
£51.77 A Light in the Attic
£53.74 Tipping the Velvet
£50.10 Soumission
£47.82 Sharp Objects
Разберем, что здесь происходит:
timeout=10не дает программе зависнуть навсегда, если сервер не отвечает. Без таймаута requests ждет бесконечно.raise_for_status()сразу останавливает работу при ответе 404 или 500, вместо того чтобы молча разбирать страницу с ошибкой.soup.select("article.product_pod")находит все карточки товаров по CSS-селектору: тегarticleс классомproduct_pod.- Название берется из атрибута
title, потому что видимый текст ссылки на сайте обрезан многоточием.
Селекторы для своей задачи находят так: открываете страницу в браузере, нажимаете правой кнопкой на нужный элемент, выбираете "Исследовать" и смотрите, какие теги и классы его окружают. Ищите класс, который есть у всех однотипных элементов, например у всех карточек товара.
Куда сохранять собранные данные
Печать в консоль годится для отладки, но результат парсинга обычно нужен дальше: в таблице, в отчете, в базе. Удобнее всего сначала собрать данные в список словарей, а потом выгрузить в нужный формат.
import csv
import json
books = [
{"title": "A Light in the Attic", "price": 51.77},
{"title": "Tipping the Velvet", "price": 53.74},
]
# CSV: открывается в Excel и Google Таблицах
with open("books.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(f, fieldnames=["title", "price"])
writer.writeheader()
writer.writerows(books)
# JSON: удобно для дальнейшей обработки программами
with open("books.json", "w", encoding="utf-8") as f:
json.dump(books, f, ensure_ascii=False, indent=2)
Кодировка utf-8-sig добавляет в начало файла специальную метку, благодаря которой Excel в Windows правильно показывает кириллицу.
| Формат | Плюсы | Минусы |
|---|---|---|
| CSV | Простой, открывается в любой таблице | Только плоские данные, нет вложенности |
| JSON | Хранит списки и вложенные словари | Неудобно смотреть глазами большие объемы |
| Excel (xlsx) | Сразу готов для коллег, несколько листов | Нужны pandas и openpyxl |
| SQLite | Поиск, фильтры, дозапись без дублей | Нужно знать основы SQL |
Для регулярного сбора, когда парсер запускается каждый день и дописывает новые данные, лучше всего подходит SQLite: можно сделать уникальный ключ по ссылке и не получать дубликаты.
Типичные ошибки новичков
- Парсер падает с
AttributeError: 'NoneType' object has no attribute. Методfindилиselect_oneничего не нашел и вернулNone. Проверяйте результат перед обращением к атрибутам или пишите защищенный код:el.get_text(strip=True) if el else "". - Кракозябры вместо русского текста. Сервер не указал кодировку, и requests угадал неверно. Задайте
response.encoding = "utf-8"или передайте в BeautifulSoup байтыresponse.content. - В браузере данные есть, а в ответе их нет. Они подгружаются JavaScript. Ищите запрос к API во вкладке Network.
- Ответ 403 или пустая страница. Сайт отсекает запросы без заголовков. Добавьте
User-Agentи снизьте частоту запросов. - Парсер сломался через месяц. Сайт поменял верстку. Выносите селекторы в константы в начале файла, чтобы править их в одном месте.
Частые вопросы
Несколько вопросов, которые часто задают начинающие, и ответы на них.
Законно ли парсить сайты?
Сбор общедоступной информации сам по себе обычно не запрещен, но важны детали: пользовательское соглашение сайта, авторские права на контент, персональные данные. Учебные проекты на сайтах вроде books.toscrape.com безопасны. Для коммерческого сбора с чужих сайтов лучше заранее изучить их правила и использовать официальный API, если он есть.
Что выбрать: BeautifulSoup или lxml?
Для обучения и большинства задач берите BeautifulSoup с движком lxml: удобный API и хорошая скорость. Чистый lxml с XPath стоит использовать, когда страниц десятки тысяч и важна каждая миллисекунда или когда вы уже знаете XPath.
Как парсить сайты на JavaScript?
Сначала ищите внутренний API во вкладке Network браузера: чаще всего данные приходят в JSON, и их можно получить обычным requests. Если API закрыт, используйте браузерную автоматизацию (Playwright или Selenium), но она в десятки раз медленнее.
Как не получить блокировку?
Делайте паузу хотя бы в 1 секунду между запросами, используйте requests.Session, указывайте User-Agent, соблюдайте robots.txt и не запускайте десятки параллельных потоков на маленький сайт. Аккуратный парсер почти никогда не блокируют.