Веб-скрэйпинг

Бизюк Андрей

ВГТУ

2024-12-03

Веб-скраппинг

Веб-скрапинг (web scraping) — это процесс автоматизированного извлечения данных с веб-сайтов. Этот метод позволяет собирать информацию с веб-страниц и сохранять её в удобном для анализа формате (например, в виде таблицы или базы данных). Веб-скрапинг используется в самых разных задачах, от сбора цен для сравнения товаров до мониторинга новостных сайтов и социальных сетей.

Основные этапы веб-скрапинга:

  1. Отправка HTTP-запроса: Для получения содержимого веб-страницы используется HTTP-запрос, который посылает ваша программа (скрапер) на сервер.

  2. Парсинг HTML: После получения содержимого страницы (HTML-кода) необходимо извлечь из него нужную информацию. Это делается с помощью инструментов для парсинга (например, BeautifulSoup, lxml или встроенные средства Python).

  3. Извлечение данных: Из HTML-кода страницы извлекаются определенные данные, такие как текст, изображения, ссылки и т.д.

  4. Сохранение данных: Извлеченные данные можно сохранить в разных форматах — текстовые файлы, CSV, базы данных, JSON и другие.

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

  1. BeautifulSoup: Библиотека Python для парсинга HTML и XML документов. Она создает дерево синтаксического разбора, которое упрощает навигацию и поиск данных.

    from bs4 import BeautifulSoup
    import requests
    
    url = 'https://example.com'
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # Извлечение данных
    title = soup.find('h1').get_text()
    print(title)
  2. Scrapy: Фреймворк для более сложных задач веб-скрапинга. Он позволяет не только извлекать данные, но и следовать по ссылкам и собирать информацию со многих страниц сайта.

  3. Selenium: Используется для скрапинга динамических страниц, которые загружают контент с помощью JavaScript. Selenium позволяет эмулировать браузер и взаимодействовать с элементами страницы.

    from selenium import webdriver
    
    url = 'https://example.com'
    driver = webdriver.Chrome()  # Или используйте другой браузерный драйвер
    driver.get(url)
    
    # Извлечение данных
    title = driver.find_element_by_tag_name('h1').text
    print(title)
    
    driver.quit()
  4. Puppeteer: Инструмент на JavaScript для управления браузером Chrome или Chromium. Подходит для более сложного скрапинга и тестирования веб-приложений.

Важные аспекты веб-скрапинга:

  • Этические и правовые вопросы: Перед тем как начать скрапинг, обязательно ознакомьтесь с robots.txt сайта и его политикой использования данных. В некоторых случаях веб-скрапинг может быть запрещен или ограничен условиями использования сайта.

  • Ограничение частоты запросов: Чтобы не перегружать сервер сайта, рекомендуется устанавливать задержку между запросами (time.sleep()) и ограничивать количество одновременных запросов.

  • Защита от блокировок: Некоторые сайты могут блокировать скраперы, поэтому может понадобиться использование прокси-серверов или ротация User-Agent.

Пример простого скрапера с использованием BeautifulSoup:

import requests
from bs4 import BeautifulSoup

url = 'https://example.com'
response = requests.get(url)

soup = BeautifulSoup(response.text, 'html.parser')

# Извлекаем заголовки статей
for title in soup.find_all('h2'):
    print(title.get_text())

Этот код отправляет запрос на сайт, парсит его содержимое и выводит заголовки всех статей на странице.

Использование Scrapy

Scrapy — это мощный и широко используемый фреймворк для веб-скрапинга на Python. Он позволяет извлекать данные с веб-сайтов и обрабатывать их по вашему усмотрению. Вот краткое руководство по настройке и использованию Scrapy для создания базового веб-скрейпера.

1. Установка Scrapy

Сначала убедитесь, что у вас установлен Python. Затем установите Scrapy с помощью pip:

pip install scrapy

2. Создание нового проекта Scrapy

Чтобы начать новый проект Scrapy, перейдите в каталог, где хотите создать проект, и выполните команду:

scrapy startproject myproject

Эта команда создаст новый каталог myproject со следующей структурой:

myproject/
    scrapy.cfg            # Конфигурационный файл
    myproject/            # Модуль Python для вашего проекта
        __init__.py
        items.py          # Определение структур данных
        middlewares.py    # Пользовательские миддлвары (опционально)
        pipelines.py      # Пост-обработка данных
        settings.py       # Настройки проекта
        spiders/          # Каталог для модулей пауков
            __init__.py

3. Создание паука

Паук (spider) — это класс, который определяет, как переходить по ссылкам на веб-сайте и извлекать данные. Внутри каталога spiders создайте новый файл, например, my_spider.py:

