В связи с идеей провести лёгкий анализ ответов кандидатов в Координационный совет оппозиции на вопросы “Политического компаса” возникла необходимость пропарсить полученный html-файл и вытащить из него имена кандидатов и их ответы. Я уже раньше сталкивался с подобной задачей и поэтому решил работать с файлом не как с текстом, который обрабатывается регулярными выражениями, а как с html-документом, который обрабатывается специальными для этого случая инструментами.
В R-расширении XML есть функция htmlTreeParse
, которая преобразует html-файл в объект, который далее можно “разбирать” на кусочки средствами R.
1 2 | 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
. Для отбора этих тэгов воспользуемся следующей командой:
3 | candidcompass <- getNodeSet(doc, "//div[@class='candidate_compass_data']") |
Здесь getNodeSet
– это команда из пакета XML, которая в нашем случае отбирает из документа doc
узлы, которые соответствуют запросу “//div[@class='candidate_compass_data']
“. Результатом работы функции является список (list), в каждом из элементов которого хранится очередной тэг, соответствующий XPath-запросу.
Далее вытягиваем значение, хранящееся в тэге:
4 5 | 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, которая производит в строке замену по регулярному выражению.
6 7 | library(stringr) compass <- str_replace(compass, '\\[(.*)\\]', '\\1') |
Теперь compass стал напоминать файл со значениями, разделёнными запятыми. Чем и воспользуемся:
8 | compass <- read.table(textConnection(compass), sep=',') |
В итоге, переменная compass содержит массив с ответами кандидатов. Сделаем более содержательные заголовки переменных:
9 10 | varlabs <- c("Парл.респуб", "Защит.пошлины", "Огранич.миграц.", "Госучр.из Мск", "Оппозиц.на выборы", "Беспл.мед. и обр", "ЭксСССР", "Бюдж.в рег", "Проф.армия", "Плоск.налог", "Интегр.с ЕС", "Оружие", "ЕГЭ", "Тит.нация", "Нет ЕР", "Выборн.МСУ", "Деньги Кавказу", "Пересм.приватиз", "Госкорпорац", "Накопит.пенс", "Религ.в УК", "Альтер.парлам", "Присяжн.УК", "Либерал.экон", "Компромисс с власт") names(candidates)[2:26] <- varlabs |
Аналогичным образом получаются имена кандидатов. Полный исходный код скрипта доступен в моём аккаунте на GitHub.
[…] нужное слово из получаемых в ответ страниц с помощью XPath. Но здесь нужно подумать, насколько такие действия […]