Введение в Scrapy
Что такое веб-скрейпинг и зачем он нужен
Веб-скрейпинг — это автоматизированный процесс извлечения данных с веб-сайтов. Он позволяет собирать информацию в структурированном виде, что невозможно сделать вручную в разумные сроки. Веб-скрейпинг применяется для:
- Анализа рынка: сбор данных о ценах, характеристиках товаров.
- Мониторинга конкурентов: отслеживание изменений на сайтах конкурентов.
- Сбора новостей и информации: агрегация данных из различных источников.
- Исследований и анализа данных: создание баз данных для дальнейшей обработки.
Представьте, вам нужно собрать данные о 1000 товарах с разных интернет-магазинов, чтобы сравнить цены и характеристики. Вручную это займет недели, а с помощью веб-скрейпинга можно сделать за несколько часов.
Знакомство с фреймворком Scrapy: преимущества и особенности
Scrapy — это мощный и гибкий фреймворк для веб-скрейпинга на языке Python. Он предоставляет все необходимые инструменты для разработки сложных парсеров и обработки данных.
Преимущества Scrapy:
- Асинхронность: Scrapy использует асинхронную архитектуру, что позволяет ему обрабатывать множество запросов параллельно.
- Гибкость: Scrapy легко расширяется и настраивается под различные задачи.
- Поддержка XPath и CSS Selectors: Scrapy позволяет извлекать данные с помощью мощных и удобных селекторов.
- Item Pipelines: Scrapy предоставляет механизм для обработки и сохранения извлеченных данных.
- Middleware: Scrapy позволяет добавлять промежуточные слои для обработки запросов и ответов.
В отличие от простых библиотек для работы с HTTP-запросами (например, requests
), Scrapy предоставляет готовое решение для организации процесса сбора данных, включая обработку ошибок, управление concurrency и многое другое.
Архитектура Scrapy: компоненты и взаимодействие
Архитектура Scrapy состоит из нескольких основных компонентов, взаимодействующих между собой:
- Spiders: Определяют, как обходить сайт и извлекать данные.
- Item: Контейнер для хранения извлеченных данных.
- Item Pipelines: Обрабатывают и сохраняют данные из Item.
- Downloader Middlewares: Обрабатывают запросы перед отправкой и ответы после получения.
- Spider Middlewares: Обрабатывают данные между Spider и Downloader.
- Scheduler: Управляет очередью запросов.
Процесс работы Scrapy выглядит следующим образом:
- Scheduler отправляет запрос в Downloader.
- Downloader загружает страницу и передает ее в Spider.
- Spider извлекает данные и создает Item.
- Item передается в Item Pipelines для обработки и сохранения.
Установка Scrapy и необходимые зависимости
Для установки Scrapy необходимо:
- Установить Python (версия 3.7 и выше).
- Установить
pip
(менеджер пакетов Python). - Установить Scrapy с помощью команды:
pip install scrapy
Рекомендуется использовать виртуальное окружение для каждого проекта Scrapy, чтобы избежать конфликтов зависимостей. Создать виртуальное окружение можно с помощью команды: python -m venv venv
Активировать виртуальное окружение: source venv/bin/activate
(Linux/macOS) или venv\Scripts\activate
(Windows).
Создание первого Scrapy-проекта
Генерация проекта с помощью команды scrapy startproject
Для создания нового проекта Scrapy используется команда scrapy startproject <project_name>
. Например, для создания проекта my_scraper
необходимо выполнить команду:
scrapy startproject my_scraper
Эта команда создаст директорию my_scraper
со следующей структурой:
my_scraper/
scrapy.cfg # Файл конфигурации проекта
my_scraper/
__init__.py
items.py # Определение Item
middlewares.py # Middleware проекта
pipelines.py # Item Pipelines проекта
settings.py # Настройки проекта
spiders/
__init__.py
Структура проекта Scrapy: spiders, items, pipelines, settings
spiders
: Директория, содержащая файлы с определениями Spider.items.py
: Файл, содержащий определения Item (структуры данных для извлеченной информации).pipelines.py
: Файл, содержащий определения Item Pipelines (классов для обработки и сохранения данных).settings.py
: Файл, содержащий настройки проекта (User-Agent, concurrency, и т.д.).
Определение Item: структура данных для извлеченной информации
Item — это контейнер для хранения извлеченных данных. Он определяет структуру данных, которые будут извлечены с веб-сайта. Item описывается как класс, наследующийся от scrapy.Item
. Например, для хранения информации о товаре можно определить следующий Item:
import scrapy
class ProductItem(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field()
description = scrapy.Field()
url = scrapy.Field()
Создание первого Spider: определение логики сбора данных
Spider — это класс, определяющий логику сбора данных с веб-сайта. Он определяет, какие URL-адреса посещать, как извлекать данные и как обрабатывать результаты. Spider должен наследоваться от scrapy.Spider
и определять следующие методы:
name
: Уникальное имя Spider.start_urls
: Список URL-адресов, с которых начинается сбор данных.parse
: Метод, который вызывается для обработки ответа от сервера.
Пример простого Spider для извлечения заголовков страниц:
import scrapy
class TitleSpider(scrapy.Spider):
name = "title_spider"
start_urls = ['https://example.com', 'https://scrapy.org']
def parse(self, response):
yield {
'title': response.xpath('//title/text()').get(),
'url': response.url,
}
Запуск Spider и просмотр результатов
Для запуска Spider используется команда scrapy crawl <spider_name>
. Например, для запуска Spider title_spider
необходимо выполнить команду:
scrapy crawl title_spider
Результаты работы Spider будут выведены в консоль. Для сохранения результатов в файл можно использовать опцию -o <filename>
. Например, для сохранения результатов в файл titles.json
необходимо выполнить команду:
scrapy crawl title_spider -o titles.json
Извлечение данных с использованием Selectors
Обзор XPath и CSS Selectors: синтаксис и применение
Selectors используются для извлечения данных из HTML-документов. Scrapy поддерживает два типа селекторов: XPath и CSS Selectors.
- XPath: Язык запросов для выбора узлов в XML-документе. XPath позволяет выбирать элементы по их имени, атрибутам, содержимому и т.д.
- CSS Selectors: Язык запросов для выбора элементов в HTML-документе, основанный на CSS-синтаксисе.
Примеры XPath:
//title/text()
: Выбрать текст из элемента<title>
.//a/@href
: Выбрать атрибутhref
из всех элементов<a>
.//div[@class='product']/h2/text()
: Выбрать текст из элемента<h2>
, находящегося внутри элемента<div>
с классомproduct
.
Примеры CSS Selectors:
title::text
: Выбрать текст из элемента<title>
.a::attr(href)
: Выбрать атрибутhref
из всех элементов<a>
.div.product h2::text
: Выбрать текст из элемента<h2>
, находящегося внутри элемента<div>
с классомproduct
.
Использование Scrapy Shell для интерактивной отладки Selectors
Scrapy Shell — это интерактивная консоль, позволяющая тестировать XPath и CSS Selectors в реальном времени. Для запуска Scrapy Shell необходимо выполнить команду:
scrapy shell <url>
Например:
scrapy shell https://example.com
После запуска Scrapy Shell можно использовать переменные response
и selector
для доступа к содержимому страницы и тестирования селекторов. Например:
response.xpath('//title/text()').get()
response.css('title::text').get()
Извлечение текста, атрибутов и других данных
Для извлечения данных из элементов используются методы get()
и getall()
:
get()
: Возвращает первое найденное значение.getall()
: Возвращает список всех найденных значений.
Пример извлечения текста и атрибутов:
title = response.xpath('//title/text()').get()
href = response.xpath('//a/@href').getall()
Обработка относительных и абсолютных URL-адресов
При извлечении URL-адресов необходимо учитывать, что они могут быть относительными или абсолютными. Для преобразования относительных URL-адресов в абсолютные можно использовать метод response.urljoin()
:
relative_url = '/path/to/page'
absolute_url = response.urljoin(relative_url)
Примеры извлечения данных с различных веб-сайтов
Пример 1: Извлечение названия и цены товара с сайта интернет-магазина:
name = response.xpath('//h1[@class="product-title"]/text()').get()
price = response.xpath('//span[@class="price"]/text()').get()
Пример 2: Извлечение заголовков новостей с новостного сайта:
titles = response.xpath('//h2[@class="news-title"]/a/text()').getall()
Работа с Item Pipelines
Назначение Item Pipelines: очистка, проверка и сохранение данных
Item Pipelines используются для обработки и сохранения извлеченных данных. Они позволяют выполнять следующие операции:
- Очистка данных: Удаление лишних пробелов, приведение к нужному формату.
- Проверка данных: Проверка на соответствие заданным критериям.
- Сохранение данных: Сохранение в CSV, JSON, базу данных.
Создание собственного Item Pipeline
Item Pipeline — это класс, который должен реализовывать следующие методы:
process_item(self, item, spider)
: Обрабатывает Item и возвращает его или вызывает исключениеDropItem
для отбрасывания Item.open_spider(self, spider)
: Вызывается при запуске Spider.close_spider(self, spider)
: Вызывается при завершении Spider.
Пример Item Pipeline для очистки пробелов в названии товара:
from itemadapter import ItemAdapter
class CleanTextPipeline:
def process_item(self, item, spider):
adapter = ItemAdapter(item)
if 'name' in adapter.keys():
name = adapter['name']
adapter['name'] = name.strip()
return item
Примеры Item Pipelines: сохранение в CSV, JSON, базу данных
Пример 1: Сохранение в CSV:
import csv
class CSVPipeline:
def open_spider(self, spider):
self.csvfile = open('items.csv', 'w', newline='')
self.csvwriter = csv.writer(self.csvfile)
self.csvwriter.writerow(['name', 'price', 'url'])
def close_spider(self, spider):
self.csvfile.close()
def process_item(self, item, spider):
self.csvwriter.writerow([item['name'], item['price'], item['url']])
return item
Пример 2: Сохранение в JSON:
import json
class JsonPipeline:
def open_spider(self, spider):
self.jsonfile = open('items.json', 'w')
self.items = []
def close_spider(self, spider):
json.dump(self.items, self.jsonfile)
self.jsonfile.close()
def process_item(self, item, spider):
self.items.append(dict(item))
return item
Пример 3: Сохранение в базу данных (PostgreSQL):
import psycopg2
class PostgreSQLPipeline:
def __init__(self, postgres_uri, postgres_db, postgres_user, postgres_password):
self.postgres_uri = postgres_uri
self.postgres_db = postgres_db
self.postgres_user = postgres_user
self.postgres_password = postgres_password
@classmethod
def from_crawler(cls, crawler):
return cls(
postgres_uri=crawler.settings.get('POSTGRES_URI'),
postgres_db=crawler.settings.get('POSTGRES_DB'),
postgres_user=crawler.settings.get('POSTGRES_USER'),
postgres_password=crawler.settings.get('POSTGRES_PASSWORD')
)
def open_spider(self, spider):
self.conn = psycopg2.connect(host=self.postgres_uri, database=self.postgres_db, user=self.postgres_user, password=self.postgres_password)
self.cur = self.conn.cursor()
self.cur.execute("""
CREATE TABLE IF NOT EXISTS products (
name VARCHAR(255),
price VARCHAR(255),
url TEXT
)
""")
self.conn.commit()
def close_spider(self, spider):
self.cur.close()
self.conn.close()
def process_item(self, item, spider):
self.cur.execute("""
INSERT INTO products (name, price, url)
VALUES (%s, %s, %s)
""", (
item['name'],
item['price'],
item['url']
))
self.conn.commit()
return item
Обработка ошибок и исключений в Item Pipelines
В Item Pipelines можно обрабатывать ошибки и исключения. Например, можно отбрасывать Item, если он не соответствует заданным критериям, вызвав исключение DropItem
:
from scrapy.exceptions import DropItem
class PriceValidationPipeline:
def process_item(self, item, spider):
if float(item['price']) <= 0:
raise DropItem("Invalid price: %s" % item['price'])
return item
Активация Item Pipelines в настройках проекта
Для активации Item Pipelines необходимо добавить их в файл settings.py
:
ITEM_PIPELINES = {
'my_scraper.pipelines.CleanTextPipeline': 100,
'my_scraper.pipelines.CSVPipeline': 200,
}
Числа (100, 200) указывают порядок выполнения Item Pipelines.
Обработка ссылок и навигация по сайту
Использование Link Extractors для автоматического извлечения ссылок
Link Extractors используются для автоматического извлечения ссылок из HTML-документов. Scrapy предоставляет класс scrapy.linkextractors.LinkExtractor
для этой цели.
Пример использования Link Extractor:
from scrapy.linkextractors import LinkExtractor
le = LinkExtractor(allow=r'/product/') # Извлекать ссылки, содержащие '/product/'
links = le.extract_links(response)
for link in links:
print(link.url)
Правила (Rules) для управления переходом по страницам
Rules используются для автоматического перехода по страницам сайта. Они определяют, какие ссылки извлекать и как их обрабатывать. Rules определяются в Spider с помощью класса scrapy.spiders.Rule
.
Пример использования Rules:
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
class MySpider(CrawlSpider):
name = 'my_spider'
start_urls = ['https://example.com']
rules = (
Rule(LinkExtractor(allow=r'/product/'), callback='parse_item'),
Rule(LinkExtractor(allow=r'/category/')), # Просто переходить по ссылкам
)
def parse_item(self, response):
# Обработка страницы товара
yield {
'name': response.xpath('//h1[@class="product-title"]/text()').get(),
}
Обработка пагинации и переходов между страницами
Для обработки пагинации можно использовать Link Extractors и Rules или вручную формировать URL-адреса для следующих страниц. Например:
next_page = response.xpath('//a[@class="next-page"]/@href').get()
if next_page:
yield scrapy.Request(response.urljoin(next_page), callback=self.parse)
Реализация обхода сайта с ограничением глубины
Для ограничения глубины обхода сайта можно использовать параметр depth_limit
в настройках Spider:
class MySpider(CrawlSpider):
name = 'my_spider'
start_urls = ['https://example.com']
custom_settings = {
'DEPTH_LIMIT': 2,
}
Использование FormRequest для работы с формами
Заполнение и отправка форм с помощью Scrapy
Для работы с формами в Scrapy используется класс scrapy.FormRequest
. Он позволяет заполнять и отправлять формы с помощью HTTP-запросов.
Пример заполнения и отправки формы:
from scrapy.http import FormRequest
class FormSpider(scrapy.Spider):
name = 'form_spider'
start_urls = ['https://example.com/login']
def parse(self, response):
# Извлекаем токен CSRF, если он есть
csrf_token = response.xpath('//input[@name="csrf_token"]/@value').get()
yield FormRequest.from_response(
response,
formdata={
'username': 'my_username',
'password': 'my_password',
'csrf_token': csrf_token, # Если есть
},
callback=self.after_login
)
def after_login(self, response):
# Обработка страницы после авторизации
if "Welcome" in response.text:
yield {
'message': "Login successful!"
}
Авторизация на веб-сайтах
Авторизация на веб-сайтах выполняется с помощью отправки POST-запроса с данными для входа (логин, пароль). Необходимо также учитывать защиту от CSRF-атак и передавать соответствующие токены.
Обработка CAPTCHA (обзор)
Обработка CAPTCHA является сложной задачей и требует использования сторонних сервисов распознавания CAPTCHA (например, 2Captcha, Anti-Captcha). Scrapy не предоставляет встроенных средств для обработки CAPTCHA.
Настройки Scrapy и управление проектом
Основные параметры в файле settings.py
Файл settings.py
содержит основные настройки проекта Scrapy. Важные параметры:
BOT_NAME
: Имя бота.ROBOTSTXT_OBEY
: Учитывать правилаrobots.txt
.DEFAULT_REQUEST_HEADERS
: Заголовки HTTP-запросов по умолчанию.SPIDER_MIDDLEWARES
: Список Spider Middlewares.DOWNLOADER_MIDDLEWARES
: Список Downloader Middlewares.ITEM_PIPELINES
: Список Item Pipelines.DOWNLOAD_DELAY
: Задержка между запросами (в секундах).CONCURRENT_REQUESTS
: Максимальное количество параллельных запросов.
Управление concurrency и throttling: ROBOTSTXTOBEY, DOWNLOADDELAY
Для управления concurrency и throttling используются параметры CONCURRENT_REQUESTS
и DOWNLOAD_DELAY
. Параметр ROBOTSTXT_OBEY
определяет, учитывать ли правила, указанные в файле robots.txt
.
Пример:
ROBOTSTXT_OBEY = True
DOWNLOAD_DELAY = 0.25 # 250ms задержка
CONCURRENT_REQUESTS = 16
Использование User-Agent для маскировки
Для маскировки бота рекомендуется использовать User-Agent, имитирующий браузер. Список User-Agent можно найти в интернете. Пример:
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
Настройка логирования и отладки
Scrapy предоставляет встроенную систему логирования. Уровень логирования можно настроить с помощью параметра LOG_LEVEL
:
LOG_LEVEL = 'INFO'
Возможные уровни логирования: DEBUG
, INFO
, WARNING
, ERROR
, CRITICAL
.
Развертывание Scrapy-проекта на Scrapinghub (обзор)
Scrapinghub — это облачная платформа для развертывания и запуска Scrapy-проектов. Она предоставляет удобный интерфейс для управления проектами, мониторинга и масштабирования.
Продвинутые техники веб-скрейпинга
Использование прокси-серверов для обхода блокировок
Для обхода блокировок можно использовать прокси-серверы. Scrapy поддерживает использование прокси-серверов с помощью Downloader Middlewares.
Пример Downloader Middleware для использования прокси-серверов:
class ProxyMiddleware:
def process_request(self, request, spider):
request.meta['proxy'] = 'http://user:password@host:port'
Работа с AJAX-запросами и динамическим контентом
Для работы с AJAX-запросами и динамическим контентом необходимо использовать инструменты, способные выполнять JavaScript-код (например, Selenium или Splash).
Интеграция с Selenium для рендеринга JavaScript
Selenium — это инструмент для автоматизации браузера. Он позволяет запускать браузер в автоматическом режиме и выполнять JavaScript-код. Интеграция с Selenium позволяет Scrapy извлекать данные с сайтов, использующих AJAX и динамический контент.
Пример использования Selenium в Scrapy:
from scrapy import Spider
from selenium import webdriver
class SeleniumSpider(Spider):
name = 'selenium_spider'
start_urls = ['https://example.com']
def __init__(self):
self.driver = webdriver.Chrome() # Или другой браузер
def parse(self, response):
self.driver.get(response.url)
# Извлекаем данные с помощью Selenium
title = self.driver.find_element_by_xpath('//title').text
yield {
'title': title,
}
Обработка cookies и сессий
Scrapy автоматически обрабатывает cookies и сессии. Для управления cookies можно использовать Downloader Middlewares.
Борьба с anti-scraping мерами (обзор)
Для борьбы с anti-scraping мерами можно использовать следующие техники:
- Использование прокси-серверов.
- Изменение User-Agent.
- Установка задержки между запросами.
- Использование CAPTCHA-решателей.
- Имитация поведения пользователя (случайные переходы по сайту, скроллинг страниц и т.д.).
Примеры проектов на Scrapy
Сбор данных о товарах из интернет-магазина
Этот проект предполагает извлечение информации о товарах (название, цена, описание, характеристики) с сайта интернет-магазина.
Парсинг новостей с новостного сайта
Этот проект предполагает извлечение заголовков новостей, текста статей и другой информации с новостного сайта.
Сбор информации о вакансиях с сайта поиска работы
Этот проект предполагает извлечение информации о вакансиях (название, описание, требования, зарплата) с сайта поиска работы.
Мониторинг цен конкурентов
Этот проект предполагает отслеживание цен на товары у конкурентов и сохранение данных в базу данных для дальнейшего анализа.
Заключение
Перспективы развития веб-скрейпинга
Веб-скрейпинг продолжает развиваться, появляются новые инструменты и техники для извлечения данных с веб-сайтов. Веб-скрейпинг становится все более важным инструментом для бизнеса и науки.
Рекомендации по дальнейшему изучению Scrapy
Для дальнейшего изучения Scrapy рекомендуется:
- Изучить документацию Scrapy.
- Реализовать несколько проектов на Scrapy.
- Изучить продвинутые техники веб-скрейпинга.
- Присоединиться к сообществу Scrapy.