Практическое руководство по веб-скрапингу в R

В этом руководстве мы рассмотрим все шаги, связанные с веб-скрапингом в R с помощью rvest с целью извлечения отзывов о товарах из одного общедоступного URL с сайта Amazon.
2 мин. чтения
People coding at computers with data and media icons.

В этом руководстве мы рассмотрим:

  • Начало работы с веб-скрапингом в R
  • Понимание веб-страницы  
  • Понимание DevTools  
  • Глубокое погружение в веб-скрапинг в R: учебник  
  • Масштабирование на несколько URL-адресов  
  • Следующий шаг: Pre-Built vs. Self-Built?  
  • Начало работы с веб-скрапингом в R

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

    Понимание инструментов: R и rvest

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

    rvest 一 от «harvest»一 один из самых популярных пакетов R, предоставляющий функции веб-скрапинга, в том числе и благодаря чрезвычайно удобному интерфейсу. Ванильный rvest позволяет извлекать данные только с одной веб-страницы, что идеально подходит для первоначального исследования. Впоследствии вы можете расширить его с помощью библиотеки polite для скрапинга большего количества веб-страниц.  

    Настройка среды разработки

    Если вы еще не используете R в RStudio, следуйте приведенным здесь инструкциям по его установке.  

    После этого откройте консоль и установите rvest:

    install.packages("rvest")
    

    Официальная рекомендация заключается в расширении встроенных функций rvest за счет дополнительных пакетов из коллекции tidyverse — например, magrittr, который улучшает читабельность кода, или xml2, позволяющего работать с HTML и XML. Вы можете сделать это, установив tidyverse:

    install.packages("tidyverse")

    Понимание веб-страницы

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

    Из этого определения вытекают три важных момента:

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

    Чтобы понять, как выполнить веб-скрапинг целевого URL, сначала необходимо разобраться, как отображается содержимое веб-страницы с помощью языка разметки HTML и CSS.

    HTML отвечает за содержание и структуру веб-страницы 一 язык разметки загружается в веб-браузер для создания древовидной объектной модели документа (DOM) 一 путем организации ее содержимого с помощью специальных тегов, которые имеют иерархическую структуру. Каждый из них обладает определенной функциональностью, применяемой ко всему содержимому, находящему внутри его открывающих (<>) и закрывающих угловых скобок (</>):  

    <!DOCTYPE html>
    <html lang="en-gb" class="a-ws a-js a-audio a-video a-canvas a-svg a-drag-drop a-geolocation a-history a-webworker a-autofocus a-input-placeholder a-textarea-placeholder a-local-storage a-gradients a-transform3d -scrolling a-text-shadow a-text-stroke a-box-shadow a-border-radius a-border-image a-opacity a-transform a-transition a-ember" data-19ax5a9jf="dingo" data-aui-build-date="3.22.2-2022-12-01">
    ▶<head>..</head>
    ▶<body class="a-aui_72554-c a-aui_accordion_a11y_role_354025-c a-aui_killswitch_csa_logger_372963-c a-aui_launch_2021_ally_fixes_392482-t1 a-aui_pci_risk_banner_210084-c a-aui_preload_261698-c a-aui_rel_noreferrer_noopener_309527-c a-aui_template_weblab_cache_333406-c a-aui_tnr_v2_180836-c a-meter-animate" style="padding-bottom: 0px;">..</body>
    </html>

    Тег <html> является обязательным элементом любой веб-страницы, внутри которого вложены еще два — <head> и <body>. Последние также являются родительскими для множества других тегов, среди которых самые популярные — это <div> (для секции документа) и <p> (для параграфа).  

    В приведенном выше фрагменте вы можете увидеть атрибуты, связанные с каждым HTML-элементом: lang, class и style создаются по умолчанию, тогда как атрибуты, которые начинаются с «data-» — являются на Amazon пользовательскими.  

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

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

    <body .. style="padding-bottom: 0px;">

    На чистом CSS это будет выглядеть следующим образом:

    body {padding-bottom: 0px;}
    

    Здесь body — это выбранный селектор, padding-bottom — свойство, а 0px — его значение. Любой тег, класс или id может быть использован в качестве селектора CSS.  

    Интернет-пользователи могут динамически взаимодействовать с содержимым веб-страницы с помощью функций JavaScript благодаря внедрению в HTML-разметку специального тега script. После взаимодействия с пользователем отображаемое содержимое может измениться, а вместо него появится новое; продвинутые веб-скраперы могут имитировать действия реальных пользователей, о чем мы поговорим позже.  

    Понимание DevTools

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

    Инструменты разработчика можно найти в настройках, которые открываются при нажатии на три вертикальные точки в верхнем правом углу браузера, в разделе «Дополнительные инструменты»:

    Процесс открытия инструментов разработчика в Chrome
    Процесс открытия инструментов разработчика в Chrome

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

    Процесс доступа к отрисованным элементам веб-страницы из инструментов разработчика в Chrome
    Процесс доступа к отрисованным элементам веб-страницы из инструментов разработчика в Chrome

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

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

    Глубокое погружение в веб-скрапинг в R: Учебник

    В этом разделе мы рассмотрим, как выполнять веб-скрапинг URL-адресов Amazon для извлечения отзывов о товарах.  

    Предустановки

    Убедитесь, что в среде Rstudio установлено следующее:

    • R = 4.2.2
    • rvest = 1.0.3
    • tidyverse = 1.3.2

    Интерактивное изучение веб-страницы

    Вы можете использовать DevTools в Chrome для изучения HTML вашего URL и создания списка всех классов и идентификаторов HTML-элементов, которые содержат интересующую вас информацию, т.е. обзоры продуктов:

    Отзыв покупателя со страницы товара Amazon, выбранный с помощью DevTools в Chrome
    Отзыв покупателя со страницы товара Amazon, выбранный с помощью DevTools в Chrome

    Каждый отзыв клиента располагается в div с id в следующем формате:  

    customer_review_$INTERNAL_ID.
    

    Содержимое HTML-элемента div, соответствующее отзыву покупателя на скриншоте выше, выглядит следующим образом:

    <div id="customer_review-R2U9LWUSIPY0GS" class="a-section celwidget" data-csa-c-id="kj23dv-axnw47-69iej3-apdvzi" data-cel-widget="customer_review-R2U9LWUSIPY0GS">
    <div data-hook="genome-widget" class="a-row a-spacing-mini">..</div>
    <div class="a-row">
    <a class="a-link-normal" title="4.0 out of 5 stars" href="https://www.amazon.co.uk/gp/customer-reviews/R2U9LWUSIPY0GS/ref=cm_cr_dp_d_rvw_ttl?ie=UTF8&amp;ASIN=B07SR4R8K1">
    <i data-hook="review-star-rating" class="a-icon a-icon-star a-star-4 review-rating">
    <span class="a-icon-alt">4.0 out of 5 stars</span>
    </i>
    </a>
    <span class="a-letter-space"></span>
    <a data-hook="review-title" class="a-size-base a-link-normal review-title a-color-base review-title-content a-text-bold" href="https://www.amazon.co.uk/gp/customer-reviews/R2U9LWUSIPY0GS/ref=cm_cr_dp_d_rvw_ttl?ie=UTF8&amp;ASIN=B07SR4R8K1">
     		<span>Very good controller if a little overpriced</span>
      	 </a>
    </div>
    <span data-hook="review-date" class="a-size-base a-color-secondary review-date">..</span>
    <div class="a-row a-spacing-mini review-data review-format-strip">..</div>
    <div class="a-row a-spacing-small review-data">
    <span data-hook="review-body" class="a-size-base review-text">
    <div data-a-expander-name="review_text_read_more" data-a-expander-collapsed-height="300" class="a-expander-collapsed-height a-row a-expander-container a-expander-partial-collapse-container" style="max-height:300px">
    <div data-hook="review-collapsed" aria-expanded="false" class="a-expander-content reviewText review-text-content a-expander-partial-collapse-content">
    <span>In all honesty I'm not sure why the price is quite as high ….</span>
    </div>
    				…</div>
    			…</span>
    		…</div>
    	…</div>
    

    Каждый интересующий вас фрагмент отзыва покупателя имеет свой уникальный класс: review-title-content для заголовка, review-text-content для основного текста и review-rating для рейтинга.  

    Можно проверить, является ли класс на веб-странице уникальным и, если да, то воспользоваться им в качестве «простого селектора». Однако более надежным способом является все же использование дескриптора CSS, который останется уникальным, даже если в будущем тот же класс будет присвоен и некоторым другим элементам веб-страницы.

    Просто извлеките CSS-дескриптор, щелкнув правой кнопкой мыши по элементу в DevTools и выбрав Copy Selector:

    Процесс копирования селектора CSS для элемента из Инструментов разработчика в Chrome
    Процесс копирования селектора CSS для элемента из Инструментов разработчика в Chrome

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

    • customer_review-R2U9LWUSIPY0GS > div:nth-child(2) > a.a-size-base.a-link-normal.review-title.a-color-base.review-title-content.a-text-bold > span для title  
    • customer_review-R2U9LWUSIPY0GS > div.a-row.a-spacing-small.review-data > span > div > div.a-expander-content.reviewText.review-text-content.a-expander-partial-collapse-content > span для body    
    • customer_review-R2U9LWUSIPY0GS > div:nth-child(2) > a:nth-child(1) > i.review-rating > span для rating *.review-rating был добавлен вручную для лучшей согласованности.  

    CSS Selector vs XPath для веб-скрапинга

    В этом учебнике мы решили использовать селектор CSS для идентификации элементов при веб-скрапинге. Другой популярный метод — использовать XPath, т.е. XML Path, который идентифицирует элемент через его полный путь в DOM.

    Вы можете извлечь Xpath (полный путь к элементу в DOM), следуя той же процедуре, которая используется и для селекторов CSS. Например, название обзора является следующим:

    /html/body/div[2]/div[3]/div[6]/div[32]/div/div/div[2]/div/div[2]/span[2]/div/div/div[3]/div[3]/div/div[1]/div/div/div[2]/a[2]/span 
    

    Селектор CSS чуть быстрее, а XPath имеет немного лучшую обратную совместимость. За исключением этих небольших различий, выбор одного из них зависит больше от личных предпочтений, чем от их технических преимуществ.

    Программное извлечение информации с веб-страницы

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

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

    library(”rvest”)
    library(”tidyverse”)

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

    HtmlLink <- "https://www.amazon.co.uk/Xbox-Elite-Wireless-Controller-2/dp/B07SR4R8K1/ref=sr_1_1_sspa?crid=3F4M36E0LDQF3"
    

    Затем извлеките стандартный идентификационный номер Amazon (ASIN) из URL-адреса, чтобы использовать его в качестве уникального идентификатора продукта:

    ASIN <- str_match(HtmlLink, "/dp/([A-Za-z0-9]+)/")[,2]
    

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

    Теперь загрузите HTML-контент веб-страницы:

    HTMLContent <- read_html(HtmlLink)
    

    Функция read_html() является частью пакета xml2.

    Если вы выведете контент с помощью функции print(), мы увидим, что он соответствует проанализированной нами ранее структуре HTML:  

    {html_document}
    <html lang="en-gb" class="a-no-js" data-19ax5a9jf="dingo">
    [1] <head>n<meta http-equiv="Content-Type" content="text/ht ...
    [2] <body class="a-aui_72554-c a-aui_accordion_a11y_role_354 ...
    

    Теперь вы можете извлечь три интересующих вас узла для всех отзывов о товаре на странице. Используйте дескрипторы CSS, предоставленные инструментами разработчика в Chrome и модифицированные для удаления идентификатора отзыва покупателя #customer_review-R2U9LWUSIPY0GS и соединителя «>» из строки; вы также можете воспользоваться функциями html_nodes() и html_text() в rvest для сохранения HTML-контента в отдельных объектах.  

    Следующие команды извлекут заголовки обзоров:

    review_title <- HTMLContent %>%
    html_nodes("div:nth-child(2) a.a-size-base.a-link-normal.review-title.a-color-base.review-title-content.a-text-bold span") %>%
    html_text()
    

    Пример записи в review_title: «Очень хороший контроллер, хотя цена немного завышена».  

    Приведенный ниже код извлечет «тело» обзора:

    review_body <- HTMLContent %>%
    html_nodes("div.a-row.a-spacing-small.review-data span div div.a-expander-content.reviewText.review-text-content.a-expander-partial-collapse-content span") %>%
    html_text()
    

    Пример записи в review_body начинается со слов “Честно говоря, я не уверен, почему цена…”.  

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

    review_rating <- HTMLContent %>%
    html_nodes("div:nth-child(2) a:nth-child(1) i.review-rating span") %>%
    html_text()
    

    Примером записи в review_rating является «4,0 из 5 звезд».  

    Чтобы улучшить качество этой переменной, извлеките только оценку «4.0» и преобразуйте ее в int:

    review_rating <- substr(review_rating, 1, 3) %>% as.integer()
    

    Функция %>% обеспечивается за счет использования magrittr.

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

    df <- tibble(review_title, review_body, review_rating)
    

    Итоговый фрейм данных выглядит следующим образом:

    Выведенные tibble данные, которые были получены с помощью веб-скрапинга
    Выведенные tibble данные, которые были получены с помощью веб-скрапинга

    Наконец, отличной идеей будет рефакторинг кода в функцию scrape_amazon <- function(HtmlLink), что позволит привести его в соответствие к лучшим современным практикам и оптимизировать для масштабирования сразу на несколько целевых URL.    

    Масштабирование на несколько URL-адресов

    После составления скрапинг-шаблона вы можете создать с помощью веб-краулинга и веб-скрапинга список URL-адресов всех продуктов главных конкурентов на Amazon.  

    При масштабировании на несколько URL-адресов необходимо описать технические требования приложения.

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

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

    • Пакетно или в режиме реального времени
    • Формат(ы) вывода, например, JSON, NDJSON, CSV или XLSX
    • Цель(и) вывода, например, электронная почта, API, webhook или облачное хранилище

    Мы уже упоминали, что вы можете расширить возможности rvest с помощью polite для веб-скрапинга сразу нескольких интернет-страниц. polite создает и управляет сеансом сбора данных с веб-страниц при помощи трех основных функций, в полном соответствии с файлом robots.txt веб хоста, с использованием встроенного ограничителя скорости и кэшированием ответов:  

    • bow() создает сессию по сбору данных для определенного URL, т.е. представляет вас веб-хосту и запрашивает разрешение на веб-скрапинг.  
    • scrape() получает доступ к HTML-коду URL-адреса; вы можете передать эту функцию из rvest в html_nodes() и html_text(), чтобы получить необходимый контент.  
    • nod() обновляет URL сессии до следующей страницы без необходимости заново создавать сессию.  

    Цитирую непосредственно с их сайта: «Три главных правила вежливого сеанса — спрашивать разрешение, не спешить и никогда не просить дважды».  

    Следующий шаг: Pre-Built vs. Self-Built?

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

    • Команда специалистов с большим опытом извлечения данных
    • Команда инженеров DevOps с большим опытом управления прокси и обхода антиботов, позволяющим преодолевать любую CAPTCHA-защиту и работать с сайтами с ограниченным доступом.
    • Команда инженеров с опытом создания инфраструктуры по извлечению данных — пакетному или в режиме реального времени
    • Команда экспертов в области права в сфере законодательных требований по защите конфиденциальной информации (таких как GDPR и CCPA)

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

    Как правило, пользователи прибегают к использованию следующего продвинутого функционала:

    1. Минимизируйте вероятность CAPTCHA и обнаружения ботов: Самый простой подход здесь — добавление случайного sleep(), чтобы избежать перегрузки веб-серверов и стандартных шаблонов запросов. Наиболее же эффективным подходом считается использование user_agent или прокси-сервера для распределения запросов между различными IP.  
    2. Веб-скрапинг сайтов с использованием Javascript: В нашем примере с Amazon URL-адрес не меняется при выборе конкретного варианта товара. Это приемлемо для отзывов, поскольку они являются общими, но не для характеристик продукта. Чтобы имитировать взаимодействие пользователей на динамических веб-страницах, можно использовать такой инструмент, как RSelenium, который позволяет автоматизировать навигацию по веб-браузеру.  

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

    Web Scraper от Bright Data предоставляет шаблоны для множества веб-сайтов, оснащенных самыми современными функциями, включая продвинутый Amazon Scraper!