Scrapy: Полное руководство по веб-скрейпингу на русском языке

Введение в 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 выглядит следующим образом:

  1. Scheduler отправляет запрос в Downloader.
  2. Downloader загружает страницу и передает ее в Spider.
  3. Spider извлекает данные и создает Item.
  4. Item передается в Item Pipelines для обработки и сохранения.

Установка Scrapy и необходимые зависимости

Для установки Scrapy необходимо:

  1. Установить Python (версия 3.7 и выше).
  2. Установить pip (менеджер пакетов Python).
  3. Установить 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.

Полезные ресурсы и ссылки


Добавить комментарий