CoderCastrov logo
CoderCastrov
Парсер веб-страниц

Как парсить данные о продуктах на Etsy с помощью Rvest

Как парсить данные о продуктах на Etsy с помощью Rvest
просмотров
11 мин чтение
#Парсер веб-страниц

Оригинальная публикация на ScraperAPI.

Зачем парсить Etsy? С момента своего основания в 2015 году Etsy стал компанией электронной коммерции с оборотом в 30 миллиардов долларов, с более чем 4,4 миллиона активных продавцов и 81,9 миллионами покупателей согласно данным Statista. Это много пользователей.

Хотя Etsy менее известен, чем гигант электронной коммерции Amazon, это одна из крупнейших площадок для нестандартных и креативных товаров.

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

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

Еще одно потенциальное использование такого скрипта - помощь продавцам и владельцам магазинов в лучшем понимании конкурентной среды, поиск изменений в ценах или спросе в отрасли и многое другое.

Если вы хотите усилить свое присутствие на Etsy или в электронной коммерции с помощью данных о клиентах, то это руководство для вас!

Пошаговое руководство по созданию парсера Etsy с использованием Rvest

Для этого руководства мы будем парсить раздел костюмы для мальчиков на Etsy с использованием фреймворка Rvest и Dplyr.

Прежде чем мы начнем писать наш скрипт, нам нужно установить две вещи:

После установки и открытия R Studio пришло время загрузить и установить наши зависимости.

1. Установка Rvest и Dplyr

В R Studio давайте создадим новый каталог с названием "rvest-etsy-scraper" и сохраните его в доступной папке на вашем компьютере, чтобы было легче найти его при необходимости.

С открытым новым проектом мы можем создать новый скрипт и назвать его как угодно. В нашем случае мы назвали его etsy-rvest для простоты.

Теперь мы можем установить наши зависимости с помощью двух простых строк кода:

install.packages("rvest")

install.packages("dplyr")

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

library("rvest")

library("dplyr")

2. Скачайте HTML-код Etsy для парсинга

Без HTML-кода невозможен парсинг. С этим в виду, давайте отправим HTTP-запрос на сервер и сохраним ответ в переменной с именем 'page'.

link = "https://www.etsy.com/c/clothing/boys-clothing/costumes?ref=pagination&explicit=1&page=1"

page = read_html(link)

Обратите внимание, что мы используем другую версию URL-адреса страницы категории.

Если вы перейдете на веб-сайт вручную, вы увидите, что это оригинальная версия URL-адреса:

https://www.etsy.com/c/clothing/boys-clothing/costumes?ref=catnav-10923

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

Чтобы сделать это более наглядным, вот как выглядит второй URL-адрес пагинации:

https://www.etsy.com/c/clothing/boys-clothing/costumes?ref=pagination&page=2

Следовательно, мы можем получить доступ к первой странице, просто изменив параметр 'page' в URL-адресе.

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

3. Поиск CSS свойств для выделения

Существуют два общих способа определения CSS селекторов, которые нам понадобятся для извлечения названия продукта, цены и URL.

Первый способ - это вручную перейти на страницу и использовать инструмент "Инспектор". Вы можете открыть его, нажав CTRL + Shift + C в Windows или CMD + Shift + C на Mac.

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

После некоторых тестов мы определили, что на каждой странице есть 64 списка продуктов, и вот CSS классы для каждого элемента:

  • Название продукта: .v2-listing-card h3
  • Цена продукта: .wt-text-title-01 .wt-text-title-01 .currency-value
  • URL продукта: li.wt-list-unstyled div.js-merch-stash-check-listing a.listing-link

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

Использование SelectorGadget для тестирования логики

Не все веб-сайты построены одинаково, поэтому нет способа получить CSS свойства напрямую из SelectorGadget, потому что URL не всегда находится в определенном элементе.

Например, URL товара часто находится в том же элементе, что и название товара на многих веб-сайтах. Но это не относится к Etsy.

Однако есть другой способ использования SelectorGadget для поиска CSS элементов, таких как URL: тестирование свойств.

С открытым SelectorGadget мы сначала нашли элемент самого высокого уровня для карточек товаров.

Внутри элемента <li> мы хотим найти основной <div>, в котором содержится URL товара.

Затем мы знаем, что мы хотим выбрать тег <a> внутри этого div, чтобы найти URL. Мы использовали SelectorGadget, чтобы убедиться, что мы выбираем 64 элемента, чтобы проверить правильность нашей логики.

Вот почему так важно понимать, как устроены веб-страницы при парсинге.

Совет: Вы можете использовать нашу шпаргалку по CSS селекторам, чтобы узнать больше о CSS селекторах и ускорить разработку парсера.

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

