Парсинг с помощью Python. Урок 4

Учимся оптимизированно переходить по ссылкам и скрейпить сайт с помощью библиотеки Scrapy

Дата
26 нояб. 2021
Парсинг с помощью Python. Урок 4

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

:
Съемка и монтаж: Глеб Лиманский

Откроем проект, с которым работали на прошлом уроке и создадим еще одного паука. Для этого переходим в папку spiders и создаем новый файл с расширением «py». Назовем его «all_books_spider.py».

Импорт библиотек

Как и в прошлый раз, мы начинаем наш проект с импорта библиотеки.

Пишем: import scrapy

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

Пишем:

from scrapy.spiders import CrawlSpider, Rule

from scrapy.linkextractors import LinkExtractor

Создаем класс

Как и в прошлом уроке, создаем класс, в который запишем правила скрейпинга. Только на этот раз в скобках вместо scrapy.Spider мы напишем CrawlSpider: class BookSpider(CrawlSpider).

Даем пауку имя: name = 'all_books'. Задаем начальную ссылку — это будет стартовая страница онлайн-магазина: start_urls = ['https://book24.ru/'].

Сбор ссылок

Теперь нужно написать правило сбора ссылок. 

Пишем: rules =. Cоздаем кортеж. Кортеж похож на список, отличие в том, что список — изменяемый тип данных, а кортеж нет. 

Чтобы понять, какое правило задать, откроем сайт. Мы видим несколько категорий с книгами. Можно переходить по ним поэтапно, собирая информацию о каждой книжке на каждой странице каждого раздела. И так пройтись по всем разделам. Ссылку для каждого перехода нам бы пришлось задавать с помощью css-селектора, как мы это делали в прошлый раз. Класс Crawl spider позволяет выполнить задачу проще и быстрее.

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

Скопируем ссылку и посмотрим на нее. Чтобы эта строка не влияла на код, закомментируем ее, для этого нужно написать в начало решетку: #https://book24.ru/catalog/fiction-1592/.

Мы видим, что после основного названия сайта (https://book24.ru) есть слово «catalog», а затем конкретный раздел каталога: fiction. Если мы зайдем в любой другой раздел, в ссылке тоже будет слово «catalog». Значит, нам нужно создать правило, чтобы паук проходился по всем ссылкам, в которых есть «catalog». Так мы соберем все разделы. 

Теперь зайдем на страницу с книгой. Скопируем ссылку и посмотрим на нее. #https://book24.ru/product/portret-doriana-greya-1597309/.

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

Запишем наше правило: Rule(LinkExtractor(allow='catalog')). Команда allow говорит, чтобы паук перешел по всем ссылкам, в которых есть слово «catalog». С помощью deny мы могли бы задать, по ссылкам с каким словом переходить не нужно. 

Вторым правилом зададим переход по страницам книг, то есть ссылкам со словом «product»: Rule(LinkExtractor(allow='product').

За то, что паук делает на странице, отвечает callback. Ему мы передадим функцию parse_items, в которой будет лежать информация, что именно нужно собрать со страницы: Rule(LinkExtractor(allow='product'), callback='parse_items')

Мы получили два правила. Первое говорит пауку, что нужно пройти по всем ссылкам со словом «catalog», после этого включается второе правило, которое говорит переходить по ссылкам со словом «product» и собирать нужную информацию. 

Функция

В прошлом уроке первую созданную функцию мы называли parse. Работая с классом CrawlSpider, нельзя использовать это название. Иначе код будет работать некорректно. Это важно помнить. Поэтому мы назвали нашу функцию parse_items. Как собирать информацию со страницы книги, мы подробно разбирали на прошлом уроке. 

Напишем ключевое слово yield и создадим словарь. Собирать необходимые нам элементы будем с помощью css-селекторов. 

Путь к названию и количеству покупок скопируем из предыдущего паука.

'name': response.css('h1.product-detail-page__title::text').get().strip(),

'buy': response.css('p.product-detail-page__purchased-text::text').get().split()[1], 

Чтобы полученный датасет был хорошо структурирован, соберем информацию обо всех разделах, которым принадлежит книга. Они как матрешка вкладываются друг в друга. Для примера перейдем в раздел «художественная литература» → «проза» → «историческая проза» и откроем страницу с книгой.

Scrapy Shell

Чтобы собрать информацию об этих разделах, перейдем в scrapy shell. Для этого наберем в терминале команду scrapy shell.

После этого передадим команде fetch страницу книги: fetch('https://book24.ru/product/odin-den-v-drevnem-mire-zapiski-puteshestvennika-vo-vremeni-6024803/').

Мы увидели ответ 200, значит, с сайтом можно работать. 

Посмотрим, где лежат названия разделов. Нажмем правой кнопкой мыши, выберем «просмотреть код». Мы видим, что название раздела лежит в теге span, который вложен в тег a. 

Обратимся к нему с помощью уже известной команды response.css. Если какой-то тег вложен в другой, мы можем дописать его через пробел. Мы дописываем тег span. Слово text поможет увидеть, что именно находится в css-селекторе, к которому мы обращаемся: response.css('a.breadcrumbs__link.smartLink span::text') 

Мы получили на выход список css-selector, в которых видим нужные слова: 

  • Главная
  • Художественная литература
  • Проза
  • Классическая зарубежная литература

Нам нужно достать каждый раздел по отдельности. Так как это список, обратимся по номеру элемента. Художественная литература на втором месте после раздела главная. Так как в программировании отсчет идет с нуля, обратимся к первому элементу.

Напишем: response.css('a.breadcrumbs__link.smartLink span::text')[1]. На выход мы получим нужный css-селектор. 

Чтобы выбрать содержание селектора, допишем get(): response.css('a.breadcrumbs__link.smartLink span::text')[1].get().

Пробелы в строке по бокам уберем с помощью известного метода strip(): response.css('a.breadcrumbs__link.smartLink span::text')[1].get().strip().

Мы получили нужный элемент, добавим его в словарь. Ключ назовем «first_type».

Чтобы получить следующий раздел, к которому относится книга, обратимся ко второму элементу списка: response.css('a.breadcrumbs__link.smartLink span::text')[2].get().strip()

Назовем ключ «second_type»: 'second_type': response.css('a.breadcrumbs__link.smartLink span::text')[2].get().strip(). И так же достанем третий последний раздел.

Мы указали все элементы, которые нам нужно достать. Выходим из ScrapyShell — control+D

Запись в файл

Нам даже не нужно прописывать переход по страницам, потому что паук сам соберет все ссылки на сайте, которые соответствуют нашему правилу. Сохраняем файл и можем запускать паука. Результат запишем в csv-файл all_books.csv. Напишем команду в терминале: scrapy crawl all_books -O all_books.csv

Паук начал собирать информацию обо всех книгах на сайте. Это займет около 10 минут. В папке с проектом мы видим новый документ. В нем есть информация о каждой из 16 тысяч книг. 

Это уже полноценный датасет, который можно анализировать. Например, посмотреть, какую книгу покупали чаще всего. Попробуйте выделить пятерку самых популярных книг, результат получится неожиданный. 

Мы используем cookie