Собираем отзывы на Amazon с помощью Scrapy

311

Scrapy — это продвинутый Python-фреймворк для веб-скрапинга, который помогает разработчикам извлекать данные с разных сайтов. Scrapy использует веб-краулеров, называемых Spider. Они могут доставать, обрабатывать и сохранять данные. Поскольку Scrapy построен на базе Twitsted, асинхронного сетевого фреймворка, он отправляет запросы без блокировки потока. Это влияет на скорость.

Преимущества Scrapy

  • Имеется встроенный механизм под названием Selector, который отвечает за поиск и извлечение данные со страниц с помощью Xpath и CSS.
  • Для работы Scrapy не нужно много дополнительного кода как в случае с остальными фреймворками. Достаточно лишь указать сайт и данные, которые требуется получить. Scrapy сделает все остальное.
  • Scrapy — это бесплатный, кроссплатформенный проект с открытым исходным кодом.
  • Он является быстрым, мощным и легко расширяемым за счет асинхронной обработки запросов.
  • Используется для создания скраперов для крупных проектов.
  • С помощью Scrapy можно извлекать данные с любых страниц вне зависимости от их доступности.
  • Куда меньшее потребление памяти и мощности процессора в сравнении с другими библиотеками.
  • Поддерживает экспорт данных в разные форматы, включая CSV, XML, JSON и JSON Line.
  • Отличное сообщество для разработчиков.

Установка Scrapy

Scrapy работает в обеих версиях Python (2 и 3), но в этом руководстве будет использоваться Python 3. Есть два способа установки. Если имеется Anaconda, то нужно использовать канал conda-forge. Сама платформа доступна по ссылке.

Второй вариант — использовать пакетный менеджер pip. С его помощью можно установить Scrapy прямо на компьютер.

					

conda install -c conda-forge scrapy

pip install scrapy

В обоих случаях будет загружена и установлена последняя версия.

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

Архив с кодом проекта. Весь код протестирован на: python 3.8 / scrapy 2.3.0 / ubuntu 16.04

Для создания проекта нужно переместиться в папку с ним. Дальше создается проект Scrapy. В этом руководстве он будет называться scrapy_tutorial.

Есть вы получили ошибку No module named ‘_cffi_backend’, установите cffipip install cffi

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

Структура проекта scrapy

Рассмотрим в подробностях.

ФайлОписание
spidersЭта папка содержит всех Spider в формате класса Python. Если запустить Scrapy, то он выполнит поиск именно в этой папке
items.pyСодержит контейнер, который будет загружаться вместе с извлеченными данными
middleware.pyСодержит механизм обработки для работы с запросами и ответами
pipeline.pyНабор классов Python для последующей обработки классов
settings.pyЗдесь находятся все настройки

Создание Spider

Spider — это класс, содержащий методологию извлечения данных с указанного сайта. Другими словами, он определяет, как именно должен проходить процесс.

Для создания Spider используется такая команда.

В качестве spidername можно задать любое название, а на месте ссылки — URL сайта или домена, с которого требуется извлечь данные. В этом руководстве попробуем достать пользовательские обзоры на Apple iPhone XS Max с сайта Amazon.com.

Поэтому Spider будет называться reviewspider.

					

scrapy genspider reviewspider amazon.com/Apple-iPhone-Max-Fully-Unlocked/product-reviews/B07KFNRQ5S

Scrapy Shell

Scrapy Shell — это интерактивная оболочка, напоминающая Python Shell, где можно проверять свой код. С помощью нее можно протестировать выражения Xpath и CSS, убедившись, что данные извлекаются. Spider при этом даже не будет запускаться. Это быстрый и важный инструмент для разработки и отладки.

					

scrapy shell https://www.amazon.com/Apple-iPhone-Max-Fully-Unlocked/product-reviews/B07KFNRQ5S

Определение структуры HTML

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

Страница отзывов Amazon

На изображении видно, что у каждого обзора есть текст и оценка в звездах. Будет извлекать оба элемента.

Для просмотра структуры нужно кликнуть правой кнопкой по странице и нажать «Посмотреть код» или посмотреть код с помощью инструментов разработчика в браузере.

Согласно структуре все отзывы заключены в блок с id cm_cr-review_list, у которого есть внутренние блоки для каждого отзыва.

Структура страницы отзывов

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

<i data-hook="review-star-rating" class="a-icon a-icon-star a-star-2 review-rating">
  <span class="a-icon-alt">2.0 out of 5 stars</span>
</i>

Здесь рейтинг определяется классом a-icon-alt.

<span data-hook="review-body" class="a-size-base review-text review-text-content">
  <span>
  I know is use phones but for the price of $700 it looks in
 a bad condition unfortunately you take a risk when you buy
 phones with out been able to see them and are used and I am
 not happy with this purchase.
  </span>