4. Тестирование нашего скрипта парсинга

Для этого теста мы хотим запустить весь скрипт, чтобы извлечь название 64 продуктов на странице.

Здесь нам пригодится Dplyr, так как он позволит нам использовать оператор Pipe (%>%) для упрощения процесса.

Простыми словами, оператор Pipe (%>%) берет значение, которое находится слева, вычисляет его и передает результат в качестве первого аргумента в функцию, которая находится после оператора.

Примечание: Если вы хотите узнать больше об операторе Pipe, ознакомьтесь с нашим учебником по начальному веб-скрапингу на R.

product_name = page %>% html_nodes(".v2-listing-card h3") %>% html_text()

Как видите, мы передаем значение, хранящееся в переменной 'page' - это HTML, которое мы загрузили ранее - в нашу функцию 'html_nodes()'.

Результат этой операции затем передается следующей функции - 'html_text()', чтобы мы могли извлечь только текст внутри элемента без тегов и всего остального.

Чтобы протестировать это, введите 'product_names' в консоли.

Вот и все, 64 названия продуктов получены всего за несколько секунд.

К сожалению, на странице много лишних пробелов и эти раздражающие \n в начале и конце каждой строки.

Чтобы очистить их, давайте добавим дополнительную функцию к нашей переменной 'product_name':

%>% stringr::str_trim()

Вот результат:

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

5. Получение остальных элементов с использованием той же логики

Хорошо, теперь, когда мы знаем, что наш скрипт работает, давайте спарсим цену и URL каждого из этих элементов на странице.

product_price = page %>% html_nodes(".wt-text-title-01 .wt-text-title-01 .currency-value") %>% html_text()

product_url = page %>% html_nodes("li.wt-list-unstyled div.js-merch-stash-check-listing a.listing-link") %>% html_attr("href")

В случае атрибутов, вместо использования функции html_text(), мы использовали html_attr("href") для извлечения значения внутри выбранного атрибута - в данном случае 'href'.

6. Отправка данных в data frame

Хорошо, наш парсер работает отлично. Однако, вывод данных в консоль может быть не самым лучшим способом их обработки. Давайте создадим data frame для организации наших данных для последующего анализа.

Для этого мы вызовем функцию data.frame() из пакета Rvest и используем наши переменные в качестве столбцов.

costumes_ideas = data.frame(product_name, product_price, product_url, stringsAsFactors = FALSE)

Мы можем ввести команду View(costumes_ideas), чтобы посмотреть на только что созданный data frame.

Примечание: команда View чувствительна к регистру, поэтому убедитесь, что вы используете заглавную букву V.

7. Переход по страницам с пагинацией в нашем скрипте

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

Хотя есть несколько способов сделать это, мы создадим цикл for для парсинга двух страниц в первую очередь. Конечно, вы можете масштабировать его для более крупных проектов, которые парсят много страниц, но для экономии времени и простоты давайте ограничимся небольшим объемом.

Несколько вещей, которые следует учесть при написании цикла for:

  • Проанализируйте URL-адрес страниц с пагинацией, чтобы определить, сколько из них есть - в нашем примере категории их всего 194.
  • Посмотрите, как увеличиваются числа - в нашем случае пагинация увеличивается на одну в URL с каждой страницей, но это не относится ко всем сайтам.

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

costumes_ideas = data.frame()

for (page_result in seq(from = 1, to = 2, by = 1)) {

link = paste0("https://www.etsy.com/c/clothing/boys-clothing/costumes?ref=pagination&explicit=1&page=", page_result)

page = read_html(link)

product_name = page %>% html_nodes(".v2-listing-card h3") %>% html_text() %>% stringr::str_trim()

product_price = page %>% html_nodes(".wt-text-title-01 .wt-text-title-01 .currency-value") %>% html_text()

product_url = page %>% html_nodes("li.wt-list-unstyled div.js-merch-stash-check-listing a.listing-link") %>% html_attr("href")

costumes_ideas = rbind(costumes_ideas, data.frame(product_name, product_price, product_url, stringsAsFactors = FALSE))

}

Хорошо, здесь происходит много всего, поэтому давайте рассмотрим каждую часть:

  • Мы создали пустой data frame за пределами цикла for, чтобы избежать перезаписи существующих данных из предыдущего цикла новыми данными из следующего цикла.
  • Затем мы обернули наш старый data frame в функцию rbind(), которая использует пустой data frame в качестве первого аргумента. Вместо перезаписи это добавит каждый набор данных к существующему.
  • page_result начнется со значения 1, а затем увеличится на один, пока не достигнет 2. Это будет наш основной способ перемещения по страницам.
  • Функция paste0() склеит наш URL со значением page_result, при этом автоматически удаляя любые пробелы.

