May 15: rvest
Запись занятия
Запись занятия, которое было 15 мая, можно найти здесь:
Все записи организованы в плейлист
HTML интро
Web-сервер
При попытке открыть какую-нибудь html-страницу (сайт) происходит запрос к web-серверу, на котором размещена эта страница. Если не возникает ошибок, то сервер возвращает сообщение с кодом страницы (html + javascript). Соответственно, когда браузер получает сообщение, он обрабатывает и выполняет код, “отрисовывает страницу” для пользователя. Инструменты скрапинга (rvest, в частности), аналогично запрашивают web-сервер, однако результат не отрисовывают, а хранят в виде объекта в памяти.
Структура html-страницы
Все страницы сайтов — это текст, форматированный с помощью языка разметки html. Это значит, что все элементы страницы — тексты, картинки, гиперссылки, заголовки и проч. имеют свою метку, иначе говоря, тэг. Тэги — ключевые слова, обернутые в угловые скобки <tag_name>
. Тэги всегда представлены в паре: открывающий (<tag_name>
) и закрывающий тэги (</tag_name>
). Между ними как раз и размещается материал страницы — текст, картинка и проч.
Стандартная html-страница имеет вид иерархического дерева тэгов, где корневой тэг — html
. Ниже дан простейший пример кода страницы, в которой есть заголовок и список. Список формируется из общего тэга <ol></ol>
(ordered list) и элементов списка внутри тэга, каждый в собственной паре тэгов <li></li>
.
У тэгов есть атрибуты — как правило, это либо дополнительная информация (адрес гиперссылки, адрес картинки), либо класс, который используется в таблицах стилей, чтобы к разным тегам применять разные визуальные эффекты. Например, чтобы текст во всех тэгах с классом my_class1
был синим, а с классом my_class2
— зеленым. Атрибуты тэгов пишутся сразу после названия открывающего тэга, в угловых скобках: <div class="my_class1"></div>
.
Пример кода страницы:
<!DOCTYPE HTML>
<html>
<body>
<h2>Правда о лосях в html-тегах</h2>
<h3>это пример параграфа</h3>
<p style="color:red;">
, какую знаем о лосях
Здесь мы расскажем вам всю правду</p>
<h3>это пример списка</h3>
<ol>
<li>Лось — животное хитрое</li>
<li>...и коварное!</li>
</ol>
<h3>это пример внутритекстовой гиперссылки</h3>
<a href="http://upravitelev.gitlab.io/mar191s">какой-то левый сайт</a>
<h3>это пример тега с классом</h3>
<p class='my_class'>дальше будет дичь</p>
<h3>это пример таблицы</h3>
<div class="table">
<table>
<tr><th>cell</th><th>colour</th></tr>
<tr><td>1st</td><td>white</td></tr>
<tr><td>2nd</td><td>red</td></tr>
<tr><td>3rd</td><td>black</td></tr>
<tr><td>4th</td><td>green</td></tr>
</table>
</div>
</body>
</html>
Вот так выглядит эта страница в том виде, как её присылает веб-сервер:
<pre><body><h2>Правда о лосях в html-тегах</h2><h3>это пример параграфа</h3><p style="color:red;">Здесь мы расскажем вам всю правду, какую знаем о лосях</p><h3>это пример списка</h3><ol><li>Лось — животное хитрое</li><li>...и коварное!</li></ol><h3>это пример внутритекстовой гиперссылки</h3><a href="http://upravitelev.gitlab.io/mar191s">какой-то левый сайт</a><h3>это пример тега с классом</h3><p class='my_class'>дальше будет дичь</p><h3>это пример таблицы</h3><div class="table"><table><tr><th>cell</th><th>colour</th></tr><tr><td>1st</td><td>white</td></tr><tr><td>2nd</td><td>red</td></tr><tr><td>3rd</td><td>black</td></tr><tr><td>4th</td><td>green</td></tr></table></div></body></pre>
Вот так выглядит эта страница в браузере:
Правда о лосях в html-тегах
это пример параграфа
Здесь мы расскажем вам всю правду, какую знаем о лосях
это пример списка
- Лось — животное хитрое
- ...и коварное!
это пример внутритекстовой гиперссылки
какой-то левый сайтэто пример тега с классом
дальше будет дичь
это пример таблицы
cell colour 1st white 2nd red 3rd black 4th green
Общая последовательность
Последовательность действий при скрапинге данных с помощью rvest
такова:
с помощью функции
read_html()
в рабочее окружение импортируется заданая страница (web-адрес) или XML-документвизуально по структуре или визуально в средствах web-разработчика (в частности, SelectorGadget и нативные инструменты браузеров для web-разрботчиков), а так же функциями
html_children()
,html_attrs()
анализируется структура дерева элементов документа (тэгов и атрибутов)с помощью функций
html_element()
иhtml_elements()
указывается, какой элемент (элементы) структуры необходимо выбратьиз выбранного элемента с помощью функций
html_text()
,html_table
иhtml_attr()
извлекаются значенияпри необходмости во время сбора данных с html-страниц процесс масштабируется на прочие схожие разделы сайта или осуществляется в регулярном формате (краулинг)
Импорт страницы
Установка и подключение пакета стандартные. На *nix/MacOS-системах могут потребоваться дополнительные библиотеки. Для импорта таблицы требуется read_html()
, при импорте может быть необходимо указать кодировку.
## install.packages('rvest')
library(rvest)
## импорт страницы
url <- read_html('./data/elk.html', encoding = 'UTF-8')
Выбор узлов и их значений
Для того, чтобы извлечь значение из какого-то тэга, необходимо указать путь к этому тэгу в дереве тэгов страницы. Выбор тэгов осуществляется с помощью функции html_element()
, где первым аргументом указывают импортированную страницу, а в аргументе xpath
- путь к тэгу на языке XPath.
В тэгах может быть разная информация: текст или таблица, в некоторых случаях важно не содержание тэга, а его атрибут. После того, как выделяется из дерева тэг, необходимо извлечь его содержание. Это делается с помощью функций:
-
html_text()
если в тэге хранится текстовое значение. По сути, используется всегда, когда в тэге не табличка и не картинка.
# извлекаем текстовое значение - заголовок
html_element(url, xpath = '//h2') %>%
html_text()
## [1] "Правда о лосях в html-тегах"
-
html_table()
если в тэге хранится таблица ().
# извлекаем таблицу html_element(url, xpath = '//table') %>% html_table()
## # A tibble: 4 × 2 ## cell colour ## <chr> <chr> ## 1 1st white ## 2 2nd red ## 3 3rd black ## 4 4th green
-
html_attr('attr_name')
- используется для случаев, когда надо извлечь атрибут тэга. Атрибуты тэга можно узнать, применив к выделенному с помощьюhtml_element()
тэгу функциюhtml_attrs()
.
# смотрим атрибуты тэга <a> html_element(url, xpath = '//a') %>% html_attrs()
## href ## "https://ru.wikipedia.org/wiki/%D0%9B%D0%BE%D1%81%D0%B8"
# извлекаем значение атрибута href html_element(url, xpath = '//a') %>% html_attr('href')
## [1] "https://ru.wikipedia.org/wiki/%D0%9B%D0%BE%D1%81%D0%B8"
# извлекаем не атрибут, а значение тэга, # то есть, каким текстом видит эту ссылку пользователь html_element(url, xpath = '//a') %>% html_text()
## [1] "ссылка на вики"
Навигация по дереву тегов
Ключевые элементы языка XPath:
%tag_name%
— название тэга%tag_name%
/
— Иcпользуется для указания прямого пути к элементу от корневого/родительского тега. Если весь xpath-путь начинается с/
, то это абсолютный путь от корня дерева. Вот так можно выбрать тэг (ноду, узел) заголовка страницы.
# длинный путь, от корня через все поколения родителей к тэгу h2 html_element(url, xpath = '/html/body/h2') %>% html_text()
## [1] "Правда о лосях в html-тегах"
-
//
— Выбирает теги независимо от места их расположения, при этом может использоваться как в начале пути, так и в середине:
# короткий путь, "пропусти все до первого тэга h2" html_element(url, xpath = '//h2') %>% html_text()
## [1] "Правда о лосях в html-тегах"
-
@
— выбор атрибута узла. Если необходимо использовать атрибут тэга в пути, то атрибут указывается как@attr_name
. Если указать путь к атрибуту тэга с использованием@
, то можно не использовать функциюhtml_attr()
, а обойтись общейhtml_text()
:
html_element(url, xpath = '//a/@href') %>% html_text()
## [1] "https://ru.wikipedia.org/wiki/%D0%9B%D0%BE%D1%81%D0%B8"
-
[x]
— фильтрация тэга с помощью номера места в списке тэгов-сиблингов (на одном уровне в иерархии) или по наличию какого-либо атрибута. В целом, очень похоже на фильтрацию таблиц по номеру строки или логическому условию.
### выбираем по номеру тэга в списке # первый заголовок h3 html_element(url, xpath = '//h3[1]') %>% html_text()
## [1] "это пример параграфа"
# третий заголовок h3 html_element(url, xpath = '//h3[3]') %>% html_text()
## [1] "это пример тега с классом"
### выбираем по содержанию определенного атрибута # выбираем значение тэга <p>, у которого есть атрибут класса class="my_class" html_element(url, xpath = '//p[@class="my_class"]') %>% html_text()
## [1] "дальше будет дичь"
-
*
— знак подстановки, “на этом месте может быть что угодно” — используется, когда надо пропустить какой-то длинный кусок дерева тэгов или точно неизвестно, какой тэг или атрибут используется:
# не знаем тэг, знаем атрибут класс, вместо тэга пишем * html_element(url, xpath = '//*[@class="my_class"]') %>% html_text()
## [1] "дальше будет дичь"
# знаем тэг, но не знаем, какой атрибут со значением "my_class" html_element(url, xpath = '//p[@*="my_class"]') %>% html_text()
## [1] "дальше будет дичь"
Дополнительные материалы
Один из лучших справочников и туториалов по HTML. Есть примеры написания и использования тэгов. Тэги описаны по функционалу, есть список тэгов
Справочник и туториалы, как и w3s, но с некоторыми изменениями/дополнениями и на русском языке.
Короткое введение в XPath. Сайт выглядит страшненько, да и примеры все на xml (хотя разница с html минимальна). Скорее для тех, кто хочет глубже разобраться в особенностях XPath, так как содержит много излишне детальной информации.
Домашнее задание
Установите и подключите пакет rvest. Импортируйте страницу https://cran.r-project.org/web/packages/rvest/index.html. Страницу можно импортировать, можно сохранить на диск (горячие клавиши для сохранения - ctrl + s). Для того, чтобы посмотреть дерево тэгов, можно страницу открыть в инструментах разработчика (клавиша F12 в большинстве браузеров и там раскрывать узлы тегов, либо правый клик мышкой и что-нибудь в меню типа “инструменты разработчика / inspect object”). Также можно сохранить страницу и открыть просто в каком-нибудь блокноте.
Используя полный путь XPath, выведите на печать заголовок страницы (тэг h2)
Используя сокращенный XPath-путь, выведите на печать заголовок страницы (rvest:…), тег h2 единственный на всей странице.
Выведите на печать h4-заголовок второго блока (Reverse dependencies:).
Выведите на печать блок информации о пакете (от Version: 0.3.5 до Downlods:). Можно сократить вывод до трех строк. Это первый тэг table на странице.
-