</span>

Текст же заключен в класс a-size-base. Эта информация пригодится для создания Spider.

Создание парсера Scrapy

Если открыть Spider, который был создан раньше, то внутри будет такой класс.

					

import scrapy

class ReviewspiderSpider(scrapy.Spider):
name = 'reviewspider'
allowed_domains = ['amazon.com']
start_urls = ['https://www.amazon.com/Apple-iPhone-Max-Fully-Unlocked/product-reviews/B07KFNRQ5S/']

def parse(self, response):
pass

Это базовый шаблон, а allowed_domains и start_urls определены на основе переданных ссылок.

Логика извлечения данных будет прописана в функции parse, которая начнет работу после перехода на страницу, указанную в start_urls.

Scrapy предоставляет возможность поиска по нескольким URL одновременно. Для этого нужно определить базовый URL и те части, которые нужны присоединить к нему. Делается это с помощью urljoin(). Однако в этом примере достаточно будет лишь одной ссылки.

Далее код, который будет извлекать отзывы пользователей.

					

import scrapy

class ReviewspiderSpider(scrapy.Spider):
name = 'reviewspider'
allowed_domains = ['amazon.com']
start_urls = ['https://www.amazon.com/Apple-iPhone-Max-Fully-Unlocked/product-reviews/B07KFNRQ5S/']

def parse(self, response):
pass

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

star_rating=response.xpath('//span[@class="a-icon-alt"]/text()').extract()

В последней строке Scrapy использует Xpath для получения узла в ответе и извлечения его данных в текстовом формате.

for item in zip(star_rating, comments):
    # создаем словарь для хранения собранной информации
    scraped_data = {
      'Рейтинг': item[0],
      'Отзыв': item[1],
    }

Здесь каждый элемент добавляется в словарь Python.

yield scraped_data

Yield возвращает извлеченные данные для обработки и сохранения.

Обработка нескольких страниц

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

Перемещение по страницам происходит с помощью кнопки Next Page, и вот HTML-код для нее.

<li class="a-last">
  <a href="/Apple-iPhone-Max-Fully-Unlocked/product-reviews/B07KFNRQ5S/ref=cm_cr_arp_d_paging_btm_2?ie=UTF8&amp;pageNumber=2">
    Next page
    <span class="a-letter-space"></span>
    <span class="a-letter-space"></span>
    →
  </a>
</li>

Теперь осталось изменить Spider так, чтобы он мог определять кнопку и проверять, существует ли она. Если да, то он будет переходить по ней и снова вызывать парсер. Для этого достаточно добавить следующее в конец функции parse.

					

def parse(self, response):
star_rating = response.xpath('//span[@class="a-icon-alt"]/text()').extract()
comments = response.xpath('//span[@class="a-size-base review-text review-text-content"]/span/text()').extract()
count = 0

for item in zip(star_rating, comments):
# создаем словарь для хранения собранной информации
scraped_data = {
'Рейтинг': item[0],
'Отзыв': item[1],
}

# возвращаем собранную информацию
yield scraped_data

Здесь в качестве селектора для Next Page использовался CSS. После определения extract_first() ищет первое совпадение и проверяет, существует ли оно. Если да, то для нового URL вызывается метод self.parse.

Работа Spider

После создания Spider его нужно запустить с помощью следующей команды.

					

next_page = response.css('.a-last a ::attr(href)').extract_first()
if next_page:
yield scrapy.Request(
response.urljoin(next_page),
callback=self.parse
)

Команда runspider принимает reviewspider.py в качестве входящего файла и возвращает CSV-файл scraped_data.csv с собранными результатами.

Собираем отзывы на Amazon с помощью Scrapy

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

Scrapy предоставляет возможность экспорта для сохранения извлеченных данных в разных форматах или методах сериализации. Поддерживаются форматы CSV, XML и JSON.

Например, для получения вывода в формате CSV нужно перейти в settings.py и ввести следующие строки.

					

scrapy runspider scrapy_tutorial/spiders/reviewspider.py -o scraped_data.csv

После этого сохраните файл и снова запустите Spider. Сгенерированный файл окажется в папке проекта.

Если нужны временная метка или имя, то их можно передать в FEED_URI так: %(time)s или %(name)s.

Например:

FEED_URI = "scraped_data_%(time)s.json"

Выводы

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

Тест на знание python

Что делает код ниже?
Какой код выведет строку — "C:\Common\testString.doc" ?
Что выведет этот код?
Что выведет этот код?
Какие операторы можно использовать со строками?
Александр
Я создал этот блог в 2018 году, чтобы распространять полезные учебные материалы, документации и уроки на русском. На сайте опубликовано множество статей по основам python и библиотекам, уроков для начинающих и примеров написания программ. Пишу на популярные темы: веб-разработка, работа с базами данных, data sciense и другие...