Scrapy — Простой скрапинг сайтов

Scrapy на примерах

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

  • Многопоточность;
  • Веб-краулер для перехода от ссылке к ссылки;
  • Извлечение данных;
  • Проверка данных;
  • Сохранение в другой формат/базу данных;
  • Многое другое.

Главное отличие между Scrapy и другими популярными библиотеками, такими как Requests или BeautifulSoup, заключается в том, что он позволяет решать обычные задачи веб скрапинга при помощи самых элегантных методов.

К недостаткам Scrapy можно отнести и тот факт, что начать ему обучаться бывает довольно сложно. Но мы ведь для этого здесь и собрались :)

В данном руководстве мы создадим два веб скрапера. Один будет простым, его задачей станет извлечение данных со страницы продукта онлайн магазина. Второй будет несколько сложнее. Его назначением будет скрапинг целого каталога сайта онлайн магазина.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Обзор основ работы со Scrapy

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

Я использую Virtualenv и Virtualenvwrapper:

После активации виртуальной среды, у вас в терминале должен изменится ввод команд. Например:

Теперь у вас изолированная среда разработки, можете установить в ней нужные пакеты:

Теперь можно создать cкрапи проект с помощью этой команды:

Это создаст все необходимые файлы для проекта:

Далее представлено краткое описание файлов и папок:

  • items.py является моделью для извлеченных данных. Вы можете определить настраиваемую модель (например Product), что унаследует класс Item.
  • middlewares.py Middleware используется для изменения жизненного цикла запросов и ответов. Например, вы можете создать промежуточное программное обеспечение для ротации пользовательских агентов или использовать API вроде ScrapingBee вместо того, чтобы выполнять запросы самостоятельно.
  • pipelines.py В скрапи, пайплайны, или конвейеры используются для обработки извлеченных данных, очистки HTML, проверки данных, их экспорта в пользовательский формат или сохранения в базе данных.
  • /spiders является папкой, содержащей классы Spider. В Scrapy Spider являются классом, которые определяют, как должен быть проведен скрапинг сайта, в том числе по какой ссылке следовать и как извлечь данные для этих ссылок.
  • scrapy.cfg является файлом конфигурации для изменения некоторых настроек.

Скрапинг продуктов из интернет магазина на Python

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

Товар онлайн магазина

Мы извлечем название продукта, изображение, цену и описание.

Оболочка Scrapy Shell в командной строке

Scrapy поставляется со встроенной оболочкой, что помогает отладить код скрапинга в режиме реального времени. С ним можно быстро протестировать XPath-выражения или CSS селекторы. Это очень крутой инструмент для написания веб скраперов, и я всегда им пользуюсь!

Можно настроить Scrapy Shell на использование другой консоли вместо стандартной консоли Python как IPython. У вас появится возможность автозаполнения и другие приятные бонусы вроде цветного вывода.

Для его использования в оболочке Scrapy Shell нужно добавить следующую строку в файл scrapy.cfg:

После завершения конфигурации можно использовать оболочку Scrapy:

Можно начать выборку URL следующим простым действием:

Она начнется с загрузки файла /robot.txt

В данном случае нет никакого robot.txt, поэтому мы получаем 404 HTTP код. Если бы у нас был файл robot.txt, по умолчанию Scrapy придерживался бы правил.

Можно отключить такое поведение, изменив boolean параметр в settings.py:

После этого у вас должен появится лог подобного рода:

Теперь можно увидеть объект ответа, заголовки ответа и попробовать различные XPath выражения и CSS селекторы, чтобы извлечь нужные данные.

Увидеть ответ прямо в браузере, можно использовав данную функцию:

Обратите внимание, что страница будет плохо отображаться в браузере по многим причинам. Это могут быть проблемы с CORS, не выполненный Javascript код или относительные URL для ресурсов, которые не будут работать локально.

Оболочка Scrapy похожа на обычную оболочку Python, поэтому не бойтесь загружать в нее свои любимые скрипты или функции.

Извлечение данных с сайта через Scrapy

Scrapy по умолчанию не выполняет Javascript код. По этой причине при попытке сделать скрапинг на сайте, что использует Javascript-фреймворки вроде Angular или React.js, у вас могут возникнуть проблемы с получением доступа к запрашиваемым данным.

Попробуем использовать некоторые XPath выражения для извлечения названия и цены продукта:

XPath Scrapping

Для извлечения цены мы используем выражение XPath, выберем первый span после div с классом my-4

Я мог также использовать следующий CSS селектор:

Создаем Scrapy Spider

В Scrapy, Spider является классом, где определяется поведение при анализе (какие ссылки или URL должны пройти через скрапинг) и при скрапинге (что нужно извлечь).

Предусмотрено несколько этапов, которые Spider использует для скрапинга вебсайта:

  • Все начинается с просмотра атрибута класса start_urls и вызова этих URL-адресов с помощью метода start_requests(). Вы можете переопределить этот метод, если нужно изменить HTTP verb, добавить некоторые параметры в запрос (например, отправив запрос POST вместо GET).
  • Затем генерируется объект Request для каждого URL и отправляется ответ в функцию обратного вызова parse().
  • Затем метод parse() извлекает данные (в нашем случае — цену продукта, изображение, описание, заголовок) и возвращает либо словарь, объект Item, запрос или итерацию.

Может показаться удивительным, что метод parse может возвращать так много разных объектов. Это сделано для гибкости. Допустим, вы хотите сделать скрапинг онлайн магазина, на котором нет карты сайта. Вы можете начать со скрапинга товарных категорий, это будет первый метод парсинга.

