Scrapy – это мощный и гибкий фреймворк Python, предназначенный для веб-скрапинга. Он позволяет эффективно извлекать структурированные данные из веб-сайтов. В этой статье мы подробно рассмотрим, как работает процесс краулера Scrapy, начиная с основ и заканчивая продвинутыми техниками.
Основы Scrapy и архитектура краулера
Что такое Scrapy и зачем он нужен: обзор фреймворка для веб-скрапинга
Scrapy – это не просто библиотека, а полноценный фреймворк, предоставляющий инструменты для всего цикла веб-скрапинга: от отправки запросов до хранения извлеченных данных. Он асинхронный, что позволяет ему обрабатывать множество запросов одновременно, обеспечивая высокую производительность. Scrapy полезен для:
-
Парсинга интернет-магазинов для сравнения цен.
-
Сбора данных для анализа рынков.
-
Автоматического извлечения информации из новостных сайтов.
-
Создания ботов для индексации веб-страниц.
Архитектура Scrapy: основные компоненты и их взаимодействие (движок, пауки, планировщик, загрузчики, конвейеры элементов, промежуточное ПО)
Архитектура Scrapy состоит из нескольких ключевых компонентов, работающих вместе для эффективного скрапинга:
-
Движок (Engine): Сердце Scrapy. Он управляет потоком данных между всеми компонентами.
-
Пауки (Spiders): Определяют, какие сайты парсить и как извлекать данные. Это основное место, где вы пишете свой код для скрапинга.
-
Планировщик (Scheduler): Определяет, какие URL-адреса следует посетить следующими.
-
Загрузчики (Downloader): Отвечают за загрузку веб-страниц с заданных URL-адресов.
-
Конвейеры элементов (Item Pipelines): Обрабатывают извлеченные данные (Items) после того, как они были спарсены пауками. Здесь можно очищать, проверять и сохранять данные.
-
Промежуточное ПО (Middleware): Предоставляет механизмы для обработки запросов и ответов. Существует промежуточное ПО для загрузчиков (Downloader Middleware) и пауков (Spider Middleware), позволяющее, к примеру, менять User-Agent или обрабатывать редиректы.
Взаимодействие компонентов:
-
Движок получает начальные URL-адреса от паука.
-
Движок передает URL-адреса планировщику.
-
Планировщик возвращает URL-адрес движку.
-
Движок отправляет запрос загрузчику через промежуточное ПО загрузчика.
-
Загрузчик загружает веб-страницу и возвращает ответ движку через промежуточное ПО загрузчика.
-
Движок отправляет ответ пауку для обработки через промежуточное ПО паука.
-
Паук парсит ответ и извлекает данные (Items) и новые URL-адреса.
-
Извлеченные данные отправляются в конвейеры элементов для обработки.
-
Новые URL-адреса отправляются планировщику.
Жизненный цикл запроса и ответа в Scrapy
Инициализация запроса пауком: создание и отправка URL-адресов
Процесс начинается с паука, который определяет начальные URL-адреса для скрапинга. Паук создает объекты scrapy.Request для каждого URL-адреса и передает их движку. Эти запросы могут содержать метаданные, колбэки (callback functions) для обработки ответа и другие параметры.
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['http://example.com/page1', 'http://example.com/page2']
def parse(self, response):
# Обработка ответа здесь
pass
Обработка ответа движком и передача пауку: извлечение данных и генерация новых запросов
Когда загрузчик получает ответ, он передает его движку, который, в свою очередь, отправляет его обратно пауку, вызвав указанную функцию обратного вызова (callback). Паук обрабатывает ответ, используя селекторы CSS или XPath для извлечения нужных данных. Извлеченные данные обычно представляются в виде объектов Item. Паук также может генерировать новые запросы для скрапинга других страниц.
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['http://example.com']
def parse(self, response):
# Извлечение заголовка страницы
title = response.css('title::text').get()
yield {'title': title}
# Создание нового запроса
next_page_url = response.css('a::attr(href)').get()
if next_page_url:
yield scrapy.Request(url=response.urljoin(next_page_url), callback=self.parse)
Практическое руководство: создание и настройка Scrapy-паука
Определение паука: имя, стартовые URL-адреса и правила парсинга
Чтобы создать паука, нужно определить класс, наследующийся от scrapy.Spider. В этом классе необходимо указать:
-
name: Уникальное имя паука. -
start_urls: Список URL-адресов, с которых начинается скрапинг. -
parse(self, response): Метод, который вызывается для обработки каждого ответа от веб-сервера.
Извлечение данных с помощью селекторов CSS и XPath: разбор HTML и XML
Scrapy предоставляет мощные селекторы, основанные на CSS и XPath, для извлечения данных из HTML и XML. CSS-селекторы проще в использовании для простых задач, в то время как XPath более гибок и подходит для сложных структур.
Пример использования CSS-селекторов:
title = response.css('h1.title::text').get()
price = response.css('.price::text').get()
Пример использования XPath-селекторов:
title = response.xpath('//h1[@class="title"]/text()').get()
price = response.xpath('//div[@class="price"]/text()').get()
Обработка и хранение данных: Item Pipeline и промежуточное ПО
Item Pipeline: очистка, проверка и сохранение извлеченных данных в базу данных или файл
Item Pipeline – это механизм для обработки извлеченных данных (Items) после того, как они были спарсены пауками. Он состоит из нескольких компонентов (pipeline processors), которые выполняются последовательно над каждым Item. Pipeline processors могут:
-
Очищать данные (например, удалять лишние пробелы).
-
Проверять данные (например, убедиться, что цена является числом).
-
Сохранять данные в базу данных или файл.
-
Отбрасывать Items, которые не соответствуют определенным критериям.
Пример Item Pipeline:
class PriceToFloatPipeline:
def process_item(self, item, spider):
if 'price' in item:
try:
item['price'] = float(item['price'].replace('$', ''))
except ValueError:
item['price'] = None
return item
class SaveToDatabasePipeline:
def __init__(self, db_uri):
self.db_uri = db_uri
@classmethod
def from_crawler(cls, crawler):
return cls(db_uri=crawler.settings.get('DATABASE_URI'))
def open_spider(self, spider):
self.connection = ... # Open database connection
def close_spider(self, spider):
self.connection.close()
def process_item(self, item, spider):
# Save item to database
return item
Промежуточное ПО (Middleware): обработка запросов и ответов, управление куками и user-agent
Промежуточное ПО (Middleware) позволяет вмешиваться в процесс обработки запросов и ответов. Существует два типа промежуточного ПО: промежуточное ПО загрузчика (Downloader Middleware) и промежуточное ПО паука (Spider Middleware).
-
Промежуточное ПО загрузчика позволяет:
-
Изменять User-Agent для предотвращения блокировки.
-
Управлять куками.
-
Обрабатывать прокси.
-
Перехватывать и изменять запросы и ответы.
-
-
Промежуточное ПО паука позволяет:
-
Обрабатывать исключения, возникающие при парсинге.
-
Изменять результаты парсинга.
-
Фильтровать элементы.
-
Пример промежуточного ПО для изменения User-Agent:
class RandomUserAgentMiddleware:
def process_request(self, request, spider):
ua = random.choice(USER_AGENT_LIST)
request.headers['User-Agent'] = ua
Заключение
Scrapy – это мощный инструмент для веб-скрапинга, предлагающий гибкую архитектуру и множество возможностей для обработки и хранения данных. Понимание основных компонентов и жизненного цикла запроса и ответа позволяет создавать эффективные и надежные краулеры для решения разнообразных задач парсинга данных. Изучайте документацию, экспериментируйте с различными подходами и создавайте собственные решения для веб-скрапинга!