R: преобразование различных -классов в списки с (вспомогательными) элементами

#r #xpath #web-scraping #rvest

#r #xpath #очистка веб-страниц #rvest

Вопрос:

Я использую rvest для очистки этого веб-сайта. Он содержит данные в такой форме (упрощенной):

 <div class="editor-type">Editors</div>
<div class="editor">
  <div class="editor-name"><h3>Otto Heath</h3></div>
  <span class="editor-affiliation">Royal Holloway University of London</span>
</div>
<div class="editor">
  <div class="editor-name"><h3>Kathrin Smets</h3></div>
  <span class="editor-affiliation">Royal Holloway University of London</span>
</div>

<div class="editor-type">Associate Editor</div>
<div class="editor">
  <div class="editor-name"><h3>Rosa Dassonville</h3></div>
  <span class="editor-affiliation">University of Montreal</span>
</div>
<div class="editor">
  <div class="editor-name"><h3>Matthias Wagner</h3></div>
  <span class="editor-affiliation">University of Wagner</span>
</div>

<div class="editor-type">Editorial Assistant</div>
<div class="editor">
  <div class="editor-name"><h3>Markus Polacko</h3></div>
  <span class="editor-affiliation">Royal Holloway University of London</span>
</div>
  

Я могу легко очистить editor-type и editor-name в соответствующие списки, например, так:

 library("rvest")
webpage <- read_html(url("https://www.journals.elsevier.com/electoral-studies/editorial-board"))
editorial_types <- webpage %>%
  html_nodes(xpath = "//div[@class='editor-type']")
editor_names <- webpage %>%
  html_nodes(xpath = "//div[@class='editor']/descendant::div[@class='editor-name']")
  

Однако я хочу объединить их в один список. Он должен содержать элементы editor-type (редакторы, ассоциированные редакторы и т. Д.) И вложенные элементы с соответствующими editor-name , возможно, такими:

 list_of_editors
[[1]] Editors
[1] Otto Heath
[2] Kathrin Smets

[[2]] Associate Editor
[1] Rosa Dassonville
[2] Markus Wagner

[[3]] Editorial Assistant
[1] Markus Polacko 
  

Как я могу этого добиться?

Ответ №1:

Это было немного сложно, поскольку это был прямой список названий и имен, а не иерархический список. Стратегия состоит в том, чтобы найти все узлы, отсортировать узлы, содержащие заголовок, а затем извлечь имена из узлов между узлами, содержащими заголовки.

 library(rvest)
library(dplyr)

#read the document
webpage <- read_html("https://www.journals.elsevier.com/electoral-studies/editorial-board")

#find parent Node
pubeditors <- webpage %>% html_nodes("div.publication-editors")

#get the children Nodes
editorsnodes <- html_children(pubeditors)

#find nodes with the Position title
titlesnodesnum <- which(html_attr(editorsnodes, "class") =="publication-editor-type")
#create vector of title
titles <- editorsnodes[titlesnodesnum] %>% html_text() %>% trimws()

#include the last node in the list
titlesnodesnum <- c(titlesnodesnum, length(editorsnodes) 1) #identify the last record

#find names between subcategory nodes
answer <- lapply(2:length(titlesnodesnum), function(n){
   start<- titlesnodesnum[n-1] 1  #starting node in subcategory
   end <- titlesnodesnum [n] -1   #ending node in subcategory
   names <- editorsnodes[start:end] %>% html_nodes("div.publication-editor-name") %>% html_text() %>% trimws()
})

#rename the list
names(answer) <- titles
answer

$Editors
[1] "Oliver Heath" "Kaat Smets"  

$`Associate Editor`
[1] "Ruth Dassonneville" "Markus Wagner"     

$`Editorial Assistant`
[1] "Matt Polacko"

$`Editorial Board`
 [1] "Eva Anduiza"            "Paolo Bellucci"         "Amanda Bittner"         "Andre Blais"            "Damien Bol"            
 [6] "Shaun Bowler"           "Barry Burden"           "David Butler"           "Rosie Campbell"         "Miguel Carreras"       
[11] "Harold D Clarke"        "Brian Crisp"            "Ruth Dassonneville"     "Martin Elff"            "Geoffrey Evans"        
[16] "Steve Fisher"           "Rob Ford"               "Aina Gallego"           "Thomas Gschwend"        "Carolien van Ham"      
[21] "Chris Hanretty"         "Elina Kestilä-Kekkonen" "Ann-Kristin Kölln"      "Mona Krewel"            "Matthew Lebo"          
[26] "Michael Lewis-Beck"     "Ian McAllister"         "Caitlin Milazzo"        "Andreas Murr"           "Anja Neundorf"         
[31] "Sergi Pardos"           "Charles Pattie"         "Mikael Persson"         "Stephanie Reher"        "Jason Reifler"         
[36] "Robert Rohrschneider"   "Eline de Rooij"         "Jan Rovny"              "Shane Singh"            "Mary Stegmaier"        
[41] "Laura Stephenson"       "Rune Stubager"          "Nick Vivyan"            "Herbert Weisberg"       "Christopher Wlezien"   
[46] "Georgios Xezonakis"     "Elizabeth Zechmeister"  "Adam Ziegfeld"