import scrapy

class MySpider(scrapy.Spider):
    name = "myspider"
    start_urls = [
        'https://example.com',  # Замените на сайт, который хотите скрапить
    ]

    def parse(self, response):
        # Извлечение данных с страницы и передача их в виде словаря
        for item in response.css('div.item'):  # Замените 'div.item' на нужный CSS-селектор
            yield {
                'title': item.css('h2::text').get(),
                'link': item.css('a::attr(href)').get(),
            }

        # Переход по ссылкам пагинации, если они есть
        next_page = response.css('a.next::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

4. Запуск паука

Чтобы запустить вашего паука, используйте команду scrapy crawl:

scrapy crawl myspider

Эта команда запустит паука, и он начнет скрапить данные в соответствии с вашими настройками.

5. Экспорт данных

Вы также можете экспортировать собранные данные в файл (например, JSON или CSV), выполнив команду:

scrapy crawl myspider -o output.json

Это сохранит собранные данные в файл с именем output.json.

6. Настройка и расширение

Вы можете дополнительно настроить своего паука, добавив больше логики для парсинга, обработав разные типы страниц или используя миддлвары, пайплайны и настройки Scrapy.

Пример: Настройка Scrapy

Вы можете настроить параметры проекта в файле settings.py. Например, для изменения User-Agent и задержки между запросами:

# settings.py

# Задайте User-Agent для идентификации вашего паука на сайте
USER_AGENT = 'myspider (+http://www.example.com)'

# Задержка между запросами (в секундах)
DOWNLOAD_DELAY = 2

# Максимальное количество одновременных запросов (по умолчанию: 16)
CONCURRENT_REQUESTS = 8

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

Утилиты командной строки

Scrapy предоставляет несколько полезных утилит командной строки, которые позволяют управлять проектами, запускать пауков, отлаживать и тестировать код, а также взаимодействовать с фреймворком. Вот основные команды и их использование:

1. Создание проекта

scrapy startproject <имя_проекта>

Эта команда создаёт новый Scrapy проект с заданным именем.

2. Запуск паука

scrapy crawl <имя_паука>

Запускает паука, который определён в вашем проекте. Например, если паук называется myspider, то команда будет:

scrapy crawl myspider

3. Отладка и тестирование (shell)

scrapy shell <URL>

Запускает интерактивную оболочку (shell) Scrapy, где вы можете выполнить запрос к URL и вручную исследовать и парсить HTML-код страницы. Это полезно для тестирования селекторов перед внедрением их в паука.

4. Создание паука

scrapy genspider <имя_паука> <домен>

Эта команда генерирует шаблон паука, который будет настроен для работы с указанным доменом. Например:

scrapy genspider myspider example.com

Создаст паука с именем myspider, настроенного на example.com.

5. Вывод результатов в файл

scrapy crawl <имя_паука> -o <имя_файла>

Запускает паука и сохраняет результаты в указанный файл. Поддерживаются форматы JSON, CSV, XML. Например:

scrapy crawl myspider -o output.json

Сохранит результаты в файл output.json.

6. Просмотр списка пауков

scrapy list

Выводит список всех пауков, которые доступны в вашем проекте.

7. Просмотр документации для команды

scrapy <команда> --help

Выводит подробную информацию и список опций для указанной команды. Например:

scrapy crawl --help

8. Запуск пауков по расписанию

Используя опцию schedule, можно запускать пауков по расписанию. Для этого можно использовать внешние планировщики (например, cron на Unix-подобных системах) или сторонние инструменты, такие как scrapy-crawlera для управления запросами.

9. Логирование и дебаг

Scrapy поддерживает различные уровни логирования (DEBUG, INFO, WARNING, ERROR, CRITICAL). Чтобы изменить уровень логирования:

scrapy crawl myspider --loglevel=INFO

Выводит только информационные сообщения и выше (ошибки, критические).

10. Обратная сборка страницы

scrapy fetch <URL>

Команда делает запрос к указанному URL и возвращает HTML-код страницы. Полезно для отладки.

11. Обратный вызов селектора

scrapy view <URL>

Эта команда делает запрос к указанному URL, сохраняет его в файл и открывает его в браузере.

12. Просмотр настроек

scrapy settings --get <имя_настройки>

Выводит значение конкретной настройки. Например:

scrapy settings --get USER_AGENT

13. Тестирование XPath и CSS селекторов

scrapy shell <URL>

Запустите scrapy shell, чтобы протестировать ваши селекторы (XPath или CSS) в интерактивной оболочке.

14. Деплой проекта

С помощью команды scrapy deploy можно загружать проект на сервер или облачную платформу (например, Scrapy Cloud). Обычно эта команда требует дополнительной настройки и используется с платформами, такими как Scrapyd.

Эти команды помогают эффективно управлять проектами Scrapy, тестировать и отлаживать код, а также сохранять и анализировать результаты веб-скрапинга.

Пауки

В Scrapy пауки (spiders) являются основными компонентами, которые занимаются сбором информации с веб-сайтов. Пауки определяют, какие страницы нужно загружать, как извлекать данные и как следовать по ссылкам для перехода на другие страницы.

Основные элементы паука:

  1. Класс паука Пауки в Scrapy определяются как подклассы scrapy.Spider. Это базовый класс, который включает все необходимые методы и атрибуты для работы с сайтами.

  2. Имя паука (name) Каждому пауку присваивается уникальное имя. Это имя используется для вызова паука командой scrapy crawl <имя_паука>.

  3. Начальные URL (start_urls) Это список URL, с которых паук начнет сканирование. Например:

    start_urls = [
        'https://example.com',
    ]
  4. Метод parse Основной метод паука. Он вызывается при получении ответа от каждого URL из start_urls. Этот метод занимается парсингом страницы и извлечением данных.

    def parse(self, response):
        # Логика извлечения данных

Пример простого паука

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }
        
        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

