Архитектура пауков¶
Что нужно знать
- Прочитайте страницу Основы Fetcher, чтобы узнать о разных типах Fetcher и понять, когда их использовать.
- Прочитайте страницу Основные классы, чтобы познакомиться с классами Selector и Response.
Система пауков Scrapling представляет собой асинхронный фреймворк для обхода сайтов, вдохновлённый Scrapy. Она поддерживает одновременные запросы, несколько сессий, паузу и возобновление работы. Система объединяет парсер и Fetcher в общий API для обхода, а также добавляет планирование запросов, управление их одновременным выполнением и контрольные точки.
Если вы знакомы со Scrapy, многие приёмы будут привычны. Если нет, система всё равно проста в освоении.
Поток данных¶
На схеме показан путь данных в системе пауков во время обхода:

Вот что происходит при запуске паука, без лишних подробностей:
- Паук создаёт первую группу объектов
Request. По умолчанию для каждого URL вstart_urlsсоздаётся один запрос. Для своей логики можно переопределитьstart_requests(). - Планировщик принимает запросы, помещает их в очередь с приоритетами и создаёт их отпечатки. Запросы с более высоким приоритетом извлекаются первыми.
- Движок обхода просит планировщик выдать следующий запрос, соблюдая общие ограничения числа одновременных запросов, ограничения для каждого домена и задержки загрузки. Если включён
robots_txt_obey, движок сначала проверяет правила robots.txt домена. Запрещённые запросы отбрасываются без уведомления. Полученный запрос движок обхода передаёт менеджеру сессий, который выбирает сессию по полюsidзапроса (ID сессии). - Сессия загружает страницу и возвращает объект Response движку обхода. Движок собирает статистику и проверяет, не заблокирован ли ответ. При блокировке запрос повторяется до
max_blocked_retriesраз. Обнаружение блокировок и логику повторных попыток можно настроить. - Движок обхода передаёт Response обработчику запроса. Обработчик выдаёт либо словарь с извлечённой записью, либо следующий запрос, который передаётся планировщику и попадает в очередь.
- Цикл повторяется с шага 2, пока очередь не опустеет и не завершатся все задачи, либо пока паук не будет поставлен на паузу.
- Если при запуске задан
crawldir, движок обхода периодически сохраняет на диск контрольную точку: ожидающие запросы и множество уже встреченных URL. При корректной остановке (Ctrl+C) сохраняется последняя контрольная точка. При следующем запуске с тем жеcrawldirпаук продолжает работу с места остановки: пропускаетstart_requests()и восстанавливает состояние планировщика.
Компоненты¶
Spider¶
Основной класс, с которым вы работаете. Создайте подкласс Spider, задайте start_urls и метод parse(). При необходимости настройте сессии и переопределите хуки жизненного цикла.
from scrapling.spiders import Spider, Response, Request
class MySpider(Spider):
name = "my_spider"
start_urls = ["https://example.com"]
async def parse(self, response: Response):
for link in response.css("a::attr(href)").getall():
yield response.follow(link, callback=self.parse_page)
async def parse_page(self, response: Response):
yield {"title": response.css("h1::text").get("")}
Движок обхода¶
Движок управляет всем обходом: главным циклом, ограничениями одновременных запросов, отправкой запросов через менеджер сессий и обработкой результатов. Напрямую работать с ним не нужно. Это делают методы Spider.start() и Spider.stream().
Планировщик¶
Очередь с приоритетами и встроенным удалением повторных URL. Отпечаток запроса строится на основе URL, HTTP-метода, тела и ID сессии. Планировщик поддерживает snapshot() и restore() для системы контрольных точек, чтобы сохранять состояние обхода и возобновлять его.
Менеджер сессий¶
Управляет одним или несколькими именованными экземплярами сессий. Каждая сессия имеет один из типов:
При получении запроса менеджер выбирает сессию по полю sid. Сессии могут запускаться вместе с пауком (по умолчанию) или при первом использовании.
Система контрольных точек¶
Необязательная система, которая сохраняет состояние краулера в pickle-файл на диске: ожидающие запросы и отпечатки уже встреченных URL. Запись атомарная: сначала во временный файл, затем переименование. Это защищает от повреждения данных. Контрольные точки сохраняются с заданным интервалом и при корректной остановке. После успешного завершения обхода, а не паузы, файлы удаляются автоматически.
Кеш ответов¶
Необязательный кеш в режиме разработки. Он сохраняет каждый загруженный ответ на диск и использует его при следующих запусках. Ключом служит отпечаток запроса. Ответ сохраняется как JSON, а тело кодируется в base64 для сохранения двоичных данных. Кеш нужен для доработки parse() без повторных обращений к серверу, а не для рабочего обхода.
Результаты¶
Извлечённые записи собираются в ItemList: подкласс списка с методами экспорта to_json(), to_jsonl(), to_csv() и to_xml(). Статистика обхода хранится в dataclass CrawlStats и содержит много полезных данных.
Сравнение со Scrapy¶
Если вы переходите со Scrapy, эта таблица поможет сопоставить возможности:
| Понятие | Scrapy | Scrapling |
|---|---|---|
| Определение паука | Подкласс scrapy.Spider |
Подкласс scrapling.spiders.Spider |
| Начальные запросы | start_requests() |
async start_requests() |
| Обработчики | def parse(self, response) |
async def parse(self, response) |
| Переход по ссылкам | response.follow(url) |
response.follow(url) |
| Выдача записей | yield dict или yield Item |
yield dict |
| Планирование запросов | Scheduler + Dupefilter | Планировщик со встроенным удалением дубликатов |
| Загрузка | Downloader + Middlewares | Менеджер с поддержкой нескольких сессий |
| Обработка записей | Item Pipelines | Хук on_scraped_item() |
| Обнаружение блокировок | Через свои middleware | Встроенные хуки is_blocked() + retry_blocked_request() |
| Одновременные запросы | Настройка CONCURRENT_REQUESTS |
Атрибут класса concurrent_requests |
| Ограничение доменов | allowed_domains |
allowed_domains |
| Robots.txt | Настройка ROBOTSTXT_OBEY |
Атрибут класса robots_txt_obey |
| Пауза и возобновление | Настройка JOBDIR |
Аргумент конструктора crawldir |
| Экспорт | Feed exports | result.items.to_json() / to_jsonl() / to_csv() / to_xml() или свой экспорт через хуки |
| Запуск | scrapy crawl spider_name |
MySpider().start() |
| Потоковая выдача | Нет | async for item in spider.stream() |
| Несколько сессий | Нет | Несколько сессий разных типов в одном пауке |