Web-scapping с библиотекой rvest

Сегодня мы будем сгружать данные с html-страницы. Для этого нам понадобится библиотека rvest. Установим её:

install.packages("rvest")

И загрузим:

library(rvest)

Теперь, когда у нас всё готово к работе, зайдём на сайт N+1 и посмотрим на исходный код его главной страницы. Нас будут интересовать новости за последнее время — те, что отображаются на главной странице. Для начала выберем какую-нибудь одну новость и напишем универсальный код для выгрузки информации с неё (а потом сможем написать функцию и применить её к ссылкам на новости в цикле). Сохраним ссылку и считаем код со страницы:

url <-'https://nplus1.ru/news/2019/05/23/cosmoquest'
page <- read_html(url)
page
## {xml_document}
## <html class="no-js bg-fixed _no-bg" style="background-image:url(https://nplus1.ru/images/2019/05/23/2138c00faaeeafb3e80529ca0481a42b.jpg)" lang="">
## [1] <head>\n<meta http-equiv="Content-Type" content="text/html; charset= ...
## [2] <body style="background-image:url(https://nplus1.ru/images/2019/05/2 ...

Результат выше — полный html-код в «свёрнутом» виде. Теперь в пределах этого кода мы будем искать нужные нам тэги. Библиотека rvest имеет особый синтаксис, унаследованный от magrittr, а именно, pipes, которые мы встречали в dplyr и tidyverse: %>%. Найдём в объекте page все тэги <a>:

page %>%
  html_nodes("a")
## {xml_nodeset (80)}
##  [1] <a href="#" class="action-menu pull-left"><i class="icon icon-navic ...
##  [2] <a href="/" class="link-logo"><img src="/i/logo-mobile.png"></a>
##  [3] <a href="#" class="action-search pull-right"><i class="icon icon-se ...
##  [4] <a href="#" class="action-search-close">×</a>
##  [5] <a href="/rubric/astronomy" class="">Астрономия</a>
##  [6] <a href="/rubric/physics" class="">Физика</a>
##  [7] <a href="/rubric/biology" class="">Биология</a>
##  [8] <a href="/rubric/robots-drones" class="">Роботы и дроны</a>
##  [9] <a href="/theme/oops" class="">Научные закрытия</a>
## [10] <a href="/theme/economy-literature" class="">Краткий курс по литэко ...
## [11] <a href="/theme/hayabusa" class="">Приключения «Хаябусы-2»</a>
## [12] <a href="/theme/art-of-integration" class="">Интегрирование — искус ...
## [13] <a href="/" class="link-logo"></a>
## [14] <a href="#" class="action-search-close">×</a>
## [15] <a href="/rubric/astronomy" class="">Астрономия</a>
## [16] <a href="/rubric/physics" class="">Физика</a>
## [17] <a href="/rubric/biology" class="">Биология</a>
## [18] <a href="/rubric/robots-drones" class="">Роботы и дроны</a>
## [19] <a href="#" class="action-search"><i class="icon icon-search"></i></a>
## [20] <a href="/theme/oops" class="">Научные закрытия</a>
## ...

Теперь найдём все части кода с тэгом <p> и посмотрим на первые 10 элементов:

page %>%
  html_nodes("p") %>%
  head(10)
## {xml_nodeset (10)}
##  [1] <p class="table">\n                        <a data-rubric="astronom ...
##  [2] <p class="table">\n            <a href="/news/2019/05/23">\n        ...
##  [3] <p class="table">\n            <a href="/difficult/1.2">\n          ...
##  [4] <p class="title"></p>
##  [5] <p class="credits">NASA</p>
##  [6] <p>Стартовал проект Bennu Mappers, в рамках которого любой желающий ...
##  [7] <p>Автоматическая межпланетная станция OSIRIS-REx была <a href="htt ...
##  [8] <p>Задача забора образца реголита с Бенну оказалась гораздо сложнее ...
##  [9] <p>Принять участие в проекте может любой желающий, имеющий доступ в ...
## [10] <p>Ранее мы <a href="https://nplus1.ru/news/2019/03/26/AstroQuest"  ...

Допустим, что нам нужна следующая информация о статье: дата, время, автор, сложность и сам текст статьи. Дата, время и сложность статьи содержится в табличке перед текстом. Таблицы на этой странице имеют тэг <p> с атрибутом class равным table. В rvest класс указывается через точку, id — через #.

page %>%
  html_nodes("p.table")
## {xml_nodeset (3)}
## [1] <p class="table">\n                        <a data-rubric="astronomy ...
## [2] <p class="table">\n            <a href="/news/2019/05/23">\n         ...
## [3] <p class="table">\n            <a href="/difficult/1.2">\n           ...

Если посмотреть внимательнее, то из таблицы нам нужны только те части, которые заключены в тэги <span>. Вытащим их и возьмём только текст:

page %>%
  html_nodes("p.table") %>%
  html_nodes("span") %>%
  html_text()
## [1] "17:32"       "23 Май 2019" "Сложность"   "1.2"

Теперь нам осталось сохранить результат (а это обычный текстовый вектор) в переменную и извлечь оттуда нужные части:

info <- page %>%
  html_nodes("p.table") %>%
  html_nodes("span") %>%
  html_text() 

Извлечём время написания статьи, дата и сложность:

ntime <- info[1]
ndate <- info[2]
ndiff <- as.numeric(info[4])

Проверим, что получилось:

ntime
## [1] "17:32"
ndate
## [1] "23 Май 2019"
ndiff
## [1] 1.2

С текстом статьи работать будет сложнее, займёмся этим в следующий раз.