В этом примере паук QuotesSpider:

  • Начинает с URL http://quotes.toscrape.com/page/1/.
  • Извлекает цитаты, авторов и теги с каждой страницы.
  • Переходит на следующую страницу, пока они доступны.

Типы пауков в Scrapy

  1. Generic Spider (Основной паук) Это наиболее распространенный тип паука, который может быть настроен для работы с различными структурами сайтов. Пример выше — это пример основного паука.

  2. CrawlSpider Это более мощный тип паука, который используется для сканирования сайтов с большим количеством страниц и сложной навигацией. Он использует правила (rules) для автоматического следования по ссылкам.

    Пример CrawlSpider:

    from scrapy.spiders import CrawlSpider, Rule
    from scrapy.linkextractors import LinkExtractor
    
    class MyCrawlSpider(CrawlSpider):
        name = "my_crawl_spider"
        start_urls = ['http://example.com']
    
        rules = (
            Rule(LinkExtractor(allow=('category\.php', )), callback='parse_item', follow=True),
        )
    
        def parse_item(self, response):
            self.logger.info('Parsing item page: %s', response.url)
            item = {
                'title': response.css('title::text').get(),
                'link': response.url,
            }
            return item

    В этом примере CrawlSpider автоматически переходит по ссылкам, соответствующим шаблону category.php, и использует метод parse_item для обработки этих страниц.

  3. XMLFeedSpider Этот паук используется для обработки XML-фидов (каналов), таких как RSS или Atom.

    from scrapy.spiders import XMLFeedSpider
    
    class MyXMLFeedSpider(XMLFeedSpider):
        name = 'xmlfeed'
        start_urls = ['http://example.com/feed.xml']
        iterator = 'iternodes'  # Можно использовать 'iter' для построчной итерации
        itertag = 'item'  # Тег XML, который содержит элемент
    
        def parse_node(self, response, node):
            item = {
                'title': node.xpath('title/text()').get(),
                'link': node.xpath('link/text()').get(),
            }
            return item
  4. CSVFeedSpider Этот паук предназначен для работы с CSV-файлами.

    from scrapy.spiders import CSVFeedSpider
    
    class MyCSVFeedSpider(CSVFeedSpider):
        name = 'csvfeed'
        start_urls = ['http://example.com/feed.csv']
        headers = ['id', 'name', 'description']
    
        def parse_row(self, response, row):
            item = {
                'id': row['id'],
                'name': row['name'],
                'description': row['description'],
            }
            return item

Полезные методы и атрибуты

  • response.css() / response.xpath(): Методы для выборки элементов страницы с помощью CSS или XPath селекторов.

  • yield: Используется для возврата извлеченных данных или для передачи следующего запроса (например, для перехода по ссылке).

  • scrapy.Request: Можно использовать для выполнения запросов вручную внутри метода parse или других методов.

  • follow: Метод для следования по ссылке и обработки следующей страницы.

Советы и рекомендации

  • Обработка ошибок: Используйте логирование и обработку исключений для обработки ошибок на этапах парсинга или запроса.

  • Ограничение скорости: Чтобы избежать блокировки сайта, используйте задержки (DOWNLOAD_DELAY) между запросами и установите лимиты на количество одновременных запросов (CONCURRENT_REQUESTS).

  • Cookies и сессии: Scrapy поддерживает использование cookies, что может быть полезно при работе с сайтами, требующими авторизацию.