Данный метод затем передает объект Request для каждой категории продуктов новому методу обратного вызова parse2(). Для каждой категории нужно обрабатывать нумерацию страниц. Затем для каждого продукта производится фактический скрапинг, что генерирует элемент и третью функцию parse.

С Scrapy можно возвращать данные скрапинга в виде простого словаря Python, но рекомендуется использовать встроенный класс Scrapy Item. Это простой контейнер для данных скрапинга. Scrapy будет просматривать его поля для экспорта данных в различные форматы (JSON / CSV…), источника элемента и многого другого.

Далее показан базовый класс Product:

Теперь можно сгенерировать Spider при помощи командной строки:

Также это можно сделать вручную, поместив код Spider внутри папки /spiders.

В Scrapy есть разные типы Spider, предназначенные для решения самых частых случаев веб-скрапинга:

  • Spider, который мы будем использовать, принимает список start_urls и скрапит каждый элемент через метод parse.
  • CrawlSpider переходит по ссылкам, которые соответствуют определенным набором правил.
  • SitemapSpider извлекается URL, определенные в карте сайта.
  • Многие другие.

В данном классе EcomSpider есть два запрашиваемых атрибута:

  • name, что является названием Spider (можно запустить при использовании scrapy runspider spider_name)
  • start_urls, что является начальным URL

Атрибут allow_domains необязателен, но важен, когда вы используете CrawlSpider, который может переходить по ссылкам в разных доменах.

Затем поля Product просто заполняются при помощи выражений XPath для извлечения нужных данных, и возвращается элемент.

Чтобы экспортировать результат в JSON (его также можете экспортировать в CSV), можно запустить код следующим образом:

После этого вы должны получить требуемый файл JSON:

Во время извлечения данных с веб страницы вы можете столкнуться со следующими проблемами:

  • На одном и том же сайте лейаут страницы и основной HTML могут отличаться. При скрапинге онлайн магазина вам часто будет встречаться стандартная цена и цена после скидки, у которых разные XPath и CSS селекторы.
  • Данные могут быть представлены несколько беспорядочно, поэтому зачастую требуется последующая обработка. Опять же, в онлайн магазине могут возникнуть проблемы с различным отображением цен, например — ($1.00, $1, $1,00).

Scrapy поставляется со встроенным решением проблемы — ItemLoaders. Это интересный способ заполнения объекта Product.

Вы можете добавить несколько выражений XPath одному и тому же полю, и он проверит все последовательно. По умолчанию, если найдено несколько XPath, они будут помещены в список.

В официальной документации Scrapy можно найти много примеров операций ввода и вывода данных.

Это очень полезно, если вам понадобится изменить или очистить извлеченные данные. К примеру, получение списка доступных валют, изменение одной единицы измерения в другую (сантиметры в метры, градусы Цельсия в Фаренгейты и так далее).

На нашей веб странице можно найти название продукта через разные XPath выражения: //title и //section[1]//h2/text()

В данном случае можно использовать Itemloader:

Обычно требуется только первый совпадающий XPath, поэтому нужно добавить output_processor=TakeFirst() в конструктор поля элемента.

В нашем случае нужен только первый соответствующий XPath для каждого поля, поэтому лучшим подходом будет создать собственный ItemLoader и по умолчанию output_processor для первого подходящего XPath:

Мы также добавили price_in, что является вводным процессором для удаления знака доллара из цены. Здесь используется MapCompose, что является встроенным процессором, который принимает несколько функций, которые выполняются последовательно. Можно добавить столько функций, сколько хочется. Нужно добавить _in или _out в название поля Item для добавления к нему процессора ввода или вывода.

Существует довольно много процессоров, прочитать о них подробнее можно в официальной документации.

Скрапинг нескольких страниц через Scrapy

Теперь, когда мы познакомились со скрапингом одной страницы, пришло время научиться скрапить несколько страниц. Например весь каталог товаров. Как мы видели ранее, есть разные виды Spider.

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

Зачастую можно найти один в base_url/sitemap.xml. Парсинг карты сайта может быть сложным, однако Scrapy может значительно облегчить процесс.

В нашем случае карту сайта можно найти здесь: https://clever-lichterman-044f16.netlify.com/sitemap.xml

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

К счастью, можно отфильтровать адреса URL и парсить только те, что соответствуют определенному паттерну. Это не сложно, мы будем использовать только те URL, внутри адресов которых значится совпадение с /products/.

Запустить скрипт для скрапинга всех товаров и экспорта результата в CSV файл можно следующим образом: scrapy runspider sitemap_spider.py -o output.csv

Что же делать, если на сайте нет никакой карты? У Scrapy есть решение и для таких случаев.

Позвольте представить вам… CrawlSpider.

CrawlSpider изучит сайт, начав со списка start_urls. Затем для каждого url он извлечет все ссылки, базирующиеся на списке Rule. В нашем случае все довольно просто, у товаров одинаковый URL паттерн /products/product_title, поэтому потребуется отфильтровать только эти URL.

Как видите, все встроенные «Пауки» довольно легко использовать. Начинать процесс с нуля было бы намного проблематичнее.

Вместе со Scrapy вам не нужно думать о логике парсинга, добавлении новых URL в очередь, фиксировании уже изученных адресов и многопоточности.

Заключение

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

Если до этого вы по большей части занимались скрапингом «вручную», используя такие инструменты, как BeautifulSoup / Requests, будет несложно оценить помощь Scrapy. Он значительно экономит время и создает удобные скраперы данных.

Надеюсь, вам понравился этот урок по Scrapy, и вам захочется поэкспериментировать с новым инструментом.

Для более подробного ознакомления со Scrapy можете изучить официальную документацию.

Удачного скрапинга!