Остальная часть нашего скрипта останется неизменной; мы просто вырежем ее и вставим в цикл for.

Пора запустить тест!

Вот и все! Было спарсено 128 элементов (64 на двух страницах) за считанные секунды.

Однако парсить 2 страницы из 194 не так уж и впечатляюще, верно? Давайте еще больше масштабируем наш проект.

8. Использование ScraperAPI для масштабируемости

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

Чтобы избежать этих мер, нам придется создать функцию, которая изменяет наш IP-адрес, иметь доступ к пулу IP-адресов, между которыми наш скрипт будет переключаться, создать способ обработки CAPTCHA и обрабатывать страницы с JavaScript, которые становятся все более распространенными.

Или мы можем просто отправить наш запрос HTTP через сервер ScraperAPI и позволить им автоматически обработать все.

Нам нужно только создать бесплатную учетную запись ScraperAPI, чтобы получить 5000 бесплатных вызовов API и получить доступ к нашему API-ключу.

Затем мы внесем три небольшие корректировки в наш код.

library("rvest")

library("dplyr")

costumes_ideas = data.frame()

for (page_result in seq(from = 1, to = 194, by = 1)) {

link = paste0("http://api.scraperapi.com?api_key=51e43be283e4db2a5afb62660xxxxxxx&url=https://www.etsy.com/c/clothing/boys-clothing/costumes?ref=pagination&explicit=1&page=", page_result, "&country_code=us")

page = read_html(link)

product_name = page %>% html_nodes(".v2-listing-card h3") %>% html_text() %>% stringr::str_trim()

product_price = page %>% html_nodes(".wt-text-title-01 .wt-text-title-01 .currency-value") %>% html_text()

product_url = page %>% html_nodes("li.wt-list-unstyled div.js-merch-stash-check-listing a.listing-link") %>% html_attr("href")

costumes_ideas = rbind(costumes_ideas, data.frame(product_name, product_price, product_url, stringsAsFactors = FALSE))

}

Во-первых, мы увеличили общее количество страниц, которые мы будем парсить, до 194 страниц, что является общим количеством страниц для этой категории.

Затем мы передаем наш целевой URL в качестве параметра запроса ScraperAPI:

http://api.scraperapi.com?api_key=51e43be283e4db2a5afb62660xxxxxxx**&url=https://www.etsy.com/c/clothing/boys-clothing/costumes?ref=pagination&explicit=1&page=**“

Наконец, мы добавили параметр “&country_code=us” после page_result, чтобы указать ScraperAPI отправлять наш запрос с IP-адресов США.

Поскольку на момент написания этой статьи наш скрипт отправлял запрос с итальянского IP-адреса, результаты были бы отличными от результатов, если бы мы искали из США - кроме того, цена была бы в евро, а не в долларах США, что является важным отличием.

Давайте проведем последний тест, чтобы увидеть, что мы получаем, но помните, что это займет некоторое время, так как нашему скрипту нужно перейти на каждую страницу из 194 страниц и спарсить каждый элемент:

Вы также заметите активность на панели инструментов ScraperAPI:

Отлично! Теперь у нас есть 12 415 точек данных, но мы, возможно, захотим сохранить их не только в виде фрейма данных для более удобного анализа, верно?

9. Запись данных в файл Excel

Это одна из причин, почему мы любим R. Экспорт нашего фрейма данных в файл Excel так же прост, как установка пакета.

install.packages("writexl")

Примечание: Введите команду установки в консоль.

Добавьте нашу новую зависимость в начало нашего скрипта.

library("writexl")

Создайте новую функцию за пределами цикла, где первый аргумент - это имя нашего фрейма данных, а второй - путь и имя файла.

write_xlsx(costumes_ideas,"/Users/lyns/Documents/Coding/costumes-data.xlsx")

Примечание: Вот быстрое руководство по использованию функции write_xlsx().

Наконец, мы просто запускаем две новые строки нашего парсера (не нужно запускать весь скрипт заново), и все.

Если мы перейдем по указанному пути внутри функции, мы найдем наш новый файл Excel внутри.

Теперь мы можем немного расслабиться, потому что все работает без сбоев!

Завершение

Большое спасибо, что следовали за нами в этом захватывающем проекте. R - это простой, но мощный язык, и в сочетании со всеми возможностями ScraperAPI мы можем создавать эффективные и практически неостанавливаемые скрипты для парсинга любого веб-сайта.

В дополнение к защите от блокировки или бана ScraperAPI также добавляет время отдыха в наши скрипты, чтобы избежать перегрузки серверов или повреждения парсимых веб-сайтов.

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

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

До следующего раза, счастливого парсинга!