В связи с идеей провести лёгкий анализ ответов кандидатов в Координационный совет оппозиции на вопросы “Политического компаса” возникла необходимость пропарсить полученный html-файл и вытащить из него имена кандидатов и их ответы. Я уже раньше сталкивался с подобной задачей и поэтому решил работать с файлом не как с текстом, который обрабатывается регулярными выражениями, а как с html-документом, который обрабатывается специальными для этого случая инструментами.

В R-расширении XML есть функция htmlTreeParse, которая преобразует html-файл в объект, который далее можно “разбирать” на кусочки средствами R.

library(XML)
doc <- htmlTreeParse('data/compass.cvk2012.org.htm', useInternalNodes = T)

Теперь нам надо понять, в каких элементах html-дерева хранятся нужные нам данные. Самый прогрессивный, по некоторым источникам, способ работы с деревом - это XPath, язык запросов к элементам XML-документа. Для того, чтобы быстрее понять структуру интересующего html-документа и построить необходимый XPath-запрос, воспользуемся браузером Firefox с расширениями firebug и firePath. Более подробно об этом можно почитать, например, в публикации "Примеры xpath-запросов к html".

Данные об ответах кандидатов на вопросы компаса хранятся в тэге div класса candidate_compass_data. Для отбора этих тэгов воспользуемся следующей командой:

candidcompass <- getNodeSet(doc, "//div[@class='candidate_compass_data']")

Здесь getNodeSet - это команда из пакета XML, которая в нашем случае отбирает из документа doc узлы, которые соответствуют запросу "//div[@class='candidate_compass_data']". Результатом работы функции является список (list), в каждом из элементов которого хранится очередной тэг, соответствующий XPath-запросу.

Далее вытягиваем значение, хранящееся в тэге:

library(plyr)
compass <- laply(candidcompass, xmlValue)

Здесь laply - функция из пакета plyr, которая на входе получает список (первая буква L в названии функции - сокращение от list) candidcompass, далее применяет к каждому элементу списка функцию xmlValue (о ней чуть позже), а результаты возвращает в виде массива (вторая буква в названии функции A - от array).

Функция xmlValue из пакета XML возвращает значение XML(HTML)-тэга.

Теперь в переменной compass у нас хранятся текстовые строки вида "[2,-1,-1,1,2,1,-1,2,-1,0,2,1,1,-2,-1,2,-2,0,-2,2,-2,0,2,2,2]". Нам нужно преобразовать их в числовой массив. Для начала удалим квадратные скобки по бокам. Для этого воспользуемся функцией str_replace пакета stringr, которая производит в строке замену по регулярному выражению.

library(stringr)
compass <- str_replace(compass, '\\[(.*)\\]', '\\1')

Теперь compass стал напоминать файл со значениями, разделёнными запятыми. Чем и воспользуемся:

compass <- read.table(textConnection(compass), sep=',')

В итоге, переменная compass содержит массив с ответами кандидатов. Сделаем более содержательные заголовки переменных:

varlabs <- c("Парл.респуб", "Защит.пошлины", "Огранич.миграц.", "Госучр.из Мск", "Оппозиц.на выборы", "Беспл.мед. и обр", "ЭксСССР", "Бюдж.в рег", "Проф.армия", "Плоск.налог", "Интегр.с ЕС", "Оружие", "ЕГЭ", "Тит.нация", "Нет ЕР", "Выборн.МСУ", "Деньги Кавказу", "Пересм.приватиз", "Госкорпорац", "Накопит.пенс", "Религ.в УК", "Альтер.парлам", "Присяжн.УК", "Либерал.экон", "Компромисс с власт")
names(candidates)[2:26] <- varlabs 

Аналогичным образом получаются имена кандидатов. Полный исходный код скрипта доступен в моём аккаунте на GitHub.