Пакет rvest предназначен для извлечения данных из веб-страниц — веб-скрепинга (web scraping). rvest реализован как «обертка» над пакетами XML и httr и позволяет скачивать и обрабатывать html- и xml-файлы. Функции rvest можно объединять в последовательности команд при помощи оператора %>%
из пакета magrittr.
Установка пакета
install.packages("rvest")
Подготовка к работе
В качестве примера рассмотрим, как с помощью rvest извлечь информацию о сериале «Светлячок» («Firefly») с сайта IMDB. Скачаем html-страницу фильма с помощью функции html()
:
library(rvest)
firefly <- html("http://www.imdb.com/title/tt0303461/")
Нам необходимо знать CSS-селектор или путь XPath к элементу HTML, содержащему нужную информацию. Чтобы их определить понадобится консоль разработчика (для Google Chrome и Яндекс.Браузер), а в случае использования Firefox — дополнения Firebug и Firepath.
Извлечение данных: простые случаи
Допустим, мы хотим определить рейтинг фильма. Его можно получить из текста, расположенного в «звезде» или в строке Ratings.
Пути к этим элементам по CSS-селекторам будут следующими
#overview-top > div.star-box.giga-star > div.titlePageSprite.star-box-giga-star
#overview-top > div.star-box.giga-star > div.star-box-details > strong > span
Для определения элементов достаточно последней части пути. Для «звезды» это будет
div.titlePageSprite.star-box-giga-star
Вы можете проверить это, набрав $$("div.titlePageSprite.star-box-giga-star")
в консоли разработчика.
Для второго варианта (строки Ratings) рейтинг c помощью rvest можно получить следующим образом:
firefly %>% html_node("strong > span") %>% html_text() %>% as.numeric()
Функция html_node()
возвращает первый элемент, который соответствует заданному пути, html_text()
извлекает текстовое содержимое из этого элемента, а as.numeric()
преобразует его в цифру.
Знак > в пути можно убрать, записав:
firefly %>% html_node("strong span") %>% html_text() %>% as.numeric()
Вместо CSS-селекторов можно воспользоваться путем XPath:
firefly %>% html_node(xpath="//strong//span") %>% html_text() %>% as.numeric()
Для извлечения списка актеров воспользуемся функцией html_nodes(), которая возвращает все элементы, соответствующие данному пути, т.е. весь список актеров:
> firefly %>% html_nodes("#titleCast .itemprop span") %>% html_text()
[1] "Nathan Fillion" "Gina Torres" "Alan Tudyk" "Morena Baccarin" "Adam Baldwin" "Jewel Staite" "Sean Maher" "Summer Glau" "Ron Glass"
Тогда как html_node()
возвращает лишь первый элемент:
> firefly %>% html_node("#titleCast .itemprop span") %>% html_text()
[1] "Nathan Fillion"
Получим теперь последние сообщения, появившиеся на доске объявлений (message board). Они собраны в таблицу. Всего таблиц в документе четыре. В этом можно убедиться, выполнив
firefly %>% html_nodes("table")
Нас интересует 3-я таблица, и чтобы ее получить понадобится функция [[]]
. А чтобы извлечь материал из таблицы HTML, применим к ней функцию html_table()
из rvest:
> firefly %>% html_nodes("table") %>% .[[3]] %>% html_table()
X1 X2
1 Whirring guns billandbonnie
2 Joss Whedon and his fans aradiasnight
3 Episode List Problem rv_jt
4 Mal, Simon or Jayne? VivienCastro
5 Order of watching kolias18
6 Finally got around to watching it. SacrosanctPariah
Извлечение данных, расположенных на связанных страницах
Рассмотрим данные о биржевых инвестиционных фондах (Exchange Traded Funds, ETF), размещенные на сайте Лондонской фондовой биржи.
Вначале получим первую страницу с данными о ETF.
library(rvest)
url <- "http://www.londonstockexchange.com/exchange/prices-and-markets/ETFs/ETFs.html"
content <- html(url)
Как видно, данные собраны в таблицу, которая на момент написания этого текста располагалась на 42 страницах. Возможно, теперь она стала еще длиннее. Нашей первой задачей является автоматическое получение числа страниц этой таблицы.
С помощью CSS-селекторов путь к строке, содержащей число страниц, записывается как:
#fullcontainer > div.column1_nomenu > div:nth-child(11) > p.floatsx
Для того, чтобы получить содержимое этой строки достаточно лишь последнего селектора
# строка с номером страницы
content %>% html_node("p.floatsx") %>% html_text()
Теперь из этой строки ("Page 1 of 42"
) нужно извлечь подстроку с номером страницы.
Функция regexpr()
> regexpr("of",pages)
[[1]]
[1] 9
attr(,"match.length")
[1] 2
возвращает номер позиции начала подстроки "of"
в строке pages и длину этой подстроки.
Сохраним эти данные в переменных ppos
и plen
, соответственно:
result <- regexpr("of",pages)
ppos <- result[[1]]
plen <- attr(result,"match.length")
Извлечем из строки pages
подстроку с общим числом страниц и преобразуем ее в число
pages <- substr(pages,ppos+plen,nchar(pages)) %>% as.numeric()
Теперь в переменной pages
хранится число страниц.
Таблица фондов является первой из таблиц, хранящихся в элементе table
. Ее содержимое извлекаем следующим образом:
table <- content %>% html_nodes("table") %>% .[[1]] %>% html_table()
Нам понадобится только первые 6 колонок
table <- table[1:6]
Кроме того, добавим время, в которое получены данные. Текущее время возвращает функция Sys.time()
:
table["Timestamp"] <- Sys.time()
Мы знаем как извлечь данные из одной страницы таблицы, и знаем сколько всего страниц она содержит. Остается повторить процедуру извлечения данных для каждой страницы.
Но сначала нужно создать таблицу данных, в которую мы будем складывать результаты:
etf_table <- data.frame()
Добавлять к ней строки, полученные из очередной страницы, будем с помощью функции rbind()
:
etf_table <- rbind(etf_table,table)
Теперь можно записать весь цикл операций
# для каждой страницы таблицы
for (p in 1:pages) {
cur_url <- paste(url,"?&page=",p,sep="")
# скачать html-страницу
content <- html(cur_url)
# извлечь из нее таблицу
table <- content %>% html_nodes("table") %>% .[[1]] %>% html_table()
# только первые 6 колонок
table <- table[1:6]
# добавить колонку со временем скачивания
table["Timestamp"] <- Sys.time()
# и присоединить полученные строки к таблице результатов
etf_table <- rbind(etf_table,table)
}
Другие важные функции
- Извлечь имя элемента HTML можно с помощью функции
html_tag()
, текст — с помощьюhtml_text()
, единичный атрибут —html_attr()
, а список всех атрибутов —html_attrs()
. - Перемещаться по сайту так, как это делает браузер можно с помощью функций
html_session()
,jump_to()
,follow_link()
,back()
иforward()
. Извлекать из веб-страницы формы запросов, изменять значения их полей и отправлять можно с помощьюhtml_form()
,set_values()
иsubmit_form()
соответственно. - Функция
guess_encoding()
определяет кодировку текста. Исправить возможные проблемы с кодировкой можно функциейrepair_encoding()
.
Более подробную информацию смотрите в документации к пакету.
Комментарии
comments powered by Disqus