Селекторы

Селекторы в Scrapy используются для извлечения данных из HTML-документов, которые паук загружает с веб-страниц. В Scrapy можно использовать два типа селекторов: XPath и CSS-селекторы. Оба инструмента позволяют выбирать элементы из HTML-кода страницы и извлекать нужную информацию.

1. CSS-селекторы

CSS-селекторы — это мощный и удобный способ выбирать элементы из HTML по их тегам, классам, идентификаторам и другим атрибутам.

Примеры использования CSS-селекторов:

response.css('title::text').get()
  • title — выбирает тег <title>.
  • ::text — выбирает текстовое содержимое тега.
  • get() — извлекает первое совпадение (вернет текст заголовка страницы).
response.css('h1::text').getall()
  • getall() — извлекает все совпадения (например, все заголовки первого уровня).
response.css('div.content p::text').get()
  • div.content p — выбирает все <p> элементы внутри <div> с классом content.
response.css('a::attr(href)').get()
  • a::attr(href) — извлекает значение атрибута href у всех ссылок <a>.
response.css('img::attr(src)').getall()
  • Извлекает значения атрибута src для всех изображений на странице.

2. XPath-селекторы

XPath — это язык запросов, который позволяет более точно выбирать элементы, особенно если нужно выбрать элементы на основе их структуры, а не стилей.

Примеры использования XPath-селекторов:

response.xpath('//title/text()').get()
  • //title/text() — выбирает текст внутри тега <title>.
response.xpath('//h1/text()').getall()
  • Извлекает текст всех тегов <h1>.
response.xpath('//div[@class="content"]/p/text()').get()
  • //div[@class="content"]/p/text() — выбирает текст всех <p> элементов, находящихся внутри <div> с классом content.
response.xpath('//a/@href').getall()
  • Извлекает значения атрибута href у всех ссылок <a>.
response.xpath('//img/@src').getall()
  • Извлекает значения атрибута src для всех изображений на странице.

3. Методы Scrapy для работы с селекторами

  • .get(): Возвращает первое совпадение с запросом.

    title = response.css('title::text').get()
  • .getall(): Возвращает все совпадения с запросом в виде списка.

    all_links = response.xpath('//a/@href').getall()
  • .extract(): Альтернативный метод для получения данных. Работает аналогично .getall(), но используется чаще в старых версиях Scrapy.

    titles = response.css('h1::text').extract()
  • .re(): Позволяет использовать регулярные выражения для фильтрации данных.

    prices = response.css('span.price::text').re(r'\d+\.\d+')

    В этом примере извлекаются цены, представляющие собой числа с десятичной точкой.

  • .re_first(): Возвращает первое совпадение с регулярным выражением.

    first_price = response.css('span.price::text').re_first(r'\d+\.\d+')

4. Комбинирование CSS и XPath

Scrapy позволяет использовать как CSS, так и XPath в одном пауке в зависимости от потребностей. Иногда XPath может быть полезнее для сложных структур, а CSS — для более простых и понятных запросов.

5. Примеры использования селекторов в методе parse

Пример использования CSS-селекторов для извлечения данных о книгах с веб-страницы:

import scrapy

class BooksSpider(scrapy.Spider):
    name = 'books'
    start_urls = ['http://books.toscrape.com/']

    def parse(self, response):
        for book in response.css('article.product_pod'):
            yield {
                'title': book.css('h3 a::attr(title)').get(),
                'price': book.css('p.price_color::text').get(),
            }
        
        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

Пример использования XPath-селекторов для того же сайта:

import scrapy

class BooksSpider(scrapy.Spider):
    name = 'books'
    start_urls = ['http://books.toscrape.com/']

    def parse(self, response):
        for book in response.xpath('//article[@class="product_pod"]'):
            yield {
                'title': book.xpath('.//h3/a/@title').get(),
                'price': book.xpath('.//p[@class="price_color"]/text()').get(),
            }
        
        next_page = response.xpath('//li[@class="next"]/a/@href').get()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

6. Советы по выбору селекторов

  • Используйте CSS для простых запросов: Если можно обойтись без сложных запросов, используйте CSS-селекторы — они короче и легче читаются.

  • Используйте XPath для сложных структур: XPath предоставляет больше возможностей для работы со сложными структурами и условиями, например, выбор элемента на основе его позиции в структуре документа.

  • Тестируйте селекторы в Scrapy Shell: Прежде чем интегрировать селекторы в код паука, тестируйте их в интерактивной оболочке Scrapy (scrapy shell <URL>).

Сохранение данных